<commit_before>
import sys
import datetime
import logging
import signal

import tornado.ioloop
import tornado.gen

import motor

import two.webconn
import two.playconn
import two.mongomgr
import two.commands
import two.task
import twcommon.misc
import twcommon.autoreload
from twcommon import wcproto

class Tworld(object):
    def __init__(self, opts):
        self.opts = opts
        self.log = logging.getLogger('tworld')

        self.all_commands = two.commands.define_commands()
        
        # This will be self.mongomgr.mongo[mongo_database], when that's
        # available.
        self.mongodb = None

        self.webconns = two.webconn.WebConnectionTable(self)
        self.playconns = two.playconn.PlayerConnectionTable(self)
        self.mongomgr = two.mongomgr.MongoMgr(self)

        # The command queue.
        self.queue = []
        self.commandbusy = False

        # Miscellaneous.
        self.caughtinterrupt = False
        self.shuttingdown = False

        # When the IOLoop starts, we'll set up periodic tasks.
        tornado.ioloop.IOLoop.instance().add_callback(self.init_timers)
        
    def init_timers(self):
        self.ioloop = tornado.ioloop.IOLoop.current()
        try:
            self.webconns.listen()
        except Exception as ex:
            self.log.error('Unable to listen on socket: %s', ex)
            self.ioloop.stop()
            return
        self.mongomgr.init_timers()

        # Catch SIGINT (ctrl-C) and SIGHUP with our own signal handler.
        # The handler will try to close sockets cleanly and allow messages
        # to drain out.
        # (Not SIGKILL; we leave that as a shut-down-right-now option.)
        signal.signal(signal.SIGINT, self.interrupt_handler)
        signal.signal(signal.SIGHUP, self.interrupt_handler)

        # This periodic command kicks disconnected players to the void.
        # (Every three minutes, plus an uneven fraction of a second.)
        def func():
            self.queue_command({'cmd':'checkdisconnected'})
        res = tornado.ioloop.PeriodicCallback(func, 180100)
        res.start()

    def shutdown(self, reason=None):
        """This is called when an orderly shutdown is requested. (Either
        an admin request, or by the interrupt handler.) It should only
        be called as part of its own command queue event (shutdownprocess).

        We set the shuttingdown flag, which means the command queue is
        frozen. Then we close all the sockets. Then we wait a second, to
        allow the sockets to finish closing. (IOStream doesn't seem to
        have an async close, seriously, wtf.) Then we exit the process.

        Reason 'autoreload' is a special case, triggered by the
        tornado.autoreload module. (Actually our patched version in
        twcommon.) That's the case where we're going to relaunch the
        process, rather than just exiting.
        """
        self.shuttingdown = True
        self.mongomgr.close()
        self.webconns.close()
        self.log.info('Waiting 1 second for sockets to drain...')
        if reason == 'autoreload':
            def finalshutdown():
                self.log.info('Autoreloading for real.')
                twcommon.autoreload.autoreload()
        else:
            def finalshutdown():
                self.log.info('Shutting down for real.')
                sys.exit(0)
        self.ioloop.add_timeout(datetime.timedelta(seconds=1.0),
                                finalshutdown)

    def interrupt_handler(self, signum, stackframe):
        """This is called when Python catches a SIGINT (ctrl-C) signal.
        (It replaces the usual behavior of raising KeyboardInterrupt.)
        It's also called on SIGHUP. (But not SIGKILL.)<commit_msg>More shutdown stages.<commit_after>
import sys
import datetime
import logging
import signal

import tornado.ioloop
import tornado.gen

import motor

import two.webconn
import two.playconn
import two.mongomgr
import two.commands
import two.task
import twcommon.misc
import twcommon.autoreload
from twcommon import wcproto

class Tworld(object):
    def __init__(self, opts):
        self.opts = opts
        self.log = logging.getLogger('tworld')

        self.all_commands = two.commands.define_commands()
        
        # This will be self.mongomgr.mongo[mongo_database], when that's
        # available.
        self.mongodb = None

        self.webconns = two.webconn.WebConnectionTable(self)
        self.playconns = two.playconn.PlayerConnectionTable(self)
        self.mongomgr = two.mongomgr.MongoMgr(self)

        # The command queue.
        self.queue = []
        self.commandbusy = False

        # Miscellaneous.
        self.caughtinterrupt = False
        self.shuttingdown = False

        # When the IOLoop starts, we'll set up periodic tasks.
        tornado.ioloop.IOLoop.instance().add_callback(self.init_timers)
        
    def init_timers(self):
        self.ioloop = tornado.ioloop.IOLoop.current()
        try:
            self.webconns.listen()
        except Exception as ex:
            self.log.error('Unable to listen on socket: %s', ex)
            self.ioloop.stop()
            return
        self.mongomgr.init_timers()

        # Catch SIGINT (ctrl-C) and SIGHUP with our own signal handler.
        # The handler will try to close sockets cleanly and allow messages
        # to drain out.
        # (Not SIGKILL; we leave that as a shut-down-right-now option.)
        signal.signal(signal.SIGINT, self.interrupt_handler)
        signal.signal(signal.SIGHUP, self.interrupt_handler)

        # This periodic command kicks disconnected players to the void.
        # (Every three minutes, plus an uneven fraction of a second.)
        def func():
            self.queue_command({'cmd':'checkdisconnected'})
        res = tornado.ioloop.PeriodicCallback(func, 180100)
        res.start()

    def shutdown(self, reason=None):
        """This is called when an orderly shutdown is requested. (Either
        an admin request, or by the interrupt handler.) It should only
        be called as part of its own command queue event (shutdownprocess).

        We set the shuttingdown flag, which means the command queue is
        frozen. Then we close all the sockets. Then we wait a second, to
        allow the sockets to finish closing. (IOStream doesn't seem to
        have an async close, seriously, wtf.) Then we exit the process.

        Reason 'autoreload' is a special case, triggered by the
        tornado.autoreload module. (Actually our patched version in
        twcommon.) That's the case where we're going to relaunch the
        process, rather than just exiting.
        """
        self.shuttingdown = True
        def shutdown_cont():
            if reason == 'autoreload':
                def shutdown_final():
                    self.log.info('Autoreloading for real.')
                    twcommon.autoreload.autoreload()
            else:
                def shutdown_final():
                    self.log.info('Shutting down for real.')
                    sys.exit(0)
            self.mongomgr.close()
            self.webconns.close()
            self.log.info('Waiting 1 second for sockets to close...')
            self.ioloop.add_timeout(datetime.timedelta(seconds=1.0),
                                    shutdown_final)
            return
        self.log.info('Waiting 1 second for sockets to drain...')
        self.ioloop.add_timeout(datetime.timedelta(seconds=1.0),
                                shutdown_cont)
        
    def interrupt_handler(self, signum, stackframe):
        """This is called when Python catches a SIGINT (ctrl-C) signal.
        (It replaces the usual behavior of raising KeyboardInterrupt.)
        It's also called on SIGHUP. (But not SIGKILL.)
{'fraction_non_alphanumeric': 0.08120590121872996, 'fraction_numerical': 0.00295060936497755, 'mean_word_length': 2.2228193468375363, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '176582', 'n_tokens_mistral': 2220, 'n_tokens_neox': 2097, 'n_words': 681}