Files
azul/front/msn/http/gateway.py
T
Athena Funderburg 4b463a3432 init
2026-05-25 07:05:17 +00:00

103 lines
3.3 KiB
Python

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)