houdini/Houdini/HoudiniFactory.py
2019-03-01 19:41:40 +00:00

182 lines
6.7 KiB
Python

import asyncio
import os
import sys
import pkgutil
import importlib
from Houdini.Spheniscidae import Spheniscidae
from Houdini.Penguin import Penguin
from Houdini import PenguinStringCompiler
import config
from aiologger import Logger
from aiologger.handlers.files import AsyncTimedRotatingFileHandler, RolloverInterval, AsyncFileHandler
from aiologger.handlers.streams import AsyncStreamHandler
import logging
from logging.handlers import RotatingFileHandler
import aioredis
from aiocache import SimpleMemoryCache
from watchdog.observers import Observer
from gino import Gino
try:
import uvloop
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
except ImportError:
uvloop = None
import Houdini.Handlers
from Houdini.Handlers import listeners_from_module
from Houdini.Events.HandlerFileEvent import HandlerFileEventHandler
class HoudiniFactory:
def __init__(self, **kwargs):
self.server = None
self.redis = None
self.config = None
self.cache = None
self.db = Gino()
self.peers_by_ip = {}
self.server_name = kwargs['server']
self.server_config = None
self.logger = None
self.client_class = Spheniscidae
self.penguin_string_compiler = None
self.penguins_by_id = {}
self.penguins_by_username = {}
self.xt_listeners, self.xml_listeners = {}, {}
async def start(self):
self.config = config
self.server_config = self.config.servers[self.server_name]
self.server = await asyncio.start_server(
self.client_connected, self.server_config['Address'],
self.server_config['Port']
)
await self.db.set_bind('postgresql://{}:{}@{}/{}'.format(
self.config.database['Username'], self.config.database['Password'],
self.config.database['Address'],
self.config.database['Name']))
general_log_directory = os.path.dirname(self.server_config["Logging"]["General"])
errors_log_directory = os.path.dirname(self.server_config["Logging"]["Errors"])
if not os.path.exists(general_log_directory):
os.mkdir(general_log_directory)
if not os.path.exists(errors_log_directory):
os.mkdir(errors_log_directory)
if sys.platform != 'win32':
self.logger = Logger.with_default_handlers(name='Houdini')
universal_handler = AsyncTimedRotatingFileHandler(
filename=self.server_config['Logging']['General'],
backup_count=3,
when=RolloverInterval.HOURS
)
error_handler = AsyncFileHandler(filename=self.server_config['Logging']['General'])
console_handler = AsyncStreamHandler(stream=sys.stdout)
else:
self.logger = logging.getLogger('Houdini')
universal_handler = RotatingFileHandler(self.server_config['Logging']['General'],
maxBytes=2097152, backupCount=3, encoding='utf-8')
error_handler = logging.FileHandler(self.server_config['Logging']['Errors'])
console_handler = logging.StreamHandler(stream=sys.stdout)
log_formatter = logging.Formatter('%(asctime)s [%(levelname)-5.5s] %(message)s')
error_handler.setLevel(logging.ERROR)
universal_handler.setFormatter(log_formatter)
console_handler.setFormatter(log_formatter)
self.logger.addHandler(universal_handler)
self.logger.addHandler(console_handler)
level = logging.getLevelName(self.server_config['Logging']['Level'])
self.logger.setLevel(level)
self.logger.info('Houdini module instantiated')
if self.server_config['World']:
self.redis = await aioredis.create_redis_pool('redis://{}:{}'.format(
self.config.redis['Address'], self.redis['Port']),
minsize=5, maxsize=10)
await self.redis.delete('{}.players'.format(self.server_name))
await self.redis.delete('{}.population'.format(self.server_name))
self.cache = SimpleMemoryCache(namespace='houdini', ttl=self.server_config['CacheExpiry'])
self.client_class = Penguin
self.penguin_string_compiler = PenguinStringCompiler()
self.load_handler_modules(exclude_load="Houdini.Handlers.Login.Login")
self.logger.info('World server started')
else:
self.load_handler_modules("Houdini.Handlers.Login.Login")
self.logger.info('Login server started')
handlers_path = './Houdini{}Handlers'.format(os.path.sep)
plugins_path = './Houdini{}Plugins'.format(os.path.sep)
self.configure_obvservers([handlers_path, HandlerFileEventHandler])
self.logger.info('Listening on {}:{}'.format(self.server_config['Address'], self.server_config['Port']))
async with self.server:
await self.server.serve_forever()
async def client_connected(self, reader, writer):
client_object = self.client_class(self, reader, writer)
await client_object.run()
def load_handler_modules(self, strict_load=None, exclude_load=None):
for handler_module in self.get_package_modules(Houdini.Handlers):
if not (strict_load and handler_module not in strict_load or exclude_load and handler_module in exclude_load):
if handler_module not in sys.modules.keys():
module = importlib.import_module(handler_module)
listeners_from_module(self.xt_listeners, self.xml_listeners, module)
self.logger.info("Handler modules loaded")
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 "Plugin" in subpackage_object_directory:
package_modules.append((subpackage_object, module_name))
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_obvservers(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()