__all__ = ['MessageHandler']
import asyncio
import json
from struct import pack
from session import Session
class MetaHandler(type):
"""Metaclass for MessageHandler"""
def __init__(cls, name, bases, _dict):
try:
cls._msg_handlers[cls.__msgtype__] = cls
except AttributeError:
cls._msg_handlers = {}
class MessageHandler(metaclass=MetaHandler):
_session = Session()
def handle(self, msg, transport):
try:
_handler = self._msg_handlers[msg['type']]
except KeyError:
return ErrorHandler().handler(msg)
# Handling messages in a asyncio-Task
# Don’t directly create Task instances: use the async() function
# or the BaseEventLoop.create_task() method.
#return _handler().handle(msg, transport)
return asyncio.async(_handler().handle(msg, transport))
class ErrorHandler(MessageHandler):
"""
Unknown message type
"""
__msgtype__ = 'unknown'
def handle(self, msg):
print("Unknown message type: {}".format(msg))
class Register(MessageHandler):
"""
Registry handler for handling clients registry.
Message body should like this:
{'type': 'register', 'uid': 'unique-user-id'}
"""
__msgtype__ = 'register'
def __init__(self):
self.current_uid = None
self.transport = None
@asyncio.coroutine
def handle(self, msg, transport):
self.current_uid = msg['uid']
self.transport = transport
print("registe uid: {}".format(self.current_uid))
# Register user in global session
self._session.register(self.current_uid, self.transport)
class SendTextMsg(MessageHandler):
"""
Send message to others.
Message body should like this:
{'type': 'text', 'sender': 'Jack', 'receiver': 'Rose', 'content': 'I love you forever'}
"""
__msgtype__ = 'text' # Text message
@asyncio.coroutine
def handle(self, msg, _):
"""
Send message to receiver if receiver is online, and
save message to mongodb. Otherwise save
message to mongodb as offline message.
:param msg:
:return: None
"""
print("send data...{}".format(msg))
transport = self._session.get(msg['receiver'])
msg_pack = json.dumps(msg)
msg_len = len(msg_pack)
if transport:
# Pack message as length-prifixed and send to receiver.
transport.write(pack("!I%ds" % msg_len, msg_len, bytes(msg_pack, encoding='utf-8')))
class Unregister(MessageHandler):
"""
Unregister user from global session
Message body should like this:
{'type': 'unregister', 'uid': 'unique-user-id'}
"""
__msgtype__ = 'unregister'
@asyncio.coroutine
def handle(self, msg, _):
"""Unregister user record from global session"""
self._session.unregister(msg['uid'])