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
|
"""
Notifications.py
by Jason Conti
February 15, 2010
Reads notifications in the notify-osd.log format specified at:
https://wiki.ubuntu.com/NotifyOSD#Logging notifications
"""
import re
import time
from LogWatcher import LogWatcher
message_header = re.compile("""
^
\[ # [timestamp, process-name, status?]
(
\d{4}-\d{2}-\d{2} # date YYYY-mm-dd
[Tt]
\d{2}:\d{2}:\d{2} # time HH-MM-SS
([Zz]|[+-]\d{2}:\d{2}) # time offset
)
,
([^,\]]+) # process name
(,([^\]]+))? # optional status
\]
(.*) # title
$
""", re.VERBOSE)
class Message(object):
"""A notification message"""
def __init__(self, timestamp, process_name, status, title):
self.timestamp = timestamp
self.process_name = process_name
self.status = status
self.title = title
self.body = ""
def append_body(self, body):
"""Appends a body line to the message."""
self.body += body
def formatted_time(self):
"""Returned the time in a different format."""
t = time.strptime(self.timestamp.upper(), "%Y-%m-%dT%H:%M:%S-00:00")
return time.strftime("%B %d, %Y at %I:%M:%S %p", t)
class Notifications(object):
"""Reads notifications from a log file and sends them to the listeners."""
def __init__(self, path):
self._path = path
self._listeners = set()
def add_listener(self, f):
"""A listener is a function of a single argument, the messages
received."""
self._listeners.add(f)
def remove_listener(self, f):
"""Removes f from the set of listeners."""
self._listeners.remove(f)
def start(self):
"""Reads the previous messages, sends them to the listeners and starts
watching for more messages."""
# Get the previous messages
f = open(self._path, "r")
messages = f.read()
f.close()
self._message_received(None, messages)
self._watcher = LogWatcher(self._path)
self._watcher.connect("changed", self._message_received)
self._watcher.start()
def stop(self):
"""Stops watching for more messages."""
self._watcher.stop()
def _notify_listeners(self, messages):
"""Notifies the listeners of new messages."""
for f in self._listeners:
f(messages)
def _message_received(self, watcher, messages):
"""Callback that parses messages and adds them to the queue."""
queue = self._parse_messages(messages)
if len(queue) > 0:
self._notify_listeners(queue)
def _parse_messages(self, messages):
"""Returns a list of parsed messages."""
lines = messages.splitlines()
queue = []
message = None
for line in lines:
# Try to parse a new message, discard the line if the header
# doesn't match
if message == None:
m = message_header.match(line)
if m != None:
header = m.groups()
timestamp = header[0].strip()
process_name = header[2].strip()
status = header[4]
# Status may not exist
if status == None:
status = ""
else:
status = status.strip()
title = header[5].strip()
message = Message(timestamp, process_name, status, title)
# Messages are delimited by a blank line
else:
if line.strip() == "":
queue.append(message)
message = None
else:
message.append_body(line)
# Don't forget the last message (should probably never happen)
if message != None:
queue.append(message)
return queue
|