def __init__(self, user, game): self.lock = Lock() self.game = game self.user = user try: path = config['gameprofile_db'] except KeyError: LOG.error('gameprofile_db path config variable not set') return # Create gameprofile folder and user folder on the game path path = join_path(path, game.slug) if not create_dir(path): error_msg = 'User GameProfile path \"%s\" could not be created.' % path LOG.error(error_msg) raise GameProfileError(error_msg) self.path = get_absolute_path(path) self.defaults = {} default_yaml_path = unicode( get_absolute_path(join_path(game.path, 'defaultgameprofiles.yaml'))) if path_exists(default_yaml_path): with open(default_yaml_path, 'rt') as f: try: file_defaults = yaml.load(f) self.defaults = dict((v['user'], v['value']) for v in file_defaults['profiles']) except (yaml.YAMLError, KeyError, TypeError) as e: LOG.error('Failed loading default game profiles: %s' % str(e))
def __init__(self, user, game): self.lock = Lock() self.game = game self.user = user try: path = config['gameprofile_db'] except KeyError: LOG.error('gameprofile_db path config variable not set') return # Create gameprofile folder and user folder on the game path path = join_path(path, game.slug) if not create_dir(path): error_msg = 'User GameProfile path \"%s\" could not be created.' % path LOG.error(error_msg) raise GameProfileError(error_msg) self.path = get_absolute_path(path) self.defaults = {} default_yaml_path = unicode(get_absolute_path(join_path(game.path, 'defaultgameprofiles.yaml'))) if path_exists(default_yaml_path): with open(default_yaml_path, 'r') as f: try: file_defaults = yaml.load(f) self.defaults = dict((v['user'], v['value']) for v in file_defaults['profiles']) except (yaml.YAMLError, KeyError, TypeError) as e: LOG.error('Failed loading default game profiles: %s', str(e))
def __init__(self, game): self.lock = Lock() self.game = game self.userbadges_path = None self.abs_game_path = get_absolute_path(game.path) try: self.lock.acquire() yaml_path = norm_path( get_absolute_path(join_path(game.path, 'badges.yaml'))) if not access(yaml_path, R_OK): raise BadgesUnsupportedException() f = open(unicode(yaml_path), 'r') try: self.badges = yaml.load(f) finally: f.close() except IOError as e: LOG.error('Failed loading badges: %s', str(e)) raise ApiException('Failed loading badges.yaml file %s' % str(e)) finally: self.lock.release()
def is_correct(self): try: abs_path = get_absolute_path(self.__str__()) return access(abs_path, W_OK) except (AttributeError, TypeError): # TODO: These are thrown by get_absolute_path when called on None and probably shouldn't be needed return False
def __init__(self, game, hub_pool, hub_project, hub_version, hub_versiontitle, hub_cookie, cache_dir): self.path = abspath(get_absolute_path(game.path)) self.plugin_main = game.plugin_main self.canvas_main = game.canvas_main self.flash_main = game.flash_main self.mapping_table = game.mapping_table self.files = game.deploy_files.items self.engine_version = game.engine_version self.is_multiplayer = game.is_multiplayer self.aspect_ratio = game.aspect_ratio self.cache_dir = cache_dir self.game_cache_dir = join(abspath(cache_dir), game.slug) self.stopped = False self.hub_project = hub_project self.hub_version = hub_version self.hub_versiontitle = hub_versiontitle self.hub_session = None self.hub_pool = hub_pool self.hub_cookie = hub_cookie self.hub_timeout = 200 self.total_files = 0 self.num_files = 0 self.num_bytes = 0 self.uploaded_files = 0 self.uploaded_bytes = 0 self.done = False self.error = None try: makedirs(self.get_gzip_dir()) except OSError as e: if e.errno != EEXIST: LOG.error(str(e))
def get_versions(self): # if the game path is defined, find play-html files. versions = [ ] if self.path.is_correct(): abs_path = get_absolute_path(self.path) slug = self.slug + '/' executable_extensions = self._executable_extensions flash_dict = None for file_name in listdir(abs_path): if file_name.endswith(executable_extensions): version = { 'title': os.path.basename(file_name), 'url': slug + file_name } if file_name.endswith('.swf'): if flash_dict is None: flash_dict = {} flash_config_path = join_path(abs_path, 'flash.yaml') if access(flash_config_path, R_OK): f = open(unicode(flash_config_path), 'r') try: flash_dict = yaml.load(f) finally: f.close() version['flash'] = flash_dict versions.append(version) return versions
def get_versions(self): # if the game path is defined, find play-html files. versions = [] if self.path.is_correct(): abs_path = get_absolute_path(self.path) slug = self.slug + '/' executable_extensions = self._executable_extensions flash_dict = None for file_name in listdir(abs_path): if file_name.endswith(executable_extensions): version = { 'title': os.path.basename(file_name), 'url': slug + file_name } if file_name.endswith('.swf'): if flash_dict is None: flash_dict = {} flash_config_path = join_path( abs_path, 'flash.yaml') if access(flash_config_path, R_OK): f = open(unicode(flash_config_path), 'r') try: flash_dict = yaml.load(f) finally: f.close() version['flash'] = flash_dict versions.append(version) return versions
def __init__(self): self.lock = Lock() self.lock.acquire() self._sessions = {} path = config.get('gamesessions.yaml', 'gamesessions.yaml') self.path = get_absolute_path(path) self.load_sessions() self.lock.release()
def is_correct(self): try: path = get_absolute_path(self.game.path) path = join_path(path, self.image_path) except (AttributeError, TypeError): # TODO: These are thrown by get_absolute_path when called on None and probably shouldn't be needed return None else: return access(path, R_OK)
def __call__(self, environ, start_response): request_path = environ.get('PATH_INFO', '') # check if the request is for static files at all path_parts = request_path.strip('/').split('/', 2) if len(path_parts) == 3 and path_parts[0] in ['play', 'game-meta']: slug = path_parts[1] game = self.game_list.get_by_slug(slug) if game and game.path.is_set(): asset_path = path_parts[2] file_asset_path = normpath(join(get_absolute_path(game.path), asset_path)) def build_file_iter(f, block_size): return StaticFileIter(file_asset_path, normpath(join(slug, asset_path)), f, block_size) def remove_ranges_start_response(status, headers, exc_info=None): if status == '200 OK': headers = [t for t in headers if t[0] != 'Accept-Ranges' and t[0] != 'Content-Range'] return start_response(status, headers, exc_info) # check if the request is already cached app = self.cached_apps.get(request_path) if app: environ['wsgi.file_wrapper'] = build_file_iter try: return app(environ, remove_ranges_start_response) except OSError as e: LOG.error(e) elif access(file_asset_path, R_OK): content_type, _ = guess_type(file_asset_path) if content_type in self.utf8_mimetypes: content_type += '; charset=utf-8' app = FileApp(file_asset_path, content_type=content_type) if asset_path.startswith('staticmax'): app.cache_control(max_age=self.staticmax_max_age) else: app.cache_control(max_age=0) self.cached_apps[request_path] = app environ['wsgi.file_wrapper'] = build_file_iter return app(environ, remove_ranges_start_response) start_response( '404 Not Found', [('Content-Type', 'text/html; charset=UTF-8'), ('Content-Length', '0')] ) return [''] return self.app(environ, start_response)
def path_in_use(self, query_path): """ Return True if the given path is already being used in the GameList. Otherwise False. """ # turn path absolute query_path = get_absolute_path(query_path) # check all games... for game in self._slugs.itervalues(): # ... that have a path ... test_path = game.path if test_path is not None: # .. if they are using the given path test_path = get_absolute_path(test_path) if query_path == test_path: return True return False
def _read_users(self): do_save = False try: path = config['user.yaml'] except KeyError: LOG.error('Config variable not set for path to "user.yaml"') if exists(get_absolute_path(path)): try: f = open(path, 'rt') try: user_info = yaml.load(f) if 'users' in user_info: self.active = user_info.get('active', None) for u in user_info['users']: user = self._add_user(u) if self.active is None: self.active = user.username else: user = self._add_user(user_info) self.active = user.username do_save = True finally: f.close() except IOError as e: LOG.error('Failed loading users: %s' % str(e)) else: self._add_user(User.default_username) self.active = User.default_username do_save = True try: path = path_join(CONFIG_PATH, 'defaultusers.yaml') f = open(path, 'rt') try: user_info = yaml.load(f) for u in user_info['users']: # dont overwrite changed user settings if u['username'].lower() not in self.users: user = User(u, default=True) username = user.username.lower() self.users[username] = user do_save = True finally: f.close() except IOError as e: LOG.error('Failed loading default users: %s' % str(e)) except KeyError: LOG.error('Username missing for default user "defaultusers.yaml"') except ValueError: LOG.error('Username invalid for default user "defaultusers.yaml"') if do_save: self._write_users()
def post(self, slug, filename): """ Saves given contents to file to game folder. """ game = get_game_by_slug(slug) if not game: self.set_status(404) return self.finish({'ok': False, 'msg': 'Game does not exist: %s' % slug}) if not filename: self.set_status(400) return self.finish({'ok': False, 'msg': 'Missing filename'}) if '..' in filename: self.set_status(403) return self.finish({'ok': False, 'msg': 'Cannot write outside game folder'}) content = self.get_argument('content') self.request.body = None self.request.arguments = None file_path = path_join(get_absolute_path(game.get_path()), normpath(filename)) file_dir = dirname(file_path) if not create_dir(file_dir): LOG.error('Failed to create directory at "%s"', file_dir) self.set_status(500) return self.finish({'ok': False, 'msg': 'Failed to create directory'}) if content: try: content = content.encode('utf-8') except UnicodeEncodeError as e: LOG.error('Failed to encode file contents: %s', str(e)) self.set_status(500) return self.finish({'ok': False, 'msg': 'Failed to encode file contents'}) LOG.info('Writing file at "%s" (%d bytes)', file_path, len(content)) else: LOG.info('Writing empty file at "%s"', file_path) try: file_obj = open(file_path, 'wb') try: file_obj.write(content) finally: file_obj.close() except IOError as e: LOG.error('Failed to write file at "%s": %s', file_path, str(e)) self.set_status(500) return self.finish({'ok': False, 'msg': 'Failed to write file'}) return self.finish({'ok': True})
def _set_userbadges_path(self): if not self.userbadges_path: try: path = config['userbadges_db'] except KeyError: LOG.error('badges_db path config variable not set') return if not create_dir(path): LOG.error('Game badges path \"%s\" could not be created.' % path) self.userbadges_path = norm_path(join_path(get_absolute_path(path), self.game.slug) + '.yaml')
def _set_userbadges_path(self): if not self.userbadges_path: try: path = config['userbadges_db'] except KeyError: LOG.error('badges_db path config variable not set') return if not create_dir(path): LOG.error('Game badges path \"%s\" could not be created.', path) self.userbadges_path = norm_path(join_path(get_absolute_path(path), self.game.slug) + '.yaml')
def __init__(self, game): self.game = game self.abs_game_path = get_absolute_path(game.path) try: yaml_path = norm_path(get_absolute_path(join_path(game.path, 'gamenotifications.yaml'))) if not access(yaml_path, R_OK): raise GameNotificationsUnsupportedException() with open(unicode(yaml_path), 'r') as f: notifications = {} for n_key in yaml.load(f): notifications[n_key['key']] = n_key self._notifications = notifications except (IOError, KeyError) as e: LOG.error('Failed loading gamenotifications: %s', str(e)) raise ApiException('Failed loading gamenotifications.yaml file %s' % str(e))
def get_path(self): if self.path is not None: return self.path try: path = config['datashare_db'] except KeyError: LOG.error('datashare_db path config variable not set') raise path = get_absolute_path(join_path(path, self.game.slug, self.datashare_id + '.yaml')) self.path = path return path
def create_path(self): try: path = config['datashare_db'] except KeyError: LOG.error('datashare_db path config variable not set') raise # Create datashare folder path = join_path(path, self.game.slug) if not create_dir(path): LOG.error('DataShare path \"%s\" could not be created.' % path) raise IOError('DataShare path \"%s\" could not be created.' % path) return get_absolute_path(path)
def _read_users(self): do_save = False try: path = config['user.yaml'] except KeyError: LOG.error('Config variable not set for path to "user.yaml"') if exists(get_absolute_path(path)): try: f = open(path, 'r') try: user_info = yaml.load(f) if user_info is not None: if 'users' in user_info: for u in user_info['users']: user = self._add_user(u) else: user = self._add_user(user_info) do_save = True finally: f.close() except IOError as e: LOG.error('Failed loading users: %s', str(e)) else: self._add_user(User.default_username) do_save = True try: path = path_join(CONFIG_PATH, 'defaultusers.yaml') f = open(path, 'r') try: user_info = yaml.load(f) for u in user_info['users']: # dont overwrite changed user settings if u['username'].lower() not in self.users: user = User(u, default=True) username = user.username.lower() self.users[username] = user do_save = True finally: f.close() except IOError as e: LOG.error('Failed loading default users: %s', str(e)) except KeyError: LOG.error('Username missing for default user "defaultusers.yaml"') except ValueError: LOG.error('Username invalid for default user "defaultusers.yaml"') if do_save: self._write_users()
def __init__(self, game): self.leaderboards = {} self.ordered_leaderboards = [] self.leaderboard_path = None self.issues = [] yaml_path = unicode( get_absolute_path(join_path(game.path, 'leaderboards.yaml'))) total_yaml_errors = 0 if path_exists(yaml_path): try: f = open(yaml_path, 'rt') try: file_meta = yaml.load(f) for (i, m) in enumerate(file_meta): key = m['key'] leaderboard = Leaderboard(game, key, m, i) num_errors = len(leaderboard.errors) if num_errors > 0: total_yaml_errors += num_errors self.issues.append((key, { 'errors': leaderboard.errors, 'warnings': leaderboard.warnings })) elif len(leaderboard.warnings) > 0: self.issues.append((key, { 'errors': leaderboard.errors, 'warnings': leaderboard.warnings })) self.leaderboards[key] = leaderboard self.ordered_leaderboards.append(leaderboard) finally: f.close() except (IOError, yaml.YAMLError) as e: LOG.error('Failed loading leaderboards: %s' % str(e)) raise LeaderboardError( 'Failed loading leaderboards.yaml file: %s' % str(e)) else: raise LeaderboardsUnsupported() if total_yaml_errors > 0: raise ValidationException(self.issues)
def __init__(self, game): self.lock = Lock() self.game = game self.userbadges_path = None self.abs_game_path = get_absolute_path(game.path) try: self.lock.acquire() yaml_path = norm_path(get_absolute_path(join_path(game.path, 'badges.yaml'))) if not access(yaml_path, R_OK): raise BadgesUnsupportedException() f = open(unicode(yaml_path), 'r') try: self.badges = yaml.load(f) finally: f.close() except IOError as e: LOG.error('Failed loading badges: %s', str(e)) raise ApiException('Failed loading badges.yaml file %s' % str(e)) finally: self.lock.release()
def is_json(self): if self.request_name: abs_static_path = self.abs_file_path or get_absolute_path(self.request_name) try: json_handle = open(abs_static_path) json.load(json_handle) except IOError as e: LOG.error(str(e)) return False except ValueError as e: #Expected if file is not valid json return False else: return False return True
def __init__(self, game): self.game = game self.abs_game_path = get_absolute_path(game.path) try: yaml_path = norm_path( get_absolute_path( join_path(game.path, 'gamenotifications.yaml'))) if not access(yaml_path, R_OK): raise GameNotificationsUnsupportedException() with open(unicode(yaml_path), 'r') as f: notifications = {} for n_key in yaml.load(f): notifications[n_key['key']] = n_key self._notifications = notifications except (IOError, KeyError) as e: LOG.error('Failed loading gamenotifications: %s', str(e)) raise ApiException( 'Failed loading gamenotifications.yaml file %s' % str(e))
def _get_task_path(slug, recipient, notification_type, filename=None): try: path = config['notifications_db'] except KeyError: raise GameNotificationsUnsupportedException('notifications_db path config variable not set') path = join_path(path, slug, recipient, notification_type) if not create_dir(path): raise GameNotificationPathError('User GameNotification path \"%s\" could not be created.' % path) if filename: return get_absolute_path(join_path(path, filename)) else: return path
def get_asset(asset, slug, userdata=None): game = get_game_by_slug(slug) if userdata: # asset = user / key (username, key) = asset.split('/', 1) user = get_user(username) userdata = UserData(user=user, game=game) json_asset = json.loads(userdata.get(key)) filename = key + '.txt' else: filename = get_absolute_path(os.path.join(game.path, asset)) with open(filename, 'r') as handle: json_asset = json.load(handle) return (json_asset, filename)
def read_manifest(game_path, manifest_name): """ Try reading manifest game data in dictionary form from game_path. """ try: game_path = get_absolute_path(game_path) game_path = join_path(game_path, manifest_name) f = open(unicode(game_path), 'r') try: data = yaml.load(f) finally: f.close() except IOError as e: LOG.error('Failed loading manifest: %s', str(e)) raise GameError else: return data
def _get_task_path(slug, recipient, notification_type, filename=None): try: path = config['notifications_db'] except KeyError: raise GameNotificationsUnsupportedException( 'notifications_db path config variable not set') path = join_path(path, slug, recipient, notification_type) if not create_dir(path): raise GameNotificationPathError( 'User GameNotification path \"%s\" could not be created.' % path) if filename: return get_absolute_path(join_path(path, filename)) else: return path
def get_asset_list(self, request_path, path=''): if self.path.is_correct(): game_path = self.path abs_game_path = get_absolute_path(game_path) # Load mapping table j = load_json_asset(os.path.join(game_path, self.mapping_table)) if j: # pylint: disable=E1103 mapping_table = j.get('urnmapping') or j.get( 'urnremapping', {}) # pylint: enable=E1103 self.has_mapping_table = True files = [] directories = {} len_path = len(path) if not path.endswith('/') and len_path > 0: len_path += 1 for k, v in mapping_table.iteritems(): if k.startswith(path): parts = k[len_path:].split('/') if len(parts) == 1: abs_file_path = os.path.join( abs_game_path, request_path, v) files.append( _File(parts[0], v, '%s/%s' % (request_path, v), abs_file_path)) else: if parts[0] not in directories: directories[parts[0]] = _File(parts[0]) result = directories.values() + files if len(result) == 0: raise GamePathNotFoundError( 'Asset path does not exist: %s' % path) return result else: self.has_mapping_table = False # !!! What do we expect if the user asks for Assets and there is no mapping table? return self.get_static_files(game_path, request_path, path) else: raise GamePathError('Game path not found: %s' % self.path)
def iterate_dir(cls, path, files, directories): abs_static_path = get_absolute_path(path) for file_name in listdir(abs_static_path): if os.path.isdir(os.path.join(abs_static_path, file_name)) != True: #file_name is not directory parts = path.split('/') if len(parts) > 2: directory = parts[-1] else: directory = '' files.append(_File(file_name, file_name, directory, os.path.join(abs_static_path, file_name))) else: if file_name not in directories: directories[file_name] = _File(file_name) return directories.values() + files
def iterate_dir(cls, path, files, directories): abs_static_path = get_absolute_path(path) for file_name in listdir(abs_static_path): if os.path.isdir(os.path.join(abs_static_path, file_name)) != True: #file_name is not directory parts = path.split('/') if len(parts) > 2: directory = parts[-1] else: directory = '' files.append(_File(file_name, file_name, directory, os.path.join(abs_static_path, file_name))) else: if (file_name not in directories): directories[file_name] = _File(file_name) return directories.values() + files
def __init__(self, game): self.leaderboards = {} self.ordered_leaderboards = [] self.leaderboard_path = None self.issues = [] yaml_path = unicode(get_absolute_path(join_path(game.path, 'leaderboards.yaml'))) total_yaml_errors = 0 if path_exists(yaml_path): try: f = open(yaml_path, 'r') try: file_meta = yaml.load(f) for (i, m) in enumerate(file_meta): key = m['key'] leaderboard = Leaderboard(game, key, m, i) num_errors = len(leaderboard.errors) if num_errors > 0: total_yaml_errors += num_errors self.issues.append((key, { 'errors': leaderboard.errors, 'warnings': leaderboard.warnings })) elif len(leaderboard.warnings) > 0: self.issues.append((key, { 'errors': leaderboard.errors, 'warnings': leaderboard.warnings })) self.leaderboards[key] = leaderboard self.ordered_leaderboards.append(leaderboard) finally: f.close() except (IOError, yaml.YAMLError) as e: LOG.error('Failed loading leaderboards: %s', str(e)) raise LeaderboardError('Failed loading leaderboards.yaml file: %s' % str(e)) else: raise LeaderboardsUnsupported() if total_yaml_errors > 0: raise ValidationException(self.issues)
def __init__(self, user, game, game_store_items): self.user = user self.game = game self.game_store_items = game_store_items self.user_items = {} try: path = config['storeitems_db'] except KeyError: LOG.error('storeitems_db path config variable not set') return # Create store items folder and user folder on the game path path = join_path(path, self.game.slug) if not create_dir(path): raise StoreError('User store items path \"%s\" could not be created.' % path) self.path = get_absolute_path(path) self.lock = Lock() self._read()
def __init__(self, session=None, game=None, user=None): if session is None: self.game = game self.user = user else: self.game = session.game self.user = session.user try: path = config['userdata_db'] except KeyError: LOG.error('userdata_db path config variable not set') return # Create userdata folder and user folder on the game path path = join_path(path, self.game.slug, self.user.username) if not create_dir(path): raise UserDataPathError('User UserData path \"%s\" could not be created.' % path) self.path = get_absolute_path(path)
def write_manifest(data, manifest_name): """ Write the game metadata to a YAML manifest file """ path = data.get('path') if not path: raise GamePathError('No path found in game data.\nData=' +\ '\n'.join(['%s:\t%s' % (k, v) for k, v in data.iteritems()])) path = get_absolute_path(path) # write the YAML data try: f = open(join_path(path, manifest_name), 'w') try: yaml.dump(data, f, default_flow_style=False) finally: f.close() except IOError as e: LOG.error('Failed writing manifest: %s', str(e)) raise GamePathError('Failed writing manifest file.')
def __init__(self, user, game, game_store_items): self.user = user self.game = game self.game_store_items = game_store_items self.user_items = {} try: path = config['storeitems_db'] except KeyError: LOG.error('storeitems_db path config variable not set') return # Create store items folder and user folder on the game path path = join_path(path, self.game.slug) if not create_dir(path): raise StoreError( 'User store items path \"%s\" could not be created.' % path) self.path = get_absolute_path(path) self.lock = Lock() self._read()
def get_asset_list(self, request_path, path=''): if self.path.is_correct(): game_path = self.path abs_game_path = get_absolute_path(game_path) # Load mapping table j = load_json_asset(os.path.join(game_path, self.mapping_table)) if j: # pylint: disable=E1103 mapping_table = j.get('urnmapping') or j.get('urnremapping', {}) # pylint: enable=E1103 self.has_mapping_table = True files = [ ] directories = { } len_path = len(path) if not path.endswith('/') and len_path > 0: len_path += 1 for k, v in mapping_table.iteritems(): if k.startswith(path): parts = k[len_path:].split('/') if len(parts) == 1: abs_file_path = os.path.join(abs_game_path, request_path, v) files.append(_File(parts[0], v, '%s/%s' % (request_path, v), abs_file_path)) else: if parts[0] not in directories: directories[parts[0]] = _File(parts[0]) result = directories.values() + files if len(result) == 0: raise GamePathNotFoundError('Asset path does not exist: %s' % path) return result else: self.has_mapping_table = False # !!! What do we expect if the user asks for Assets and there is no mapping table? return self.get_static_files(game_path, request_path, path) else: raise GamePathError('Game path not found: %s' % self.path)
def directory_options(cls): directory = request.params.get('dir', None) if not directory: response.status_int = 400 return {'ok': False, 'msg': 'Directory not specified'} directory = directory.strip() # Test for characters not legal in Windows paths if not set(directory).isdisjoint(set('*?"<>|\0')): response.status_int = 400 return {'ok': False, 'msg': 'Bad directory'} try: absDir = get_absolute_path(directory) except TypeError: response.status_int = 400 return {'ok': False, 'msg': 'Bad directory'} options = { 'absDir': norm_path(absDir), 'dir': directory } if not os.access(absDir, os.F_OK): options['create'] = True else: if not os.access(absDir, os.W_OK): options['inaccessible'] = True elif os.access(path_join(absDir, 'manifest.yaml'), os.F_OK): if GameList.get_instance().path_in_use(absDir): options['inUse'] = True else: options['overwrite'] = True else: options['usable'] = True return {'ok': True, 'data': options}
def check_completeness(self): errors = [] tmp = [] if not self.deploy_enable: tmp.append('"deploy" is disabled.') if self.is_temporary: tmp.append('Game is temporary.') path = self.path if not path or not path.is_set(): tmp.append('No path set.') path_correct = False else: path_correct = path.is_correct() if not path_correct: tmp.append('Incorrect path set.') if tmp: errors.append(('settings', {'errors': tmp})) tmp = [] plugin_main = self.plugin_main canvas_main = self.canvas_main flash_main = self.flash_main main_correct = True if (not plugin_main or not plugin_main.is_set()) and \ (not canvas_main or not canvas_main.is_set()) and \ (not flash_main or not flash_main.is_set()): tmp.append('No "main"-file set. Specify at least one of plugin or canvas main.') main_correct = False abs_path = get_absolute_path(path) if plugin_main: plugin_main = join_path(abs_path, plugin_main) if not access(plugin_main, R_OK): tmp.append('Can\'t access plugin "main"-file.') if canvas_main: canvas_main = join_path(abs_path, canvas_main) if not access(canvas_main, R_OK): tmp.append('Can\'t access canvas "main"-file.') if flash_main: if not flash_main.startswith('https://'): flash_main = join_path(abs_path, flash_main) if not access(flash_main, R_OK): tmp.append('Can\'t access flash "main"-file.') mapping_table = self.mapping_table if (not mapping_table or not mapping_table.is_set()) and not flash_main: tmp.append('No mapping-table set.') elif path_correct and main_correct: mapping_table = join_path(abs_path, mapping_table) if not access(mapping_table, R_OK): tmp.append('Can\'t access mapping-table.') deploy_files = self.deploy_files if not deploy_files or not deploy_files.is_set(): tmp.append('No deploy files set.') engine_version = self.engine_version if not engine_version or not engine_version.is_set(): tmp.append('No engine version set.') elif not engine_version.is_correct(): tmp.append('Invalid engine version set.') aspect_ratio = self.aspect_ratio if not aspect_ratio or not aspect_ratio.is_set(): tmp.append('No aspect ratio set.') elif not aspect_ratio.is_correct(): tmp.append('Invalid aspect ratio set.') if tmp: errors.append(('files', {'errors': tmp})) return (len(errors) == 0, {'Project-Settings': errors})
def post(self, slug, filename): """ Saves given contents to file to game folder. """ game = get_game_by_slug(slug) if not game: self.set_status(404) return self.finish({ 'ok': False, 'msg': 'Game does not exist: %s' % slug }) if not filename: self.set_status(400) return self.finish({'ok': False, 'msg': 'Missing filename'}) if '..' in filename: self.set_status(403) return self.finish({ 'ok': False, 'msg': 'Cannot write outside game folder' }) content_type = self.request.headers.get('Content-Type', '') if content_type and 'application/x-www-form-urlencoded' in content_type: content = self.get_argument('content') binary = False else: content = self.request.body binary = True self.request.body = None self.request.arguments = None file_path = path_join(get_absolute_path(game.get_path()), normpath(filename)) file_dir = dirname(file_path) if not create_dir(file_dir): LOG.error('Failed to create directory at "%s"', file_dir) self.set_status(500) return self.finish({ 'ok': False, 'msg': 'Failed to create directory' }) if content: if not binary: try: content = content.encode('utf-8') except UnicodeEncodeError as e: LOG.error('Failed to encode file contents: %s', str(e)) self.set_status(500) return self.finish({ 'ok': False, 'msg': 'Failed to encode file contents' }) LOG.info('Writing file at "%s" (%d bytes)', file_path, len(content)) else: LOG.info('Writing empty file at "%s"', file_path) try: file_obj = open(file_path, 'wb') try: file_obj.write(content) finally: file_obj.close() except IOError as e: LOG.error('Failed to write file at "%s": %s', file_path, str(e)) self.set_status(500) return self.finish({'ok': False, 'msg': 'Failed to write file'}) return self.finish({'ok': True})
def __init__(self, game, key, meta_data, index): self.user_scores = {} self.scores = [] self.aggregate = False self.aggregate_score = 0 self.lock = Lock() self.errors = [] self.warnings = [] self.path = None def error(msg): self.errors.append(msg) def warning(msg): self.warnings.append(msg) if not self.validate_key.match(key): error('invalid key format "%s"' % key) self.key = key self.index = index if 'title' not in meta_data or meta_data['title'] is None: error('title property missing for key "%s"' % key) self.title = '' else: self.title = meta_data['title'] if 'aggregate' in meta_data: if isinstance(meta_data['aggregate'], bool): self.aggregate = meta_data['aggregate'] else: warning('aggregate property must be a boolean for key "%s"' % key) self.aggregate = False else: self.aggregate = False try: sort_by = int(meta_data['sortBy']) if sort_by != -1 and sort_by != 1: error('sortBy must either -1 or 1 for key "%s"' % key) except KeyError: warning('sortBy property missing for key "%s"' % key) sort_by = 1 except ValueError: error('sortBy must either -1 or 1 for key "%s"' % key) sort_by = 1 self.sort_by = sort_by if 'icon' in meta_data: warning('"icon" yaml property has been deprecated please use ' '"icon256", "icon48" or "icon32" for leaderboard key "%s"' % key) try: icon_path = meta_data['icon256'] if path_exists(get_absolute_path(join_path(game.path, icon_path))): if splitext(icon_path)[1] != '.png': warning('icon256 must be in PNG format for key "%s"' % key) else: error('icon256 file does not exist for key "%s"' % key) except KeyError: warning('no icon256 (using default) for key "%s"' % key) self.game = game self.default_scores = [] default_scores = meta_data.get('default-scores', []) for (i, s) in enumerate(default_scores): if not isinstance(s, dict): warning('Default score must an array of objects for key "%s"' % key) continue user = s.get('user', None) if user is None: email = s.get('email', None) if email is None: warning('Default score must contain user or email for key "%s"' % key) continue try: user = email.split('@', 1)[0] # for tests if user.startswith('no-reply+'): user = user[9:] except AttributeError: warning('Default score email "%s" must be a string for key "%s"' % (email, key)) continue if 'score' in s: try: score = float(s['score']) if isinf(score) or isnan(score): warning('Default score for user "%s" must be a number for key "%s"' % (user, key)) continue user_score = UserScore(user, score, time_now() - i) self.default_scores.append(user_score) except (ValueError, TypeError): warning('Default score for user "%s" must be a number for key "%s"' % (user, key)) continue else: warning('Default score for user "%s" missing score for key "%s"' % (user, key)) continue
def __init__(self, game): self.offerings = {} self.resources = {} self.issues = [] total_yaml_errors = 0 def add_infos(key, item): num_errors = len(item.errors) if num_errors > 0 or len(item.warnings) > 0: self.issues.append((key, { 'errors': item.errors, 'warnings': item.warnings })) return num_errors yaml_path = unicode(get_absolute_path(join_path(game.path, 'storeitems.yaml'))) if path_exists(yaml_path): try: with open(yaml_path, 'r') as f: items_meta = yaml.load(f) resource_keys = set() offering_keys = set() if isinstance(items_meta, list): for index, m in enumerate(items_meta): resource = StoreResource(game, m, resource_keys) resource.index = index total_yaml_errors += add_infos(resource.key, resource) self.resources[resource.key] = resource index = 0 items_meta_end = len(items_meta) - 1 for m in items_meta: try: m['output'] = {m['key']: 1} except KeyError: raise StoreError('Store item YAML item missing key') offering = StoreOffering(game, m, offering_keys, resource_keys) # put unavailable items at the end if offering.available: offering.index = index index += 1 else: offering.index = items_meta_end items_meta_end -= 1 total_yaml_errors += add_infos(offering.key, offering) self.offerings[offering.key] = offering elif isinstance(items_meta, dict): resource_meta = items_meta.get('resources') if not isinstance(resource_meta, list): raise StoreError('Store items YAML file must contain "resources"') for index, m in enumerate(resource_meta): resource = StoreResource(game, m, resource_keys) resource.index = index total_yaml_errors += add_infos(resource.key, resource) self.resources[resource.key] = resource offerings_meta = items_meta.get('offerings') if not isinstance(offerings_meta, list): raise StoreError('Store items YAML file must contain "offerings"') index = 0 items_meta_end = len(offerings_meta) - 1 for m in offerings_meta: offering = StoreOffering(game, m, offering_keys, resource_keys) # put unavailable items at the end if offering.available: offering.index = index index += 1 else: offering.index = items_meta_end items_meta_end -= 1 total_yaml_errors += add_infos(offering.key, offering) self.offerings[offering.key] = offering else: raise StoreError('Store items YAML file must be a dictionary or list') except (IOError, yaml.YAMLError) as e: LOG.error('Failed loading store items: %s', str(e)) raise StoreError('Failed loading storeitems.yaml file: %s' % str(e)) else: raise StoreUnsupported() if total_yaml_errors > 0: raise ValidationException(self.issues) self.store_users = StoreUserList(game, self)
def __init__(self, game, key, meta_data, index): self.user_scores = {} self.scores = [] self.aggregate = False self.aggregate_score = 0 self.lock = Lock() self.errors = [] self.warnings = [] self.path = None def error(msg): self.errors.append(msg) def warning(msg): self.warnings.append(msg) if not self.validate_key.match(key): error('invalid key format "%s"' % key) self.key = key self.index = index if 'title' not in meta_data or meta_data['title'] is None: error('title property missing for key "%s"' % key) self.title = '' else: self.title = meta_data['title'] if 'aggregate' in meta_data: if (isinstance(meta_data['aggregate'], bool)): self.aggregate = meta_data['aggregate'] else: warning('aggregate property must be a boolean for key "%s"' % key) self.aggregate = False else: self.aggregate = False try: sort_by = int(meta_data['sortBy']) if sort_by != -1 and sort_by != 1: error('sortBy must either -1 or 1 for key "%s"' % key) except KeyError: warning('sortBy property missing for key "%s"' % key) sort_by = 1 except ValueError: error('sortBy must either -1 or 1 for key "%s"' % key) sort_by = 1 self.sort_by = sort_by if 'icon' in meta_data: warning('"icon" yaml property has been deprecated please use ' '"icon256", "icon48" or "icon32" for leaderboard key "%s"' % key) try: icon_path = meta_data['icon256'] if path_exists(get_absolute_path(join_path(game.path, icon_path))): if splitext(icon_path)[1] != '.png': warning('icon256 must be in PNG format for key "%s"' % key) else: error('icon256 file does not exist for key "%s"' % key) except KeyError: warning('no icon256 (using default) for key "%s"' % key) self.game = game self.default_scores = [] default_scores = meta_data.get('default-scores', []) for (i, s) in enumerate(default_scores): if not isinstance(s, dict): warning('Default score must an array of objects for key "%s"' % key) continue user = s.get('user', None) if user is None: email = s.get('email', None) if email is None: warning('Default score must contain user or email for key "%s"' % key) continue try: user = email.split('@', 1)[0] # for tests if user.startswith('no-reply+'): user = user[9:] except AttributeError: warning('Default score email "%s" must be a string for key "%s"' % (email, key)) continue if 'score' in s: try: score = float(s['score']) if isinf(score) or isnan(score): warning('Default score for user "%s" must be a number for key "%s"' % (user, key)) continue user_score = UserScore(user, score, time_now() - i) self.default_scores.append(user_score) except (ValueError, TypeError): warning('Default score for user "%s" must be a number for key "%s"' % (user, key)) continue else: warning('Default score for user "%s" missing score for key "%s"' % (user, key)) continue
def __init__(self, game): self.offerings = {} self.resources = {} self.issues = [] total_yaml_errors = 0 def add_infos(key, item): num_errors = len(item.errors) if num_errors > 0 or len(item.warnings) > 0: self.issues.append((key, { 'errors': item.errors, 'warnings': item.warnings })) return num_errors yaml_path = unicode( get_absolute_path(join_path(game.path, 'storeitems.yaml'))) if path_exists(yaml_path): try: with open(yaml_path, 'r') as f: items_meta = yaml.load(f) resource_keys = set() offering_keys = set() if isinstance(items_meta, list): for index, m in enumerate(items_meta): resource = StoreResource(game, m, resource_keys) resource.index = index total_yaml_errors += add_infos( resource.key, resource) self.resources[resource.key] = resource index = 0 items_meta_end = len(items_meta) - 1 for m in items_meta: try: m['output'] = {m['key']: 1} except KeyError: raise StoreError( 'Store item YAML item missing key') offering = StoreOffering(game, m, offering_keys, resource_keys) # put unavailable items at the end if offering.available: offering.index = index index += 1 else: offering.index = items_meta_end items_meta_end -= 1 total_yaml_errors += add_infos( offering.key, offering) self.offerings[offering.key] = offering elif isinstance(items_meta, dict): resource_meta = items_meta.get('resources') if not isinstance(resource_meta, list): raise StoreError( 'Store items YAML file must contain "resources"' ) for index, m in enumerate(resource_meta): resource = StoreResource(game, m, resource_keys) resource.index = index total_yaml_errors += add_infos( resource.key, resource) self.resources[resource.key] = resource offerings_meta = items_meta.get('offerings') if not isinstance(offerings_meta, list): raise StoreError( 'Store items YAML file must contain "offerings"' ) index = 0 items_meta_end = len(offerings_meta) - 1 for m in offerings_meta: offering = StoreOffering(game, m, offering_keys, resource_keys) # put unavailable items at the end if offering.available: offering.index = index index += 1 else: offering.index = items_meta_end items_meta_end -= 1 total_yaml_errors += add_infos( offering.key, offering) self.offerings[offering.key] = offering else: raise StoreError( 'Store items YAML file must be a dictionary or list' ) except (IOError, yaml.YAMLError) as e: LOG.error('Failed loading store items: %s', str(e)) raise StoreError('Failed loading storeitems.yaml file: %s' % str(e)) else: raise StoreUnsupported() if total_yaml_errors > 0: raise ValidationException(self.issues) self.store_users = StoreUserList(game, self)
def check_completeness(self): errors = [] tmp = [] if not self.deploy_enable: tmp.append('"deploy" is disabled.') if self.is_temporary: tmp.append('Game is temporary.') path = self.path if not path or not path.is_set(): tmp.append('No path set.') path_correct = False else: path_correct = path.is_correct() if not path_correct: tmp.append('Incorrect path set.') if tmp: errors.append(('settings', {'errors': tmp})) tmp = [] plugin_main = self.plugin_main canvas_main = self.canvas_main flash_main = self.flash_main main_correct = True if (not plugin_main or not plugin_main.is_set()) and \ (not canvas_main or not canvas_main.is_set()) and \ (not flash_main or not flash_main.is_set()): tmp.append( 'No "main"-file set. Specify at least one of plugin or canvas main.' ) main_correct = False abs_path = get_absolute_path(path) if plugin_main: plugin_main = join_path(abs_path, plugin_main) if not access(plugin_main, R_OK): tmp.append('Can\'t access plugin "main"-file.') if canvas_main: canvas_main = join_path(abs_path, canvas_main) if not access(canvas_main, R_OK): tmp.append('Can\'t access canvas "main"-file.') if flash_main: if not flash_main.startswith('https://'): flash_main = join_path(abs_path, flash_main) if not access(flash_main, R_OK): tmp.append('Can\'t access flash "main"-file.') mapping_table = self.mapping_table if (not mapping_table or not mapping_table.is_set()) and not flash_main: tmp.append('No mapping-table set.') elif path_correct and main_correct: mapping_table = join_path(abs_path, mapping_table) if not access(mapping_table, R_OK): tmp.append('Can\'t access mapping-table.') deploy_files = self.deploy_files if not deploy_files or not deploy_files.is_set(): tmp.append('No deploy files set.') engine_version = self.engine_version if not engine_version or not engine_version.is_set(): tmp.append('No engine version set.') elif not engine_version.is_correct(): tmp.append('Invalid engine version set.') aspect_ratio = self.aspect_ratio if not aspect_ratio or not aspect_ratio.is_set(): tmp.append('No aspect ratio set.') elif not aspect_ratio.is_correct(): tmp.append('Invalid aspect ratio set.') if tmp: errors.append(('files', {'errors': tmp})) return (len(errors) == 0, {'Project-Settings': errors})