Example #1
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)
Example #2
0
                        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),
Example #3
0
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()