class EventDispatcher(object): def __init__(self, mysql, cassandra, user_server): self.user_server = user_server self.mysql = mysql self.cassandra = cassandra self.mailer = Mailer(mysql) logging.info('Initializing event dispatcher') def __call__(self, frame): action = frame['action'] data = frame['data'] if action == 'tap.new': self.on_new_message(action, data) elif action == 'tap.delete': self.on_delete_message(action, data) elif action == 'response.new': self.on_new_response(action, data) elif action == 'group.follow': gid, uid, status = map(int, [data['group_id'], data['user_id'], data['status']]) self.on_group_follow(gid, uid, status) elif action == 'convo.follow': mid, uid, status = map(int, [data['message_id'], data['user_id'], data['status']]) self.on_convo_follow(mid, uid, status) elif action == 'response.typing': self.user_server.send_to(action, data, convo = int(data['cid'])) elif action == 'user.follow': uid, fid, status = map(int, [data['who'], data['whom'], data['status']]) unrecieved = self.user_server.send_to(action, data, users = set([fid])) if unrecieved or not status: self.on_user_follow(uid, fid, status) elif action == 'event.delete': self.on_delete_event(action, data) elif action == 'event.delete.all': self.on_delete_event(action, data, all = True) elif action == 'mention.new': self.on_mention_new(action, data) else: logging.warning('Unknow event! %s: %s' (action, data)) def on_new_message(self, action, message): "New message handler" sender, group, private, reciever = intcast(message['sender_id'], message['group_id'], message['private'], message['reciever_id']) if reciever is not None: recievers = {'users': set([sender, reciever])} else: recievers = {'users': self.group_users(group)} if not private: recievers['group'] = group unrecieved = self.user_server.send_to(action, message, **recievers) unrecieved = unrecieved if not private else recievers if unrecieved: self.on_unrecieved_message(int(message['id']), unrecieved, data = message) def group_users(self, group): users = self.cassandra.get('group_members', group) return set(users) if users else set() def on_new_response(self, action, response): rid, mid, timestamp = map(int, [response['id'], response['message_id'], response['timestamp']]) self.touch_message(mid, timestamp) unrecieved = self.user_server.send_to(action, response, users = self.convo_followers(mid), convo = mid) if unrecieved: self.on_unrecieved_response(mid, rid, unrecieved, data = response) def touch_message(self, mid, timestamp): "Update message timestamp to reply timestamp" sql = "UPDATE message SET modification_time = FROM_UNIXTIME(%i) WHERE id = %i" % (timestamp, mid) self.mysql.cursor().execute(sql) self.mysql.commit() def convo_followers(self, convo): return set(self.cassandra.get('convo_followers', convo)) def on_group_follow(self, group, user, status): if status: self.cassandra.insert('group_members', group, {user: user}) self.cassandra.insert('inverted_members', user, {group: group}) else: self.cassandra.remove('group_members', group, columns=[user]) self.cassandra.remove('inverted_members', user, columns=[group]) if status: unrecieved = self.user_server.send_to('member.new', {'group_id': group, 'user_id': user, 'status': status}, users = self.group_users(group)) if unrecieved: self.mailer.queue(unrecieved, 'new_member', user_id = user, group_id = group) def on_convo_follow(self, message, user, status): if status: self.cassandra.insert('convo_followers', message, {user: user}) else: self.cassandra.remove('convo_followers', message, columns=[user]) def on_unrecieved_message(self, message, users, data = None): "Adds message to events queue for each user" joined = (', 0, %i),(' % message).join(map(str, users)) sql = 'INSERT IGNORE INTO events (user_id, type, related_id) VALUES (%s, 0, %i)' % (joined, message) self.mysql.cursor().execute(sql) self.mysql.commit() type = 'new_personal' if data['reciever_id'] is not None else 'new_message' self.mailer.queue(users, type, message_id = data['id'], group_id = data['group_id'], user_id = data['sender_id']) def on_unrecieved_response(self, message, reply, users, data = None): "Insert new reply event or update every event to +1" joined = (', 1, %i, %i, 1),(' % (message, reply)).join(map(str, users)) sql = 'INSERT INTO events (user_id, type, related_id, addit_id, new_replies) VALUES (%s, 1, %i, %i, 1)' % (joined, message, reply) + \ 'ON DUPLICATE KEY UPDATE new_replies = new_replies + 1, addit_id = VALUES(addit_id)' self.mysql.cursor().execute(sql) self.mysql.commit() self.mailer.queue(users, 'new_reply', message_id = data['message_id'], user_id = data['user_id'], reply_id = data['id']) def on_user_follow(self, user, friend, status): "Updates events on user following/unfollowing" sql = '' if status: sql = 'INSERT IGNORE INTO events (user_id, type, related_id) VALUES (%i, 2, %i)' % (friend, user) else: sql = 'DELETE FROM events WHERE user_id = %i AND type = 2 AND related_id = %i' % (friend, user) self.mysql.cursor().execute(sql) self.mysql.commit() if status: self.mailer.queue(friend, 'new_follower', user_id = user) def on_delete_message(self, action, message): "Delete message from events queue and cassandra tables" cid = int(message['id']) sql = 'DELETE FROM events WHERE related_id = %i' % cid self.mysql.cursor().execute(sql) self.mysql.commit() self.cassandra.remove('convo_followers', cid) self.user_server.send_to(action, message, convo = cid) def on_delete_event(self, action, event, all = False): "Delete event by type" uid, type, id = intcast(event['user_id'], event['type'], event['event_id']) if uid is None: return where = 'WHERE user_id = %i' % uid if not all: where += ' AND related_id = %i' % id where += ' AND type IN (0, 1)' if type in (0, 1) else (' AND type = %i' % type) sql = 'DELETE FROM events %s' % where self.mysql.cursor().execute(sql) self.mysql.commit() self.user_server.send_to(action, event, users = set([uid])) def on_mention_new(self, action, data): "Add 'mention' events to queue and send emails" uid, mid, sid = intcast(data['uid'], data['mid'], data['sid']) if uid == sid: return self.user_server.send_to(action, data, users = set([sid])) self.mailer.queue(uid, 'mention', message_id = mid, user_id = sid)
def __init__(self, mysql, cassandra, user_server): self.user_server = user_server self.mysql = mysql self.cassandra = cassandra self.mailer = Mailer(mysql) logging.info('Initializing event dispatcher')
import asyncio import websockets import threading from Mail import Mailer lock = threading.RLock() mailer = Mailer() def write_in_file(message): base_file = open('logs.txt', 'a') base_file.write(message + "\n") async def mark(websocket, path): async for message in websocket: with lock: write_in_file(message) mailer.send_mail(message) def main(): start_server = websockets.serve(mark, "localhost", 8080) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever() if __name__ == "__main__": main()