from typing import Dict import time, asyncio, settings from aiohttp import web from util.misc import Logger, gen_uuid from front.msn.msnp import MSNPCtrl def register(loop: asyncio.AbstractEventLoop, app: web.Application) -> None: gateway_sessions = {} # type: Dict[str, GatewaySession] app['gateway_sessions'] = gateway_sessions app.router.add_route('OPTIONS', '/gateway/gateway.dll', handle_http_gateway_options) app.router.add_post('/gateway/gateway.dll', handle_http_gateway) loop.create_task(_clean_gateway_sessions(gateway_sessions)) async def _clean_gateway_sessions(gateway_sessions: Dict[str, 'GatewaySession']) -> None: while True: await asyncio.sleep(10) now = time.time() closed = [] for session_id, gwsess in gateway_sessions.items(): if gwsess.time_last_connect + gwsess.timeout <= now: gwsess.controller.close() closed.append(session_id) for session_id in closed: del gateway_sessions[session_id] class GatewaySession: __slots__ = ('logger', 'hostname', 'controller', 'timeout', 'time_last_connect') logger: Logger hostname: str controller: MSNPCtrl timeout: float time_last_connect: float def __init__(self, logger: Logger, hostname: str, controller: MSNPCtrl, now: float) -> None: self.logger = logger self.hostname = hostname self.controller = controller self.timeout = 60 self.time_last_connect = now def _on_close(self) -> None: self.time_last_connect = 0 async def handle_http_gateway_options(req: web.Request) -> web.Response: return web.HTTPOk(headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Expose-Headers': 'X-MSN-Messenger', 'Access-Control-Max-Age': '86400', }) async def handle_http_gateway(req: web.Request) -> web.Response: query = req.query session_id = query.get('SessionID') action = query.get('Action') backend = req.app['backend'] gateway_sessions = req.app['gateway_sessions'] # type: Dict[str, GatewaySession] now = time.time() if not session_id: from front.msn.msnp_ns import MSNPCtrlNS from front.msn.msnp_sb import MSNPCtrlSB # Create new GatewaySession server_type = query.get('Server') server_ip = query.get('IP') or '' session_id = gen_uuid() logger = Logger('MSN {} via HTTP Gateway'.format(server_type), session_id) if server_type == 'NS': controller = MSNPCtrlNS(logger, 'gw', backend) # type: MSNPCtrl else: controller = MSNPCtrlSB(logger, 'gw', backend) tmp = GatewaySession(logger, server_ip, controller, now) controller.close_callback = tmp._on_close gateway_sessions[session_id] = tmp gwsess = gateway_sessions.get(session_id) if gwsess is None: raise web.HTTPBadRequest() assert req.transport is not None if gwsess.time_last_connect != now: gwsess.time_last_connect = now if action != 'poll': gwsess.logger.log_connect() gwsess.controller.data_received(await req.read(), transport = req.transport) gwsess.logger.log_disconnect() body = gwsess.controller.flush() return web.HTTPOk(headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Expose-Headers': 'X-MSN-Messenger', 'X-MSN-Messenger': 'SessionID={}; GW-IP={}'.format(session_id, settings.TARGET_IP), 'Content-Type': 'application/x-msn-messenger', }, body = body)