6
\$\begingroup\$

I have Tornado chat with export to Redis. Other scripts will export messages from Redis to MongoDB in the time. It works, but how is it written?

def tornadoredis_client():
 client = tornadoredis.Client(*configuration.REDIS_CONFIG)
 client.connect()
 return client
class PlansqTornadoChat(SockJSConnection):
 users = dict()
 timezones = dict()
 def on_open(self, info):
 self.authenticated = False
 self.timezone = None
 self.client = tornadoredis_client()
 @tornado.gen.engine
 def on_message(self, msg):
 data = proto.json_decode(msg)
 if data['type'] == 'auth':
 if bool(data.get('sid', None)):
 try:
 int(data['sid']) # check that sid is number, not word
 self.user_sid = data['sid']
 self.users[self.user_sid] = self
 self.user_timezone = yield tornado.gen.Task(self.client.hget, 'timezones', self.user_sid)
 self.timezones[self.user_sid] = self.user_timezone
 self.authenticated = True
 self.send(proto.json_encode({"body": "You was authorized", 'type': 'alert'}))
 except Exception, e:
 logging.info("bad user's sid: " + str(data['sid']))
 else:
 self.send(proto.json_encode({"body": "You did not authorize", 'type': 'alert'}))
 self.close()
 elif data['type'] == 'message':
 if all([x in data for x in ['type', 'recipient', 'body', 'sender']]) \
 and data['sender'] == self.user_sid:
 recipient = data['recipient']
 try:
 int(recipient) # check that sid is number, not word
 except Exception, e:
 logging.info('sid of recipient is not number')
 return
 self.thread = "_".join([str(x) for x in sorted([int(self.user_sid), int(recipient)])])
 # Save to Redis
 data_to_send = {
 'thread_id': self.thread,
 'sender': self.user_sid,
 'recipient': recipient,
 'body': data['body'],
 'datetime': (datetime.now() - datetime(1970, 1, 1)).total_seconds()
 }
 yield tornado.gen.Task(self.client.sadd, "thread:" + self.thread, proto.json_encode(data_to_send))
 yield tornado.gen.Task(self.client.sadd, 'new_threads:all', "thread:" + self.thread)
 # Send to Socket
 data_to_send['type'] = 'message'
 # if user is online
 if recipient in self.users:
 data_to_send['datetime'] = utc_to_localtime(data_to_send['datetime'], self.timezones[recipient])
 self.users[recipient].send(proto.json_encode(data_to_send))
 data_to_send['datetime'] = utc_to_localtime(data_to_send['datetime'], self.user_timezone)
 self.send(proto.json_encode(data_to_send))
 else:
 logging.info('Bad request: ' + str(data))
 else:
 logging.info('Bad request: ' + str(data))
 def on_close(self):
 del self.users[self.user_sid]
 del self.timezones[self.user_sid]
 self.client.disconnect()

My configuration in configuration of main application (Flask + MongoDB). There only Redis configuration (host and port).

The rest of the code:

if __name__ == '__main__':
 logging.getLogger().setLevel(logging.DEBUG)
 logging.getLogger().setLevel(logging.INFO)
 EchoRouter = SockJSRouter(PlansqTornadoChat, '/socket')
 app = web.Application(EchoRouter.urls)
 app.listen(configuration.TORNADO_PORT)
 ioloop.IOLoop.instance().start()
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jan 23, 2016 at 22:59
\$\endgroup\$
0

1 Answer 1

1
\$\begingroup\$

I have some notes on Pythonic style.

People usually instantiate an empty dict with {}, instead of actually calling dict(). Usually, the only reason you need to call dict is if you're passing some variables to create your dictionary.

There's no need to explicitly cast a value to a boolean, Python can implicitly run a boolean test on any type. So you can just do this:

if data.get('sid', None):

I don't know exactly what type data is, but assuming it's a dictionary, get will default to returning None, so there's no need to make it an explicit parameter of get.

You have a long block inside a try followed by a blanket except Exception, e. There's a few problems here. First, your try block should be as narrow as possible. You can use return to prematurely end functions from the except block if you need to. Speaking of that except block, you should ensure that it's only catching errors you specifically expect. In this case, presumably you want to catch ValueErrors from a bad data['sid'] string, as well as catching KeyError for user_sids that don't show up in the users dictionary. Blanket exceptions will just mask errors you're not expecting, instead of handling the ones you know can occur in normal execution.

Lastly, don't use except Exception, e syntax, it will lead to trouble and was removed in Python 3. It causes ambiguities when you want to catch multiple exception types, like except KeyError, ValueError, e:. How is Python supposed to interpret that? This is why you should use except (KeyError, ValueError) as e: or except (KeyError, ValueError):, as you don't have to store the result in a variable if you're not using it.

answered Jan 25, 2016 at 10:55
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.