mirror of
https://github.com/solero/houdini.git
synced 2024-11-08 20:28:20 +00:00
Remove all code related to "hot-reloading"
Support is being dropped for now and until further notice.
This commit is contained in:
parent
9098ae50a1
commit
8a9f2e8b99
@ -5,7 +5,8 @@ from abc import abstractmethod
|
||||
import asyncio
|
||||
import enum
|
||||
import logging
|
||||
import copy
|
||||
import importlib
|
||||
import pkgutil
|
||||
|
||||
|
||||
class StatusField(enum.IntEnum):
|
||||
@ -19,7 +20,7 @@ class StatusField(enum.IntEnum):
|
||||
HasWalkedPuffleFirstTime = 65536
|
||||
HasWalkedPuffleSecondTime = 131072
|
||||
|
||||
|
||||
package_modules = package_modules + sub_package_modules
|
||||
class ConflictResolution(enum.Enum):
|
||||
Silent = 0
|
||||
Append = 1
|
||||
@ -45,24 +46,15 @@ class _AbstractManager(dict):
|
||||
self.server = server
|
||||
self.logger = logging.getLogger('houdini')
|
||||
|
||||
self.__backup = None
|
||||
super().__init__()
|
||||
|
||||
@abstractmethod
|
||||
def load(self, module):
|
||||
"""Loads entries from module"""
|
||||
async def setup(self, module):
|
||||
"""Setup manager class"""
|
||||
|
||||
@abstractmethod
|
||||
def remove(self, module):
|
||||
"""Removes all entries by module"""
|
||||
|
||||
def backup(self):
|
||||
self.__backup = copy.copy(self)
|
||||
|
||||
def restore(self):
|
||||
if self.__backup is not None:
|
||||
self.update(self.__backup)
|
||||
self.__backup = None
|
||||
async def load(self, module):
|
||||
"""Loads entries from module"""
|
||||
|
||||
|
||||
class PenguinStringCompiler(OrderedDict):
|
||||
|
@ -64,6 +64,7 @@ player_in_room = handlers.player_in_room
|
||||
|
||||
class CommandManager(_AbstractManager):
|
||||
def load(self, module):
|
||||
async def load(self, module):
|
||||
command_objects = inspect.getmembers(module, is_command)
|
||||
if not isinstance(module, plugins.IPlugin):
|
||||
raise TypeError('Commands can only be loaded from plugins')
|
||||
@ -94,12 +95,6 @@ class CommandManager(_AbstractManager):
|
||||
else:
|
||||
parent_commands[name] = [command_object]
|
||||
|
||||
def remove(self, module):
|
||||
for command_name, command_handlers in self.items():
|
||||
for command_handler in command_handlers:
|
||||
if module.__name__ == command_handler.callback.__module__:
|
||||
command_handlers.remove(command_handler)
|
||||
|
||||
|
||||
def is_command(command_object):
|
||||
return issubclass(type(command_object), _Command)
|
||||
|
@ -1,41 +0,0 @@
|
||||
import os
|
||||
|
||||
|
||||
def evaluate_listener_file_event(listener_file_event):
|
||||
# Ignore all directory events
|
||||
if listener_file_event.is_directory:
|
||||
return False
|
||||
|
||||
listener_module_path = listener_file_event.src_path[2:]
|
||||
|
||||
# Ignore non-Python files
|
||||
if listener_module_path[-3:] != ".py":
|
||||
return False
|
||||
|
||||
# Ignore package index files
|
||||
if '__init__.py' in listener_module_path:
|
||||
return False
|
||||
|
||||
listener_module = listener_module_path.replace(os.path.sep, ".")[:-3]
|
||||
|
||||
return listener_module_path, listener_module
|
||||
|
||||
|
||||
def evaluate_plugin_file_event(plugin_file_event):
|
||||
# Ignore all directory events
|
||||
if plugin_file_event.is_directory:
|
||||
return False
|
||||
|
||||
plugin_module_path = plugin_file_event.src_path[2:]
|
||||
|
||||
# Ignore non-Python files
|
||||
if plugin_module_path[-3:] != ".py":
|
||||
return False
|
||||
|
||||
# Remove file extension and replace path separator with dots. Then make like a banana.. and split.
|
||||
plugin_module_tokens = plugin_module_path.replace(os.path.sep, ".")[:-3].split(".")
|
||||
|
||||
if plugin_module_tokens.pop() == "__init__":
|
||||
return plugin_module_path, ".".join(plugin_module_tokens)
|
||||
|
||||
return False
|
@ -1,88 +0,0 @@
|
||||
import sys
|
||||
import importlib
|
||||
import logging
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
|
||||
from houdini.events import evaluate_listener_file_event
|
||||
|
||||
|
||||
class ListenerFileEventHandler(FileSystemEventHandler):
|
||||
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
self.logger = logging.getLogger('houdini')
|
||||
|
||||
def on_created(self, event):
|
||||
listener_module_details = evaluate_listener_file_event(event)
|
||||
|
||||
if not listener_module_details:
|
||||
return
|
||||
|
||||
listener_module_path, listener_module = listener_module_details
|
||||
|
||||
self.logger.debug('New listener module detected {}'.format(listener_module))
|
||||
|
||||
try:
|
||||
module = importlib.import_module(listener_module)
|
||||
self.server.xt_listeners.load(module)
|
||||
self.server.xml_listeners.load(module)
|
||||
|
||||
self.logger.info('New listener module loaded {}'.format(listener_module))
|
||||
except Exception as import_error:
|
||||
self.logger.error('{} detected in {}, not importing'.format(
|
||||
import_error.__class__.__name__, listener_module))
|
||||
|
||||
def on_deleted(self, event):
|
||||
listener_module_details = evaluate_listener_file_event(event)
|
||||
|
||||
if not listener_module_details:
|
||||
return
|
||||
|
||||
listener_module_path, listener_module = listener_module_details
|
||||
|
||||
if listener_module not in sys.modules:
|
||||
return
|
||||
|
||||
listener_module_object = sys.modules[listener_module]
|
||||
|
||||
self.logger.debug('Deleting listener module {}'.format(listener_module))
|
||||
|
||||
self.server.xt_listeners.remove(listener_module_object)
|
||||
self.server.xml_listeners.remove(listener_module_object)
|
||||
del sys.modules[listener_module]
|
||||
|
||||
self.logger.info('Deleted listener module {}'.format(listener_module))
|
||||
|
||||
def on_modified(self, event):
|
||||
listener_module_details = evaluate_listener_file_event(event)
|
||||
|
||||
if not listener_module_details:
|
||||
return
|
||||
|
||||
listener_module_path, listener_module = listener_module_details
|
||||
|
||||
if listener_module not in sys.modules:
|
||||
return False
|
||||
|
||||
self.logger.info('Reloading listener module {}'.format(listener_module))
|
||||
|
||||
self.server.xt_listeners.backup()
|
||||
self.server.xml_listeners.backup()
|
||||
|
||||
listener_module_object = sys.modules[listener_module]
|
||||
|
||||
self.server.xt_listeners.remove(listener_module_object)
|
||||
self.server.xml_listeners.remove(listener_module_object)
|
||||
|
||||
try:
|
||||
module = importlib.reload(listener_module_object)
|
||||
self.server.xt_listeners.load(module)
|
||||
self.server.xml_listeners.load(module)
|
||||
|
||||
self.logger.info('Successfully reloaded listener module {}!'.format(listener_module))
|
||||
except Exception as rebuild_error:
|
||||
self.logger.error('{} detected in {}, not reloading.'.format(
|
||||
rebuild_error.__class__.__name__, listener_module))
|
||||
|
||||
self.server.xt_listeners.restore()
|
||||
self.server.xml_listeners.restore()
|
@ -1,87 +0,0 @@
|
||||
import sys
|
||||
import importlib
|
||||
import os.path
|
||||
import logging
|
||||
from watchdog.events import FileSystemEventHandler
|
||||
|
||||
from houdini.events import evaluate_plugin_file_event
|
||||
|
||||
|
||||
class PluginFileEventHandler(FileSystemEventHandler):
|
||||
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
self.logger = logging.getLogger('houdini')
|
||||
|
||||
def on_created(self, event):
|
||||
plugin_module_details = evaluate_plugin_file_event(event)
|
||||
|
||||
if not plugin_module_details:
|
||||
return
|
||||
|
||||
plugin_module_path, plugin_module = plugin_module_details
|
||||
|
||||
self.logger.debug('New plugin detected {}'.format(plugin_module))
|
||||
|
||||
try:
|
||||
plugin_module_object = importlib.import_module(plugin_module)
|
||||
|
||||
self.server.plugins.load(plugin_module_object)
|
||||
|
||||
self.logger.info('New plugin {} has been loaded'.format(plugin_module))
|
||||
except Exception as import_error:
|
||||
self.logger.error('{} detected in {}, not importing'.format(
|
||||
import_error.__class__.__name__, plugin_module))
|
||||
|
||||
def on_deleted(self, event):
|
||||
plugin_module_path = event.src_path[2:]
|
||||
|
||||
plugin_module = plugin_module_path.replace(os.path.sep, ".")
|
||||
|
||||
if plugin_module not in sys.modules:
|
||||
return
|
||||
|
||||
self.logger.debug('Deleting plugin {}'.format(plugin_module))
|
||||
|
||||
plugin_module_object = sys.modules[plugin_module]
|
||||
|
||||
self.server.plugins.remove(plugin_module_object)
|
||||
del sys.modules[plugin_module]
|
||||
|
||||
self.logger.info('Plugin {} has been removed'.format(plugin_module))
|
||||
|
||||
def on_modified(self, event):
|
||||
plugin_module_details = evaluate_plugin_file_event(event)
|
||||
if not plugin_module_details:
|
||||
return
|
||||
|
||||
plugin_module_path, plugin_module = plugin_module_details
|
||||
|
||||
if plugin_module not in sys.modules:
|
||||
return
|
||||
|
||||
self.logger.info('Reloading plugin {}'.format(plugin_module))
|
||||
|
||||
plugin_module_object = sys.modules[plugin_module]
|
||||
|
||||
self.server.xt_listeners.backup()
|
||||
self.server.xml_listeners.backup()
|
||||
self.server.commands.backup()
|
||||
|
||||
self.server.plugins.remove(plugin_module_object)
|
||||
|
||||
try:
|
||||
new_plugin_module = importlib.reload(plugin_module_object)
|
||||
|
||||
self.server.plugins.load(new_plugin_module)
|
||||
|
||||
self.logger.info('Successfully reloaded plugin {}'.format(plugin_module))
|
||||
except LookupError as lookup_error:
|
||||
self.logger.warning('Did not reload plugin \'{}\': {}'.format(plugin_module, lookup_error))
|
||||
except Exception as rebuild_error:
|
||||
self.logger.error('{} detected in {}, not reloading'.format(
|
||||
rebuild_error.__class__.__name__, plugin_module))
|
||||
|
||||
self.server.xt_listeners.restore()
|
||||
self.server.xml_listeners.restore()
|
||||
self.server.commands.restore()
|
@ -118,16 +118,12 @@ class _ListenerManager(_AbstractManager):
|
||||
|
||||
super().__init__(server)
|
||||
|
||||
def setup(self, module, strict_load=None, exclude_load=None):
|
||||
async def setup(self, module, strict_load=None, exclude_load=None):
|
||||
self.strict_load, self.exclude_load = strict_load, exclude_load
|
||||
for handler_module in self.server.get_package_modules(module):
|
||||
module = sys.modules[handler_module] if handler_module in sys.modules.keys() \
|
||||
else importlib.import_module(handler_module)
|
||||
self.load(module)
|
||||
for handler_module in get_package_modules(module):
|
||||
await self.load(handler_module)
|
||||
|
||||
self.logger.debug('Loaded {} listeners'.format(len(self)))
|
||||
|
||||
def load(self, module):
|
||||
async def load(self, module):
|
||||
module_name = module.__module__ if isinstance(module, plugins.IPlugin) else module.__name__
|
||||
if not (self.strict_load and module_name not in self.strict_load or
|
||||
self.exclude_load and module_name in self.exclude_load):
|
||||
@ -159,12 +155,6 @@ class _ListenerManager(_AbstractManager):
|
||||
for override in listener_object.overrides:
|
||||
self[override.packet].remove(override)
|
||||
|
||||
def remove(self, module):
|
||||
for handler_id, handler_listeners in self.items():
|
||||
for handler_listener in handler_listeners:
|
||||
if module.__name__ == handler_listener.callback.__module__:
|
||||
handler_listeners.remove(handler_listener)
|
||||
|
||||
@classmethod
|
||||
def is_listener(cls, listener):
|
||||
return issubclass(type(listener), _Listener)
|
||||
|
@ -1,8 +1,6 @@
|
||||
import asyncio
|
||||
import os
|
||||
import sys
|
||||
import pkgutil
|
||||
import importlib
|
||||
import copy
|
||||
|
||||
from houdini.spheniscidae import Spheniscidae
|
||||
@ -15,7 +13,6 @@ from logging.handlers import RotatingFileHandler
|
||||
|
||||
import aioredis
|
||||
from aiocache import SimpleMemoryCache, caches
|
||||
from watchdog.observers import Observer
|
||||
|
||||
from houdini.data import db
|
||||
from houdini.data.item import ItemCrumbsCollection
|
||||
@ -37,8 +34,6 @@ except ImportError:
|
||||
|
||||
import houdini.handlers
|
||||
import houdini.plugins
|
||||
from houdini.events.listener_file_event import ListenerFileEventHandler
|
||||
from houdini.events.plugin_file_event import PluginFileEventHandler
|
||||
|
||||
from houdini.handlers import XTListenerManager, XMLListenerManager
|
||||
from houdini.plugins import PluginManager
|
||||
@ -170,11 +165,12 @@ class Houdini:
|
||||
PenguinStringCompiler.setup_default_builder(self.penguin_string_compiler)
|
||||
PenguinStringCompiler.setup_anonymous_default_builder(self.anonymous_penguin_string_compiler)
|
||||
|
||||
self.xml_listeners.setup(houdini.handlers, exclude_load='houdini.handlers.login.login')
|
||||
self.xt_listeners.setup(houdini.handlers)
|
||||
await self.xml_listeners.setup(houdini.handlers, exclude_load='houdini.handlers.login.login')
|
||||
await self.xt_listeners.setup(houdini.handlers)
|
||||
await self.dummy_event_listeners.setup(houdini.handlers)
|
||||
self.logger.info('World server started')
|
||||
else:
|
||||
self.xml_listeners.setup(houdini.handlers, 'houdini.handlers.login.login')
|
||||
await self.xml_listeners.setup(houdini.handlers, 'houdini.handlers.login.login')
|
||||
self.logger.info('Login server started')
|
||||
|
||||
self.items = await ItemCrumbsCollection.get_collection()
|
||||
@ -218,11 +214,6 @@ class Houdini:
|
||||
|
||||
self.permissions = await PermissionCrumbsCollection.get_collection()
|
||||
|
||||
handlers_path = os.path.join(os.path.dirname(__file__), 'handlers')
|
||||
plugins_path = os.path.join(os.path.dirname(__file__), 'plugins')
|
||||
self.configure_observers([handlers_path, ListenerFileEventHandler],
|
||||
[plugins_path, PluginFileEventHandler])
|
||||
|
||||
self.logger.info('Multi-client support is {}'.format(
|
||||
'enabled' if self.config.client['MultiClientSupport'] else 'disabled'))
|
||||
self.logger.info('Listening on {}:{}'.format(self.server_config['Address'], self.server_config['Port']))
|
||||
@ -231,7 +222,7 @@ class Houdini:
|
||||
self.logger.warning('The static key has been changed from the default, '
|
||||
'this may cause authentication issues!')
|
||||
|
||||
self.plugins.setup(houdini.plugins)
|
||||
await self.plugins.setup(houdini.plugins)
|
||||
|
||||
async with self.server:
|
||||
await self.server.serve_forever()
|
||||
@ -239,31 +230,3 @@ class Houdini:
|
||||
async def client_connected(self, reader, writer):
|
||||
client_object = self.client_class(self, reader, writer)
|
||||
await client_object.run()
|
||||
|
||||
def get_package_modules(self, package):
|
||||
package_modules = []
|
||||
|
||||
for importer, module_name, is_package in pkgutil.iter_modules(package.__path__):
|
||||
full_module_name = '{0}.{1}'.format(package.__name__, module_name)
|
||||
|
||||
if is_package:
|
||||
subpackage_object = importlib.import_module(full_module_name, package=package.__path__)
|
||||
subpackage_object_directory = dir(subpackage_object)
|
||||
|
||||
if houdini.plugins.IPlugin.__name__ in subpackage_object_directory:
|
||||
package_modules.append(subpackage_object)
|
||||
continue
|
||||
|
||||
sub_package_modules = self.get_package_modules(subpackage_object)
|
||||
|
||||
package_modules = package_modules + sub_package_modules
|
||||
else:
|
||||
package_modules.append(full_module_name)
|
||||
|
||||
return package_modules
|
||||
|
||||
def configure_observers(self, *observer_settings):
|
||||
for observer_path, observer_class in observer_settings:
|
||||
event_observer = Observer()
|
||||
event_observer.schedule(observer_class(self), observer_path, recursive=True)
|
||||
event_observer.start()
|
||||
|
@ -2,9 +2,8 @@ from abc import ABC
|
||||
from abc import abstractmethod
|
||||
|
||||
import inspect
|
||||
import asyncio
|
||||
|
||||
from houdini import _AbstractManager
|
||||
from houdini import _AbstractManager, get_package_modules
|
||||
|
||||
|
||||
class IPlugin(ABC):
|
||||
@ -37,11 +36,11 @@ class IPlugin(ABC):
|
||||
|
||||
|
||||
class PluginManager(_AbstractManager):
|
||||
def setup(self, module):
|
||||
for plugin_package in self.server.get_package_modules(module):
|
||||
self.load(plugin_package)
|
||||
async def setup(self, module):
|
||||
for plugin_package in get_package_modules(module):
|
||||
await self.load(plugin_package)
|
||||
|
||||
def load(self, module):
|
||||
async def load(self, module):
|
||||
plugin_class, plugin_type = inspect.getmembers(module, is_plugin).pop()
|
||||
|
||||
if self.server.server_config['Plugins'] is not True and \
|
||||
@ -51,19 +50,12 @@ class PluginManager(_AbstractManager):
|
||||
plugin_object = plugin_type(self.server)
|
||||
self[module.__name__] = plugin_object
|
||||
|
||||
self.server.commands.load(plugin_object)
|
||||
self.server.xt_listeners.load(plugin_object)
|
||||
self.server.xml_listeners.load(plugin_object)
|
||||
await self.server.commands.load(plugin_object)
|
||||
await self.server.xt_listeners.load(plugin_object)
|
||||
await self.server.xml_listeners.load(plugin_object)
|
||||
await self.server.dummy_event_listeners.load(plugin_object)
|
||||
|
||||
asyncio.run_coroutine_threadsafe(plugin_object.ready(), self.server.server.get_loop())
|
||||
|
||||
def remove(self, module):
|
||||
if module.__name__ in self:
|
||||
del self[module.__name__]
|
||||
|
||||
self.server.commands.remove(module)
|
||||
self.server.xt_listeners.remove(module)
|
||||
self.server.xml_listeners.remove(module)
|
||||
await plugin_object.ready()
|
||||
|
||||
|
||||
def is_plugin(plugin_class):
|
||||
|
Loading…
Reference in New Issue
Block a user