summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimeon Simeonov2015-04-14 19:22:40 +0200
committerSimeon Simeonov2015-04-14 19:22:40 +0200
commit36dda1cca9503fc00c15ed22c4c5969e80edc1f7 (patch)
tree046887857d1268c12e6022e04a7441bf5750ac36
parent56c09c10fd7dd1cb3a83a8d4b1bdcd98459e8175 (diff)
beinc_server_.py v.2.0 finished
-rwxr-xr-xbeinc_server.py364
-rwxr-xr-xbeinc_server_.py (renamed from beinc_server_xmlrpc.py)0
2 files changed, 0 insertions, 364 deletions
diff --git a/beinc_server.py b/beinc_server.py
deleted file mode 100755
index d079384..0000000
--- a/beinc_server.py
+++ /dev/null
@@ -1,364 +0,0 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4# Blackmore's Enhanced IRC-Notification Collection (BEINC) v1.1
5# Copyright (C) 2013-2015 Simeon Simeonov
6
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation, either version 3 of the License, or
10# (at your option) any later version.
11
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16
17# You should have received a copy of the GNU General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
21import argparse
22import errno
23import getpass
24import json
25import os
26import sys
27
28import cherrypy
29
30try:
31 import pynotify
32except ImportError as e:
33 pynotify = None
34
35try:
36 import pyosd
37 pyosd_positions = {'top': pyosd.POS_TOP,
38 'middle': pyosd.POS_MID,
39 'bottom': pyosd.POS_BOT}
40 pyosd_alignments = {'left': pyosd.ALIGN_LEFT,
41 'center': pyosd.ALIGN_CENTER,
42 'right': pyosd.ALIGN_RIGHT}
43except ImportError as e:
44 pyosd = None
45
46
47__author__ = 'Simeon Simeonov'
48__version__ = '1.1'
49__license__ = 'GPL3'
50
51
52BEINC_OSD_TYPE_NONE = 0
53BEINC_OSD_TYPE_PYNOTIFY = 1
54BEINC_OSD_TYPE_PYOSD = 2
55
56
57class BEINCInstance(object):
58 """
59 Represents a single server-instance
60 """
61
62 def __init__(self, instance_dict):
63 """
64 instance_dict: the config-dictionary node that represents this instance
65 """
66 self.__message_queue = list()
67 self.__osd_type = BEINC_OSD_TYPE_NONE
68 self.__osd_notification = None
69
70 self.__name = instance_dict.get('name')
71 self.__password = instance_dict.get('password', '')
72 self.__queue_size = int(instance_dict.get('queue_size', 3))
73 if instance_dict['osd_system'].lower() == 'pynotify':
74 self.__queue_size = 0 # disable queueing
75 if not pynotify:
76 sys.stderr.write(
77 'This server does not possess pynotify capability\n')
78 sys.stderr.write(
79 'Remove the instance {0}'.format(self.__name))
80 sys.stderr.write(
81 'or define it with "osd_system": "none" '
82 'or other available backend\n')
83 sys.exit(errno.EPERM)
84 try:
85 self.__osd_notification = pynotify.Notification(' ')
86 self.__osd_notification.set_timeout(
87 1000 * int(instance_dict.get('osd_timeout', 5)))
88 self.__osd_notification.set_property(
89 'app_name',
90 '{0} {1}'.format(sys.argv[0], __version__))
91 except Exception as e:
92 sys.stderr.write(
93 'Unable to set up a notification object for {0} ({1})\n')
94 sys.exit(errno.EPERM)
95 self.__osd_type = BEINC_OSD_TYPE_PYNOTIFY
96 elif instance_dict['osd_system'].lower() == 'pyosd':
97 self.__queue_size = 0 # disable queueing
98 if not pyosd:
99 sys.stderr.write(
100 'This server does not possess pyosd capability\n')
101 sys.stderr.write(
102 'Remove the instance {0}'.format(self.__name))
103 sys.stderr.write(
104 'or define it with "osd_system": "none" '
105 'or other available backend\n')
106 sys.exit(errno.EPERM)
107 try:
108 self.__osd_notification = pyosd.osd()
109 self.__osd_notification.set_timeout(
110 int(instance_dict.get('osd_timeout', 5)))
111 pyosd_font = instance_dict.get('pyosd_font')
112 if pyosd_font:
113 self.__osd_notification.set_font(pyosd_font)
114 self.__osd_notification.set_vertical_offset(
115 instance_dict.get('pyosd_vertical_offset', 120))
116 self.__osd_notification.set_horizontal_offset(
117 instance_dict.get('pyosd_horizontal_offset', 30))
118 align_str = instance_dict.get('pyosd_align', 'left')
119 self.__osd_notification.set_align(
120 pyosd_alignments.get(align_str, pyosd.ALIGN_LEFT))
121 position_str = instance_dict.get('pyosd_position', 'bottom')
122 self.__osd_notification.set_pos(
123 pyosd_positions.get(position_str, pyosd.POS_BOT))
124 self.__osd_notification.set_colour(
125 instance_dict.get('pyosd_color', 'blue'))
126 except Exception as e:
127 sys.stderr.write(
128 'Unable to set up a notification object for {0} ({1})\n')
129 sys.exit(errno.EPERM)
130 self.__osd_type = BEINC_OSD_TYPE_PYOSD
131
132 @property
133 def name(self):
134 """
135 name-property for the server instance (read-only)
136 """
137 return self.__name
138
139 @property
140 def queueable(self):
141 """
142 True if this instance has a queueing capability (read-only)
143 """
144 return bool(self.__queue_size)
145
146 def password_match(self, password):
147 """
148 Returns True if 'passowrd' matches the instance-password,
149 otherwise - False
150 """
151 return True if self.__password == password else False
152
153 def send_message(self, title, message):
154 """
155 Displays or enqueues the message,
156 depending on the instance's type in regard to the osd_system
157 """
158 if self.__osd_type == BEINC_OSD_TYPE_PYNOTIFY:
159 self.__send_pynotify_messaage(title, message)
160 elif self.__osd_type == BEINC_OSD_TYPE_PYOSD:
161 self.__send_pyosd_message(title, message)
162 else:
163 self.__send_message_to_queue(title, message)
164
165 def get_queue(self):
166 """
167 Reruens a json representation of the message queue
168 """
169 jstr = json.dumps(self.__message_queue)
170 self.__message_queue = list()
171 return jstr
172
173 def __send_pynotify_messaage(self, title, message):
174 """
175 Displays pynotify message
176 """
177 self.__osd_notification.set_properties(summary=title, body=message)
178 self.__osd_notification.show()
179
180 def __send_pyosd_message(self, title, message):
181 """
182 Displays pyosd message
183 """
184 self.__osd_notification.display(title, line=0)
185 self.__osd_notification.display(message, line=1)
186
187 def __send_message_to_queue(self, title, message):
188 """
189 Enqueues the message
190 """
191 if len(self.__message_queue) >= self.__queue_size:
192 self.__message_queue.pop(0)
193 self.__message_queue.append({'title': title, 'message': message})
194
195
196def beinc_instance_login(method):
197 """
198 decorator for checking login credentials
199 """
200
201 def wrapper(self, *args, **kwargs):
202 if not args:
203 raise cherrypy.HTTPError(status=404)
204 try:
205 instance = self.instances[args[0]]
206 except Exception as e:
207 raise cherrypy.HTTPError(status=401,
208 message='Wrong instance or password')
209 if not instance.password_match(kwargs.get('password')):
210 raise cherrypy.HTTPError(status=401,
211 message='Wrong instance or password')
212 return method(self, *args, **kwargs)
213
214 return wrapper
215
216
217class WebNotifyServer(object):
218 """
219 A class representing the entire server
220 """
221
222 def __init__(self, config):
223 """
224 """
225 self.__config = config
226 self.__instances = dict()
227 # initialize pynotify if the module exists and if needed
228 if pynotify:
229 for instance in self.__config['server']['instances']:
230 # check if we have at least one instance that uses pynotify
231 # before initializing it
232 if instance.get('osd_system', '').lower() == 'pynotify':
233 if not pynotify.init('BEINC Notify'):
234 sys.stderr.write('pynotify.init failed! Exiting...\n')
235 sys.exit(1)
236 break
237 try:
238 for instance in self.__config['server']['instances']:
239 self.__instances[instance['name']] = BEINCInstance(instance)
240 print('Instance "{0}" added'.format(instance['name']))
241 except Exception as e:
242 sys.stderr.write('Unable to create instance "{0}": {1}\n'.format(
243 instance['name'],
244 e))
245 sys.exit(1)
246
247 @property
248 def instances(self):
249 """
250 a property that returns the instance list (read-only)
251 """
252 return self.__instances
253
254 @cherrypy.expose
255 def index(self):
256 """
257 default dispatcher
258 """
259 return 'index'
260
261 @cherrypy.expose
262 def default(self, *args):
263 """
264 default dispatcher
265 """
266 return 'default'
267
268 @cherrypy.expose
269 @beinc_instance_login
270 def push(self, *args, **kwargs):
271 instance = self.__instances[args[0]]
272 ##print('**kwargs: {0}'.format(str(kwargs)))
273 title = kwargs.get('title', '')
274 message = kwargs.get('message', '')
275 try:
276 instance.send_message(title, message)
277 return 'OK'
278 except Exception as e:
279 sys.stderr.write(
280 'Unable to handle message in {0}: ({1})\n'.format(
281 instance.name,
282 e))
283 raise cherrypy.HTTPError(500, 'Unable to send message')
284
285 @cherrypy.expose
286 @beinc_instance_login
287 def pull(self, *args, **kwargs):
288 instance = self.__instances[args[0]]
289 if not instance.queueable:
290 raise cherrypy.HTTPError(
291 status=405,
292 message='BEINC instance "{0}" does not support queuing'.format(
293 instance.name))
294 return instance.get_queue()
295
296
297def main():
298
299 parser = argparse.ArgumentParser(
300 description='The following options are available')
301 parser.add_argument(
302 '-d',
303 action='store_true',
304 dest='daemonize',
305 default=False,
306 help='Run the BEINC-server in the background')
307 parser.add_argument(
308 '-H', '--hostname',
309 metavar='HOSTNAME',
310 type=str,
311 dest='hostname',
312 default='127.0.0.1',
313 help='BEINC server IP / hostname (default: 127.0.0.1)')
314 parser.add_argument(
315 '-p', '--port',
316 metavar='PORT',
317 type=int,
318 dest='port',
319 default=9998,
320 help='BEINC server port (default: 9998)')
321 parser.add_argument(
322 '-f', '--config-file',
323 metavar='FILE',
324 type=str,
325 default=os.path.expanduser('~/.beinc_server.json'),
326 dest='config_file',
327 help='BEINC config file (default: ~/.beinc_server.json)')
328 parser.add_argument(
329 '-v', '--version',
330 action='version',
331 version='%(prog)s {0}'.format(__version__),
332 help='Display program-version and exit')
333 args = parser.parse_args()
334 try:
335 with open(args.config_file, 'r') as fp:
336 config_dict = json.load(fp)
337 except Exception as e:
338 sys.stderr.write('Unable to parse {0}: {1}'.format(args.config_file,
339 e))
340 sys.exit(errno.EIO)
341 ssl_module = config_dict['server']['general']['ssl_module'].encode('utf-8')
342 ssl_certificate = config_dict['server']['general']['ssl_certificate']
343 ssl_private_key = config_dict['server']['general']['ssl_private_key']
344 cherrypy.config.update({
345 'server.socket_host': args.hostname,
346 'server.socket_port': args.port,
347 'server.ssl_module': ssl_module,
348 'server.ssl_certificate': ssl_certificate,
349 'server.ssl_private_key': ssl_private_key,
350 'tools.encode.on': True,
351 'tools.encode.encoding': 'utf-8',
352 'tools.log_tracebacks.on': False,
353 'request.show_tracebacks': False
354 })
355 try:
356 cherrypy.quickstart(WebNotifyServer(config_dict))
357 except Exception as e:
358 sys.stderr.write("WebServer error: {0}".format(e))
359 sys.exit(1)
360 sys.exit(0)
361
362
363if __name__ == "__main__":
364 main()
diff --git a/beinc_server_xmlrpc.py b/beinc_server_.py
index 36cbcd5..36cbcd5 100755
--- a/beinc_server_xmlrpc.py
+++ b/beinc_server_.py