-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsharknado.py
145 lines (112 loc) · 4.53 KB
/
sharknado.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import json
import motor
from bson import ObjectId
from collections import OrderedDict
from datetime import datetime, timedelta
from pymongo import ASCENDING, DESCENDING
from tornado import gen, escape
from tornado.escape import to_unicode
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.options import parse_command_line, define, options
from tornado.web import RequestHandler, Application, url
from six.moves.urllib.parse import urlparse
from six import iteritems
define("port", default='8000')
define("processes", default=1)
define("mongo_uri", default=None)
define("messages_expire", default=3600 * 24 * 30)
define("cors_origin", default="*")
def make_mongo_db():
uri = options.mongo_uri
try:
dbname = urlparse(uri).path[1:]
except:
dbname = 'sharknado'
connection = motor.MotorClient(uri)
db = connection[dbname]
messages_expire = int(options.messages_expire)
if messages_expire:
db.messages.ensure_index('created', expireAfterSeconds=messages_expire)
db.messages.ensure_index([('name', ASCENDING), ('created', DESCENDING)])
db.counters.ensure_index('name')
return db
class MongoEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, ObjectId):
return str(o)
if isinstance(o, datetime):
return o.isoformat()
return super(MongoEncoder, self).default(o)
def json_encode(value):
return json.dumps(value, cls=MongoEncoder)
escape.json_encode = json_encode
def make_evt_response(action, things, status='succeeded'):
return OrderedDict((('this', status),
('by', action),
('the', 'messages'),
('with', things)))
def parse_args(args):
parsed = {}
for name, args in iteritems(args):
args = [to_unicode(arg) for arg in args]
parsed[name] = args[0] if len(args) == 1 else args
return parsed
class CorsRequestHandler(RequestHandler):
def set_default_headers(self):
if self.request.headers.get('Origin') and options.cors_origin:
self.set_header('Access-Control-Allow-Origin', options.cors_origin)
class SendEvent(CorsRequestHandler):
@gen.coroutine
def get(self, name):
content = parse_args(self.request.arguments)
message = yield self.store_message(name, content)
self.write(make_evt_response('sending', message))
@gen.coroutine
def post(self, name):
try:
content = json.loads(to_unicode(self.request.body))
except Exception as e:
self.write(make_evt_response('sending', {'error': str(e)}, status='failed'))
else:
message = yield self.store_message(name, content)
self.write(make_evt_response('sending', message))
@gen.coroutine
def store_message(self, name, content):
db = self.settings['db']
message = {'thing': name, 'created': datetime.utcnow(), 'content': content}
message['_id'] = yield db.messages.insert(message)
yield db.counters.update({'thing': name}, {'$inc': {'count': 1}}, upsert=True)
raise gen.Return(message)
class GetMessages(CorsRequestHandler):
def initialize(self, limit=None):
self.limit = limit
@gen.coroutine
def get(self, name, days=30):
db = self.settings['db']
after = datetime.utcnow() - timedelta(days=int(days))
messages = yield db.messages.find({'thing': name, 'created': {'$gte': after}}) \
.sort('created', DESCENDING).to_list(self.limit)
self.write(make_evt_response('getting', messages))
class CountMessages(CorsRequestHandler):
@gen.coroutine
def get(self, name):
db = self.settings['db']
counter = yield db.counters.find_one({'thing': name}, projection={'_id': False})
self.write(make_evt_response('counting', counter))
def make_app():
return Application([url(r"/send/message/for/([^/]+)/?", SendEvent),
url(r"/get/latest/message/for/([^/]+)/?", GetMessages, dict(limit=1)),
url(r"/get/messages/for/([^/]+)/?", GetMessages),
url(r"/get/messages/for/([^/]+)/past/([0-9]+)-days?", GetMessages),
url(r"/count/messages/for/([^/]+)/?", CountMessages)])
def main():
parse_command_line()
app = make_app()
server = HTTPServer(app)
server.bind(int(options.port))
server.start(int(options.processes))
app.settings['db'] = make_mongo_db()
IOLoop.current().start()
if __name__ == '__main__':
main()