def __init__(self, root, settings_override): self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(logging.INFO) self.log.info('starting') self._res_home = os.path.join(root, "static") self._templates_home = os.path.join(root, "templates") self._handlers = \ admin.handlers + \ tv.handlers + \ api.handlers + \ [ (r"/help", self.WSHHelp), (r"/css/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'css')}), (r"/js/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'js')}), (r"/img/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'img')}), (r"/fonts/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'fonts')}), (r"/docs/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'docs')}), (r"/manifest.json", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'manifest.json')}) ] self._lock = threading.Lock() settings = { 'debug': False, 'template_path': self._templates_home, 'ui_modules': uimodules, } self._data_home = settings_override['data_home'] self.log.info("data home: %s", self._data_home) if not os.path.exists(self._data_home): self.log.warning('creating data home (%s) - no team data available' % self._data_home) os.makedirs(self._data_home) elif not os.path.isdir(self._data_home): raise ValueError('data_home : path exists and is not a directory (%s)' % self._data_home) else: self._version = self._get_version() self.log.info('version: %s', self._version) checker_path = os.path.join(self._data_home, '$$tmp') try: with file(checker_path, 'wt') as fp: fp.write('test') except Exception: raise ValueError('data_home : cannot write in directory (%s)' % self._data_home) else: os.remove(checker_path) settings.update(settings_override) self.debug = settings['debug'] if self.debug: self.log.setLevel(logging.DEBUG) self._display_sequence = json.loads(settings['display_sequence']) self._client_sequences = {} self._tv_message = None self._tournament = Tournament(self.ROBOTICS_ROUND_TYPES) # try to load a previously saved tournament if any, or create a new one otherwise # (we check first that it is not from an older version of the event, based on the # teams file) tournament_file = os.path.join(self._data_home, self.TOURNAMENT_DATA_FILE) if os.path.exists(tournament_file): teams_mtime = os.stat(os.path.join(self._data_home, self.TEAMS_DATA_FILE)).st_mtime if teams_mtime > os.stat(tournament_file).st_mtime: self.log.warn('found a tournament file, but is older than teams => creating a new one') self._initialize_tournament(self._tournament) else: self._load_tournament(self._tournament) else: self.log.warn('... no previous tournament data found => creating a new one') self._initialize_tournament(self._tournament) self.log.info('tournament data initialized') super(PJCWebApp, self).__init__(self._handlers, **settings)
default=all_types) args = parser.parse_args() if not os.path.exists(args.output_dir): os.makedirs(args.output_dir) print( dedent(""" input files : - %s - %s """ ).strip() % (os.path.abspath(args.teams_file.name), os.path.abspath(args.planning_file.name)) ) _tournament = Tournament() print('loading team info') _tournament.load_teams_info(fp=args.teams_file) print('loading teams plannings') _tournament.load_teams_plannings(fp=args.planning_file) _tournament.assign_tables_and_juries() _tournament.consolidate_planning() print('generating documents in : %s' % args.output_dir) for code in _generators.keys(): if code in args.doctypes: func, label, pdf_name, page_size = _generators[code] pdf_file_name = pdf_name + '.pdf' pdf_doc = FormsDocTemplate( filename=os.path.join(args.output_dir, pdf_file_name),
class PJCWebApp(tornado.web.Application): """ The Web application """ TOURNAMENT_DATA_FILE = 'tournament.dat' VERSION_FILE = 'version.txt' TEAMS_DATA_FILE = 'teams.csv' PLANNING_DATA_FILE = 'planning.csv' ROBOTICS_ROUND_TYPES = (Round1Score, Round2Score, Round3Score) # how many teams per TV display page TV_PAGE_SIZE = 10 _data_home = None class WSHHelp(tornado.web.RequestHandler): """ Returns the paths defined for the application. Intended for help when working with curl at command line. """ def get(self, *args, **kwargs): self.write("Defined routes :\n") for handler in self._handlers: self.write("- %s\n" % handler[0]) def __init__(self, root, settings_override): self.log = logging.getLogger(self.__class__.__name__) self.log.setLevel(logging.INFO) self.log.info('starting') self._res_home = os.path.join(root, "static") self._templates_home = os.path.join(root, "templates") self._handlers = \ admin.handlers + \ tv.handlers + \ api.handlers + \ [ (r"/help", self.WSHHelp), (r"/css/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'css')}), (r"/js/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'js')}), (r"/img/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'img')}), (r"/fonts/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'fonts')}), (r"/docs/(.*)", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'docs')}), (r"/manifest.json", tornado.web.StaticFileHandler, {"path": os.path.join(self._res_home, 'manifest.json')}) ] self._lock = threading.Lock() settings = { 'debug': False, 'template_path': self._templates_home, 'ui_modules': uimodules, } self._data_home = settings_override['data_home'] self.log.info("data home: %s", self._data_home) if not os.path.exists(self._data_home): self.log.warning('creating data home (%s) - no team data available' % self._data_home) os.makedirs(self._data_home) elif not os.path.isdir(self._data_home): raise ValueError('data_home : path exists and is not a directory (%s)' % self._data_home) else: self._version = self._get_version() self.log.info('version: %s', self._version) checker_path = os.path.join(self._data_home, '$$tmp') try: with file(checker_path, 'wt') as fp: fp.write('test') except Exception: raise ValueError('data_home : cannot write in directory (%s)' % self._data_home) else: os.remove(checker_path) settings.update(settings_override) self.debug = settings['debug'] if self.debug: self.log.setLevel(logging.DEBUG) self._display_sequence = json.loads(settings['display_sequence']) self._client_sequences = {} self._tv_message = None self._tournament = Tournament(self.ROBOTICS_ROUND_TYPES) # try to load a previously saved tournament if any, or create a new one otherwise # (we check first that it is not from an older version of the event, based on the # teams file) tournament_file = os.path.join(self._data_home, self.TOURNAMENT_DATA_FILE) if os.path.exists(tournament_file): teams_mtime = os.stat(os.path.join(self._data_home, self.TEAMS_DATA_FILE)).st_mtime if teams_mtime > os.stat(tournament_file).st_mtime: self.log.warn('found a tournament file, but is older than teams => creating a new one') self._initialize_tournament(self._tournament) else: self._load_tournament(self._tournament) else: self.log.warn('... no previous tournament data found => creating a new one') self._initialize_tournament(self._tournament) self.log.info('tournament data initialized') super(PJCWebApp, self).__init__(self._handlers, **settings) @property def version(self): return self._version def _get_version(self): version_file_path = os.path.join(self._data_home, self.VERSION_FILE) try: with open(version_file_path, 'rt') as fp: return Version(fp) except IOError: return Version() def _initialize_tournament(self, tournament): """ Initializes a tournament instance, loading the teams definition if the related configuration file exists """ teams_file = os.path.join(self._data_home, self.TEAMS_DATA_FILE) if os.path.exists(teams_file): self.log.info('loading teams from %s' % teams_file) with file(teams_file, 'rt') as fp: tournament.load_teams_info(fp) self.log.info('... done') else: self.log.warn('no team file found in %s' % self._data_home) planning_file = os.path.join(self._data_home, self.PLANNING_DATA_FILE) if os.path.exists(planning_file): self.log.info('loading planning from %s' % planning_file) with file(planning_file, 'rt') as fp: tournament.load_teams_plannings(fp) self.log.info('consolidating planning') tournament.consolidate_planning() self.log.info('assigning tables and juries') tournament.assign_tables_and_juries() self.log.info('... initialization complete') self.save_tournament() else: self.log.warn('no planning file found in %s' % self._data_home) @property def _tournament_file_path(self): return os.path.join(self._data_home, self.TOURNAMENT_DATA_FILE) def _load_tournament(self, tournament, silent=False): teams_file = os.path.join(self._data_home, self.TEAMS_DATA_FILE) team_file_mtime = os.stat(teams_file).st_mtime self.log.info('loading tournament from %s', self._tournament_file_path) with file(self._tournament_file_path, 'rb') as fp: tournament.deserialize(json.load(fp)) def save_tournament(self): """ Saves the tournament to disk. """ with file(self._tournament_file_path, 'wb') as fp: json.dump(self._tournament.serialize(), fp, indent=4) self.log.info('tournament saved to %s' % self._tournament_file_path) def reset_tournament(self): """ Deletes the saved tournament and restarts with a new one """ try: os.remove(self.TOURNAMENT_DATA_FILE) except OSError: pass self._initialize_tournament(self._tournament) self.log.info('tournament cleared') def client_is_known(self, client): return client in self._client_sequences def get_client_sequence(self, client): with self._lock: if self.debug: self.log.debug('sequences=%s', self._client_sequences) key = str(client) try: sequence = self._client_sequences[key] if len(sequence) == 0: raise KeyError() except KeyError: sequence = self._display_sequence[:] self._client_sequences[key] = sequence return sequence @property def display_sequence(self): return self._display_sequence @display_sequence.setter def display_sequence(self, sequence): with self._lock: self._display_sequence = sequence[:] self.log.info("display sequence changed to : %s", self._display_sequence) self._client_sequences = {} def required_pages(self, display): if display == 'ranking': return ((len(self.tournament.get_competing_teams()) - 1) / self.TV_PAGE_SIZE) + 1 elif display == 'next_schedules': return 1 else: return ((self.tournament.team_count(present_only=True) - 1) / self.TV_PAGE_SIZE) + 1 @property def title(self): return "PJCWebApplication" @property def tv_message(self): return self._tv_message @tv_message.setter def tv_message(self, msg): self._tv_message = msg @tv_message.deleter def tv_message(self): self._tv_message = None @property def tournament(self): return self._tournament def start(self, port=8080): """ Starts the application """ self.listen(port) signal.signal(signal.SIGTERM, self.signals_handler) signal.signal(signal.SIGINT, self.signals_handler) self.log.info("server IO loop started") tornado.ioloop.IOLoop.current().start() self.log.info("server IO loop terminated") def signals_handler(self, sig, frame): self.log.info('Caught signal: %s', sig) tornado.ioloop.IOLoop.instance().add_callback(self.shutdown) def shutdown(self): self.log.info('stopping server IOloop...') tornado.ioloop.IOLoop.instance().stop()