[27695] in Source-Commits
get_message commit: Implementation of gms functions necessary for get_message
daemon@ATHENA.MIT.EDU (Alexander Chernyakhovsky)
Mon Feb 10 20:50:03 2014
Date: Mon, 10 Feb 2014 20:49:55 -0500
From: Alexander Chernyakhovsky <achernya@MIT.EDU>
Message-Id: <201402110149.s1B1ntuo001951@drugstore.mit.edu>
To: source-commits@MIT.EDU
https://github.com/mit-athena/get_message/commit/f27a9bd0e5793df71f1ed3cb7ca252ac986366b7
commit f27a9bd0e5793df71f1ed3cb7ca252ac986366b7
Author: Alexander Chernyakhovsky <achernya@mit.edu>
Date: Fri May 17 23:48:44 2013 -0400
Implementation of gms functions necessary for get_message
gms.py is a python implementation spiritual successor to libgms. It
contains all the necessary functions to implement get_message
gms.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 86 insertions(+), 0 deletions(-)
diff --git a/gms.py b/gms.py
new file mode 100644
index 0000000..9ff8e05
--- /dev/null
+++ b/gms.py
@@ -0,0 +1,86 @@
+#!/usr/bin/python
+
+import hesiod
+import select
+import socket
+import os
+
+MESSAGE_VERS = 'GMS:0'
+MESSAGE_SIZE = 2048
+MESSAGE_CACHE = '/var/cache/libgms/messages'
+MESSAGE_TIMEOUT = 5
+GMS_USERFILE = '.message_times'
+GMS_PORT = 2106
+
+def get_server():
+ """Look up the globalmessage service in Hesiod, to get a server to connect to."""
+ try:
+ return hesiod.Lookup('globalmessage', 'sloc').results[0]
+ except:
+ raise Exception('Unable to lookup gms server')
+
+def parse(msg):
+ """Parse a gms message, returning a version, timestamp, text tuple
+ if successful, and an Exception otherwise."""
+ try:
+ header, text = msg.split('\n', 1)
+ version, timestamp = header.split(' ', 1)
+ if version != MESSAGE_VERS:
+ raise Exception('Incompatible version of GMS [%s] found' % (version,))
+ return (version, int(timestamp), text)
+ except:
+ raise Exception('Unable to parse the specified message')
+
+def get_message_times():
+ return os.path.expanduser(os.path.join('~', GMS_USERFILE))
+
+def has_seen(timestamp):
+ """Check if the user has seen this message, by reading
+ ~/.message_times. If this file cannot be read, assume no."""
+ try:
+ with open(get_message_times(), 'r') as mtimes:
+ _, lastread, _ = parse(mtimes.read())
+ return timestamp <= lastread
+ except:
+ return False
+
+def write_message_times(timestamp):
+ """Write ~/.message_times with the specified timestamp."""
+ try:
+ with open(get_message_times(), 'w') as mtimes:
+ mtimes.write('%s %d\n' % (MESSAGE_VERS, timestamp))
+ except:
+ # The write failed. All this means is the user will see the
+ # message again later.
+ pass
+
+def fetch_message():
+ """Connect to the globalmessage server, and read a message."""
+ server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ server.sendto('%s 0\n' % (MESSAGE_VERS,), (get_server(), GMS_PORT))
+ message = None
+ readable, _, _ = select.select([server], [], [], MESSAGE_TIMEOUT)
+ for i in readable:
+ message, _ = i.recvfrom(MESSAGE_SIZE)
+ return message
+
+def save_message_to_cache(msg_tuple):
+ """Save the specified message to the cache."""
+ with open(MESSAGE_CACHE, 'w') as f:
+ f.write('%s %d\n%s' % msg_tuple)
+
+def read_message_from_cache():
+ with open(MESSAGE_CACHE, 'r') as f:
+ return f.read()
+
+def get_message():
+ msg = fetch_message()
+ if msg is not None:
+ # Save the message to the cache, if it parses
+ msg_tuple = parse(msg)
+ save_message_to_cache(msg_tuple)
+ else:
+ # Huh, no message. Try to read it from cache
+ msg = read_message_from_cache()
+
+ return parse(msg)