def reloadStage2(self): #disconnect before reloading dispatchers self._disconnect(self.oldservers) # Reset Dispatcher loaded modules # get a list of previously loaded modules so can track stale modules oldmodules = set(Dispatcher.MODULEDICT.keys()) Dispatcher.reset() #create databases so init() can do database things. self.createDatabases(self.newservers) for server in self.servers.itervalues(): server.initializeReload() Dispatcher.showLoadErrors() #compare currently loaded modules to oldmodules oldmodules = oldmodules.difference(set(Dispatcher.MODULEDICT.keys())) #remove oldmodules from sys.modules for module in oldmodules: module = "pyBurlyBot_%s" % module #prefix as was set in Dispatcher.load print "Removing module: %s" % module try: del modules[module] except KeyError: print "WARNING: module was never in modules %s" % module # connect after load dispatchers self._connect(self.newservers) self.oldservers = self.newservers = []
def initializeReload(self): # Dispatcher should only be created once. if self.dispatcher is None: #create dispatcher: self.dispatcher = Dispatcher(self) #else reload it else: self.dispatcher.reload()
def shutdown(self, relaunch=False): self._disconnect(self.servers.keys()) #stop timers or just not care... Timers._stopall() reactor.callLater(2.0, self.databasemanager.shutdown) # to give time for individual shutdown Dispatcher.unloadModules() reactor.callLater(2.5, reactor.stop) # to give time for individual shutdown # TODO: make sure this works properly # it may act odd on Windows due to execv not replacing current process. if relaunch: register(relaunchfunc, executable, argv)
def initializeReload(self): # Addons should only be created once if self.addons is None: self.addons = _ADDONS() else: self.addons.clear() # Dispatcher should only be created once. if self.dispatcher is None: #create dispatcher: self.dispatcher = Dispatcher(self) #else reload it else: self.dispatcher.reload()
def reloadStage2(self): #disconnect before reloading dispatchers self._disconnect(self.oldservers) # Reset Dispatcher loaded modules # get a list of previously loaded modules so can track stale modules oldmodules = set(Dispatcher.MODULEDICT.keys()) Dispatcher.reset() #create databases so init() can do database things. self.createDatabases(self.newservers) for server in self.servers.itervalues(): server.initializeReload() Dispatcher.showLoadErrors() #compare currently loaded modules to oldmodules oldmodules = oldmodules.difference(set(Dispatcher.MODULEDICT.keys())) #remove oldmodules from sys.modules for module in oldmodules: print "Removing module: %s" % module try: del modules[module] except KeyError: print "WARNING: module was never in modules %s" % module # connect after load dispatchers self._connect(self.newservers) self.oldservers = self.newservers = []
def run(): """ Bootstraps the application. """ dispatcher = Dispatcher() input_file_path = sys.argv[1] if len(sys.argv) > 1 else None if input_file_path: try: with open(input_file_path, "r") as f: for cmd in f: response = dispatcher.dispatch(cmd) except FileNotFoundError: logger.error("No such file: {}".format(input_file_path)) else: cmd = None while True: cmd = input() if cmd: if cmd == 'exit': break else: response = dispatcher.dispatch(cmd)
def setUp(self): self.dispatcher = Dispatcher()
class TestParkingLot(unittest.TestCase): def setUp(self): self.dispatcher = Dispatcher() def tearDown(self): self.dispatcher = None def test_1_parse_cmd(self): cmd = "CMD_{}".format(str(uuid4())) cmd_key, parsed_data = parse(cmd) self.assertIsNone( cmd_key, msg="{} is invalid command, command key must be null".format(cmd)) self.assertIsNone( parsed_data, msg="{} is invalid command, command info must be null".format(cmd)) cmd = "status" cmd_key, parsed_data = parse(cmd) self.assertIsNotNone( cmd_key, msg="{} is valid command, command key must not be null".format( cmd)) self.assertIsNotNone( parsed_data, msg="{} is valid command, command info must not be null".format( cmd)) def test_2_check_if_parking_lot_available(self): cmd = "status" response = self.dispatcher.dispatch(cmd) if not response.success: self.assertEqual(response.error, ErrorConstant.NO_PARKING_LOT_FOUND) def test_3_create(self): size = 7 response = self.create_parking_lot(size=size) self.assertEqual(size, int(response.data.get('size', 0))) def test_4_park(self): c_response = self.create_parking_lot(size=5) self.assertTrue(c_response.success) for i in range(0, 7): # PARKING_LOT_OVERFLOW p_response = self.dispatcher.dispatch( "park DL-3C-909{} GREY".format(i)) if not p_response.success: self.assertIn(p_response.error, (ErrorConstant.PARKING_LOT_OVERFLOW, ErrorConstant.NO_PARKING_LOT_FOUND, ErrorConstant.SLOT_OCCUPIED, ErrorConstant.VEHICLE_IS_ALREADY_PARKED)) c_response = self.create_parking_lot(size=5) self.assertTrue(c_response.success) for i in range(0, 5): # VEHICLE_IS_ALREADY_PARKED p_response = self.dispatcher.dispatch("park DL-3C-9010 GREY") if not p_response.success: self.assertIn(p_response.error, (ErrorConstant.PARKING_LOT_OVERFLOW, ErrorConstant.NO_PARKING_LOT_FOUND, ErrorConstant.SLOT_OCCUPIED, ErrorConstant.VEHICLE_IS_ALREADY_PARKED)) def test_5_leave(self): c_response = self.create_parking_lot(size=5) self.assertTrue(c_response.success) reg_nums = ["DL-3C-9070", "DL-3C-9071"] for reg_num in reg_nums: self.dispatcher.dispatch("park {} GREY".format(reg_num)) for slot_num in range(1, 7): l_res = self.dispatcher.dispatch("leave {}".format(slot_num)) if not l_res.success: self.assertEqual(l_res.error, ErrorConstant.INVALID_SLOT, msg="Invalid slot") else: reg_num = l_res.data.get('reg_num', None) self.assertEqual(reg_num, reg_nums[slot_num - 1]) def test_6_reg_nums_by_color(self): c_response = self.create_parking_lot(size=5) self.assertTrue(c_response.success) col_reg_nums_mapping = { 'White': {'park DL-3C-9090', 'park DL-3C-9091', 'park DL-3C-9092'}, 'Black': {'park DL-3C-9080', 'park DL-3C-9081'} } for col, reg_nums in col_reg_nums_mapping.items(): for reg_num in reg_nums: self.dispatcher.dispatch("park {} {}".format(reg_num, col)) for col in ['White', 'Black', 'Grey']: response = self.dispatcher.dispatch( 'registration_numbers_for_cars_with_colour {}'.format(col)) fetched_reg_nums = set(response.data.get('reg_nums', [])) if fetched_reg_nums and len(fetched_reg_nums) > 0: self.assertSetEqual(fetched_reg_nums, col_reg_nums_mapping.get(col, {})) def test_7_slot_nums_by_color(self): c_response = self.create_parking_lot(size=7) self.assertTrue(c_response.success) col_slot_nums_mapping = {'White': {'1', '2', '3'}, 'Black': {'4', '5'}} for col, slot_nums in col_slot_nums_mapping.items(): for slot_num in slot_nums: self.dispatcher.dispatch("park DL-3C-909{} {}".format( slot_num, col)) for col in ['White', 'Black', 'Grey']: response = self.dispatcher.dispatch( 'slot_numbers_for_cars_with_colour {}'.format(col)) fetched_slot_nums = set(response.data.get('slot_nums', [])) if fetched_slot_nums and len(fetched_slot_nums) > 0: self.assertSetEqual(fetched_slot_nums, col_slot_nums_mapping.get(col, {})) def test_8_slot_num_by_reg_num(self): c_response = self.create_parking_lot(size=7) self.assertTrue(c_response.success) reg_nums = ["DL-3C-9017", "DL-3C-9071", "DL-3C-9072", "DL-3C-9018"] for reg_num in reg_nums: self.dispatcher.dispatch("park {} GREY".format(reg_num)) for reg_num in [ "DL-3C-9017", "DL-3C-9071", "INVALID_REG_NUM1", "INVALID_REG_NUM2" ]: res = self.dispatcher.dispatch( 'slot_number_for_registration_number {}'.format(reg_num)) if not res.success: self.assertIsNone(res.data.get('slot_num', None)) def create_parking_lot(self, size=5): cmd = "create_parking_lot {}".format(str(size)) response = self.dispatcher.dispatch(cmd) return response
def hardshutdown(self): Timers._stopall() Dispatcher.unloadModules() self.databasemanager.shutdown()
class Server(BaseServer): def __init__(self, opts): BaseServer.__init__(self, opts) self.addons = None #dispatcher placeholder (probably not needed) self.dispatcher = None # TODO: fix the complicated relationship between Factory<->Settings<->Container # also the relationship between Dispatcher<->Settings<->Dispatcher self.container = Container(self) self._factory = BurlyBotFactory(self) def initializeReload(self): # Addons should only be created once if self.addons is None: self.addons = _ADDONS() else: self.addons.clear() # Dispatcher should only be created once. if self.dispatcher is None: #create dispatcher: self.dispatcher = Dispatcher(self) #else reload it else: self.dispatcher.reload() def __getattr__(self, name): # get Server setting if set, else fall back to global Settings if name in self.__dict__: return getattr(self, name) else: return getattr(Settings, name) def getOptions(self, opts, **kwargs): vals = [] for opt in opts: vals.append(self.getOption(opt, **kwargs)) return vals # if channel or server is set, retrieve for that specific thing. # if channel or server is False, retrieve "global" for that thing. # TODO: make sure this optimized as it can be def getOption(self, opt, module=None, channel=None, server=None, default=NoDefault, setDefault=True, inreactor=False): if opt in KEYS_DENY: raise ValueError("Access denied. (%s)" % opt) if module: if server or server is None: # try searching for option in a server object if not server is None: try: moduleopts = Settings.servers[server].moduleopts except KeyError: raise ValueError("Server (%s) not found" % server) else: moduleopts = self.moduleopts if module in moduleopts: mod = moduleopts[module] if channel and "_channels" in mod and channel in mod["_channels"] and opt in mod["_channels"][channel]: value = mod["_channels"][channel][opt] if type(value) in TYPE_COPY: # copy value if compound datatype return deepcopy(value) if inreactor else blockingCallFromThread(reactor, deepcopy, value) else: return value if opt in mod: value = mod[opt] if type(value) in TYPE_COPY: # copy value if compound datatype return deepcopy(value) if inreactor else blockingCallFromThread(reactor, deepcopy, value) else: return value # fall back to global moduleopts (or server was False) moduleopts = Settings.moduleopts # duplicated code from above, micro-optimization because bad. if module in moduleopts: mod = moduleopts[module] if channel and "_channels" in mod and channel in mod["_channels"] and opt in mod["_channels"][channel]: value = mod["_channels"][channel][opt] if type(value) in TYPE_COPY: # copy value if compound datatype return deepcopy(value) if inreactor else blockingCallFromThread(reactor, deepcopy, value) else: return value if opt in mod: value = mod[opt] if type(value) in TYPE_COPY: # copy value if compound datatype return deepcopy(value) if inreactor else blockingCallFromThread(reactor, deepcopy, value) else: return value if default is NoDefault: raise AttributeError("No setting (%s) for module: %s" % (opt, module)) else: if setDefault: moduleopts.setdefault(module, {})[opt] = default return default #non-module (core) options if server is None: server = self elif server: if not server in Settings.servers: raise ValueError("Server label (%s) not found." % server) server = Settings.servers[server] if server and opt in KEYS_SERVER_SET: value = getattr(self, opt) else: if not server or server is self: if opt not in KEYS_MAIN_SET: raise ValueError("Settings has no option: (%s) to get." % opt) else: value = getattr(Settings, opt) else: #case where a server setting is specifically attempted to be got, but it's not in KEYS_SERVER # instead of falling back to KEYS_MAIN, raise error raise ValueError("Server setting has no option: (%s) to get." % opt) if opt in KEYS_COPY: # copy value if compound datatype return deepcopy(value) if inreactor else blockingCallFromThread(reactor, deepcopy, value) else: return value def setOption(self, opt, value, module=None, channel=None, server=None): if opt in KEYS_DENY: raise ValueError("Access denied. (%s)" % opt) if type(value) in TYPE_COPY: value = deepcopy(value) # copy value if compound datatype if module: if server or server is None: # try searching for option in a server object if not server is None: try: moduleopts = Settings.servers[server].moduleopts except KeyError: raise ValueError("Server (%s) not found" % server) else: moduleopts = self.moduleopts mod = moduleopts.setdefault(module, {}) if channel: mod.setdefault("_channels", {}).setdefault(channel, {})[opt] = value else: mod[opt] = value return # if server was False, (setting "global") moduleopts = Settings.moduleopts # duplicated code from above, micro-optimization because bad. mod = moduleopts.setdefault(module, {}) if channel: mod.setdefault("_channels", {}).setdefault(channel, {})[opt] = value else: mod[opt] = value else: if server is None: server = self elif server: if not server in Settings.servers: raise ValueError("Server label (%s) not found." % server) server = Settings.servers[server] if server and opt in KEYS_SERVER_SET: setattr(self, opt, value) else: if not server or server is self: if opt not in KEYS_MAIN_SET: raise ValueError("Settings has no option: (%s) to set." % opt) else: setattr(Settings, opt, value) else: #case where a server setting is specifically attempted to be set, but it's not in KEYS_SERVER # instead of falling back to KEYS_MAIN, raise error raise ValueError("Server settings has no option: (%s) to set." % opt) def getModule(self, modname): if not self.isModuleAvailable(modname): raise ConfigException("Module (%s) is not available." % modname) else: return Dispatcher.MODULEDICT.get(modname) def isModuleAvailable(self, modname): return (modname not in self.denymodules) and (modname in Dispatcher.MODULEDICT) def getAddon(self, addonname): try: modname, f = self.addons._getModuleAddon(addonname) except KeyError: raise AttributeError("No provider for %s" % addonname) if self.isModuleAvailable(modname): return f else: raise AttributeError("Provider %s is not available because module (%s) is not available." % (addonname, modname))