diff options
| author | Simeon Simeonov | 2013-06-12 21:37:12 +0200 |
|---|---|---|
| committer | Simeon Simeonov | 2013-06-12 21:37:12 +0200 |
| commit | 1621a27167041e191289c0eac9a5e1fda84b752a (patch) | |
| tree | 95ef3203cd4e46fbc8f1c52eb15443bd6bf1a1db | |
| parent | 751ab339ba5a38cbcd3a17620ab78e973fd5664f (diff) | |
beinc_server nearly done
| -rw-r--r-- | beinc_server.json | 1 | ||||
| -rwxr-xr-x | beinc_server.py | 205 | ||||
| -rwxr-xr-x | bins_server.py | 140 |
3 files changed, 168 insertions, 178 deletions
diff --git a/beinc_server.json b/beinc_server.json index 0604d36..1743239 100644 --- a/beinc_server.json +++ b/beinc_server.json | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | "name": "test", | 11 | "name": "test", |
| 12 | "password": "changeme", | 12 | "password": "changeme", |
| 13 | "osd_system": "none", | 13 | "osd_system": "none", |
| 14 | "osd_timeout": 5000, | ||
| 14 | "queue_size": 4 | 15 | "queue_size": 4 |
| 15 | } | 16 | } |
| 16 | ] | 17 | ] |
diff --git a/beinc_server.py b/beinc_server.py index a39dd05..cad8d61 100755 --- a/beinc_server.py +++ b/beinc_server.py | |||
| @@ -15,6 +15,154 @@ __version__ = '1.0-beta' | |||
| 15 | __license__ = "GPL3" | 15 | __license__ = "GPL3" |
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | BEINC_OSD_TYPE_NONE = 0 | ||
| 19 | BEINC_OSD_TYPE_PYNOTIFY = 1 | ||
| 20 | |||
| 21 | |||
| 22 | |||
| 23 | class BEINCInstance(object): | ||
| 24 | """ | ||
| 25 | """ | ||
| 26 | |||
| 27 | def __init__(self, instance_dict): | ||
| 28 | """ | ||
| 29 | """ | ||
| 30 | self.__instance_dict = instance_dict | ||
| 31 | try: | ||
| 32 | self.__name = instance_dict['name'] | ||
| 33 | self.__osd_type = BEINC_OSD_TYPE_NONE | ||
| 34 | self.__password = instance_dict['password'] | ||
| 35 | self.__queue_size = int(instance_dict['queue_size']) | ||
| 36 | self.__message_queue = list() | ||
| 37 | self.__osd_notification = None | ||
| 38 | |||
| 39 | except Exception as e: | ||
| 40 | sys.stderr.write( | ||
| 41 | 'Instance processing error {0}:\n{1}\n'.format(self.__name, | ||
| 42 | e)) | ||
| 43 | sys.exit(1) | ||
| 44 | |||
| 45 | |||
| 46 | if instance_dict['osd_system'].lower() == 'pynotify': | ||
| 47 | if not pynotify: | ||
| 48 | sys.stderr.write( | ||
| 49 | 'This server does not possess pynotify capability\n') | ||
| 50 | sys.stderr.write( | ||
| 51 | "Remove the instance {0} or define it with 'osd_system': 'none'") | ||
| 52 | sys.exit(1) | ||
| 53 | |||
| 54 | try: | ||
| 55 | self.__osd_notification = pynotify.Notification(' ') | ||
| 56 | self.__osd_notification.set_timeout( | ||
| 57 | instance_dict['osd_timeout']) | ||
| 58 | self.__osd_notification.set_property( | ||
| 59 | 'app_name', | ||
| 60 | '{0} {1}'.format(sys.argv[0], __version__)) | ||
| 61 | except Exception as e: | ||
| 62 | sys.stderr.write( | ||
| 63 | 'Unable to set up a notification object for {0} ({1})\n') | ||
| 64 | sys.exit(1) | ||
| 65 | |||
| 66 | self.__osd_type = BEINC_OSD_TYPE_PYNOTIFY | ||
| 67 | |||
| 68 | |||
| 69 | @property | ||
| 70 | def name(self): | ||
| 71 | """ | ||
| 72 | name-property for the server instance | ||
| 73 | """ | ||
| 74 | return self.__name | ||
| 75 | |||
| 76 | |||
| 77 | @property | ||
| 78 | def queueable(self): | ||
| 79 | """ | ||
| 80 | name-property for the server instance | ||
| 81 | """ | ||
| 82 | return bool(self.__queue_size) | ||
| 83 | |||
| 84 | |||
| 85 | def password_match(self, password): | ||
| 86 | """ | ||
| 87 | Returns True if 'passowrd' matches the instance-password, | ||
| 88 | otherwise - False | ||
| 89 | """ | ||
| 90 | if self.__password == password: | ||
| 91 | return True | ||
| 92 | |||
| 93 | return False | ||
| 94 | |||
| 95 | |||
| 96 | def send_message(self, title, message): | ||
| 97 | """ | ||
| 98 | Displays or enqueues the message, | ||
| 99 | depending on the instance's type in regard to the osd_system | ||
| 100 | """ | ||
| 101 | if self.__osd_type == BEINC_OSD_TYPE_PYNOTIFY: | ||
| 102 | self.__send_pynotify_messaage(title, message) | ||
| 103 | else: | ||
| 104 | self.____send_message_to_queue(title, message) | ||
| 105 | |||
| 106 | |||
| 107 | def get_queue(self): | ||
| 108 | """ | ||
| 109 | Reruens a json representation of the message queue | ||
| 110 | """ | ||
| 111 | jstr = json.dumps(self.__message_queue) | ||
| 112 | self.__message_queue = list() | ||
| 113 | return jstr | ||
| 114 | |||
| 115 | |||
| 116 | def __send_pynotify_messaage(self, title, message): | ||
| 117 | """ | ||
| 118 | Displays pynotify message | ||
| 119 | """ | ||
| 120 | |||
| 121 | self.__osd_notification.set_properties(summary=title, body=message) | ||
| 122 | self.__osd_notification.show() | ||
| 123 | |||
| 124 | |||
| 125 | def __send_message_to_queue(self, title, message): | ||
| 126 | """ | ||
| 127 | Enqueues the message | ||
| 128 | """ | ||
| 129 | |||
| 130 | if len(self.__message_queue) >= self.__queue_size: | ||
| 131 | self.__message_queue.pop(0) | ||
| 132 | |||
| 133 | self.__message_queue.append({'title': title, 'message': message}) | ||
| 134 | |||
| 135 | |||
| 136 | |||
| 137 | def beinc_instance_login(method): | ||
| 138 | """ | ||
| 139 | decorator for checking login credentials | ||
| 140 | """ | ||
| 141 | |||
| 142 | def tmp_func(self, *args, **kwargs): | ||
| 143 | |||
| 144 | if not args: | ||
| 145 | raise cherrypy.HTTPError(400) | ||
| 146 | |||
| 147 | print('args: {0}'.format(args)) | ||
| 148 | print('kwargs: {0}'.format(kwargs)) | ||
| 149 | print(cherrypy.request.config) | ||
| 150 | |||
| 151 | try: | ||
| 152 | instance = self.__instances(args[0]) | ||
| 153 | except Exception as e: | ||
| 154 | raise cherrypy.HTTPError('403 Forbidden', | ||
| 155 | 'Wrong instance or password') | ||
| 156 | |||
| 157 | if not instance.password_match(kwargs.get('password')): | ||
| 158 | raise cherrypy.HTTPError('403 Forbidden', | ||
| 159 | 'Wrong instance or password') | ||
| 160 | |||
| 161 | method(self, *args, **kwargs) | ||
| 162 | |||
| 163 | return tmp_func | ||
| 164 | |||
| 165 | |||
| 18 | 166 | ||
| 19 | class WebNotifyServer(object): | 167 | class WebNotifyServer(object): |
| 20 | 168 | ||
| @@ -23,15 +171,13 @@ class WebNotifyServer(object): | |||
| 23 | """ | 171 | """ |
| 24 | self.__config = config | 172 | self.__config = config |
| 25 | self.__instances = dict() | 173 | self.__instances = dict() |
| 26 | self.__queues = dict() | ||
| 27 | 174 | ||
| 28 | try: | 175 | try: |
| 29 | for instance in self.__config['server']['instances']: | 176 | for instance in self.__config['server']['instances']: |
| 30 | self.__queues[instance['name']] = list() | 177 | self.__instances[instance['name']] = BEINCInstance(instance) |
| 31 | self.__instances[instance['name']] = instance | ||
| 32 | 178 | ||
| 33 | except Exception as e: | 179 | except Exception as e: |
| 34 | sys.stderr.write('Unable to initialize queues: {0}'.format(e)) | 180 | sys.stderr.write('Unable to initialize queues: {0}\n'.format(e)) |
| 35 | sys.exit(1) | 181 | sys.exit(1) |
| 36 | 182 | ||
| 37 | 183 | ||
| @@ -52,47 +198,20 @@ class WebNotifyServer(object): | |||
| 52 | 198 | ||
| 53 | 199 | ||
| 54 | @cherrypy.expose | 200 | @cherrypy.expose |
| 201 | @beinc_instance_login | ||
| 55 | def push(self, *args, **kwargs): | 202 | def push(self, *args, **kwargs): |
| 56 | 203 | ||
| 57 | if not args: | 204 | instance = self.__instances(args[0]) |
| 58 | raise cherrypy.HTTPError(400) | ||
| 59 | |||
| 60 | print('args: {0}'.format(args)) | ||
| 61 | print('kwargs: {0}'.format(kwargs)) | ||
| 62 | |||
| 63 | instance = self.__get_instance(args[0]) | ||
| 64 | |||
| 65 | if not kwargs.get('password') == instance['password']: | ||
| 66 | raise cherrypy.HTTPError('403 Forbidden', | ||
| 67 | 'Wrong instance or password') | ||
| 68 | |||
| 69 | return 'OK' | 205 | return 'OK' |
| 70 | 206 | ||
| 71 | 207 | ||
| 72 | def __get_instance(self, name): | 208 | @cherrypy.expose |
| 73 | """ | 209 | @beinc_instance_login |
| 74 | returns a matching 'instance' dictionary | 210 | def pull(self, *args, **kwargs): |
| 75 | |||
| 76 | cherrypy.HTTPError - "403 Forbidden" is raised if no | ||
| 77 | instance matches 'name' | ||
| 78 | """ | ||
| 79 | |||
| 80 | try: | ||
| 81 | for instance in self.__config['server']['instances']: | ||
| 82 | if name == instance['name']: | ||
| 83 | return instance | ||
| 84 | |||
| 85 | except Exception as e: | ||
| 86 | raise cherrypy.HTTPError('403 Forbidden', | ||
| 87 | 'Wrong instance or password: {0}'.format(e)) | ||
| 88 | |||
| 89 | raise cherrypy.HTTPError("403 Forbidden", "Wrong instance or password") | ||
| 90 | 211 | ||
| 212 | instance = self.__instances(args[0]) | ||
| 213 | return 'OK' | ||
| 91 | 214 | ||
| 92 | # mappings = [ | ||
| 93 | # (r'^/push/', push), | ||
| 94 | # (r'^.*$', default), | ||
| 95 | # ] | ||
| 96 | 215 | ||
| 97 | 216 | ||
| 98 | def main(): | 217 | def main(): |
| @@ -152,6 +271,16 @@ def main(): | |||
| 152 | }) | 271 | }) |
| 153 | 272 | ||
| 154 | try: | 273 | try: |
| 274 | import pynotify | ||
| 275 | if not pynotify.init("BEINC Notify"): | ||
| 276 | sys.stderr.write('pynotify.init failed! Exiting...\n') | ||
| 277 | sys.exit(1) | ||
| 278 | except Exception as e: | ||
| 279 | sys.stderr.write( | ||
| 280 | 'Notice: pynotify support unavailable ({0})\n'.format(e)) | ||
| 281 | pynotify = False | ||
| 282 | |||
| 283 | try: | ||
| 155 | cherrypy.quickstart(WebNotifyServer(config_dict)) | 284 | cherrypy.quickstart(WebNotifyServer(config_dict)) |
| 156 | 285 | ||
| 157 | except Exception as e: | 286 | except Exception as e: |
diff --git a/bins_server.py b/bins_server.py deleted file mode 100755 index 68ccb74..0000000 --- a/bins_server.py +++ /dev/null | |||
| @@ -1,140 +0,0 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | |||
| 4 | import argparse | ||
| 5 | import getpass | ||
| 6 | import json | ||
| 7 | import os | ||
| 8 | import sys | ||
| 9 | |||
| 10 | import cherrypy | ||
| 11 | |||
| 12 | import settings | ||
| 13 | |||
| 14 | |||
| 15 | class CustomSocketServer(SocketServer.TCPServer): | ||
| 16 | |||
| 17 | def __init__(self, server_address, RequestHandlerClass, queue): | ||
| 18 | SocketServer.TCPServer.__init__(self, | ||
| 19 | server_address, | ||
| 20 | RequestHandlerClass) | ||
| 21 | self.queue = queue | ||
| 22 | |||
| 23 | |||
| 24 | class MyTCPHandler(SocketServer.StreamRequestHandler): | ||
| 25 | """ | ||
| 26 | The RequestHandler class for our server. | ||
| 27 | |||
| 28 | It is instantiated once per connection to the server, and must | ||
| 29 | override the handle() method to implement communication to the | ||
| 30 | client. | ||
| 31 | """ | ||
| 32 | |||
| 33 | def handle(self): | ||
| 34 | |||
| 35 | data = self.rfile.readline().strip() | ||
| 36 | |||
| 37 | if self.server.queue.qsize() > 3: | ||
| 38 | self.server.queue.get() | ||
| 39 | |||
| 40 | self.server.queue.put(data) | ||
| 41 | #print(self.data) | ||
| 42 | |||
| 43 | |||
| 44 | class WebNotifyServer(object): | ||
| 45 | |||
| 46 | def __init__(self, queue): | ||
| 47 | self.queue = queue | ||
| 48 | |||
| 49 | @cherrypy.expose | ||
| 50 | def notifications(self): | ||
| 51 | |||
| 52 | entry_list = list() | ||
| 53 | |||
| 54 | while not self.queue.empty(): | ||
| 55 | entry_list.append(self.queue.get(False)) | ||
| 56 | |||
| 57 | #print (json.dumps(entry_list, sort_keys=True, indent=4)) | ||
| 58 | return json.dumps(entry_list) | ||
| 59 | |||
| 60 | |||
| 61 | def socket_server(queue): | ||
| 62 | |||
| 63 | try: | ||
| 64 | server = CustomSocketServer((settings.SOCKET_SERVER_HOST, | ||
| 65 | settings.SOCKET_SERVER_PORT), | ||
| 66 | MyTCPHandler, | ||
| 67 | queue) | ||
| 68 | server.serve_forever() | ||
| 69 | |||
| 70 | except Exception as e: | ||
| 71 | sys.stderr.write("SocketServer error: {0}".format(e)) | ||
| 72 | sys.exit(1) | ||
| 73 | |||
| 74 | sys.exit(0) | ||
| 75 | |||
| 76 | |||
| 77 | |||
| 78 | def web_server(queue): | ||
| 79 | |||
| 80 | cherrypy.config.update({ | ||
| 81 | 'server.socket_host': settings.WEB_SERVER_HOST, | ||
| 82 | 'server.socket_port': settings.WEB_SERVER_PORT, | ||
| 83 | 'server.ssl_module': 'pyopenssl', | ||
| 84 | 'server.ssl_certificate': settings.WEB_SERVER_CERT, | ||
| 85 | 'server.ssl_private_key': settings.WEB_SERVER_KEY, | ||
| 86 | }) | ||
| 87 | |||
| 88 | try: | ||
| 89 | |||
| 90 | cherrypy.quickstart(WebNotifyServer(queue)) | ||
| 91 | |||
| 92 | except Exception as e: | ||
| 93 | sys.stderr.write("WebServer error: {0}".format(e)) | ||
| 94 | sys.exit(1) | ||
| 95 | |||
| 96 | sys.exit(0) | ||
| 97 | |||
| 98 | |||
| 99 | def main(): | ||
| 100 | |||
| 101 | parser = argparse.ArgumentParser(description='The following options are available') | ||
| 102 | |||
| 103 | |||
| 104 | parser.add_argument('-d', | ||
| 105 | action='store_true', | ||
| 106 | dest='daemonize', | ||
| 107 | default=False, | ||
| 108 | help='daemonize the server process') | ||
| 109 | |||
| 110 | parser.add_argument('-H', '--hostname', | ||
| 111 | metavar='HOSTNAME', | ||
| 112 | type=str, | ||
| 113 | dest='hostname', | ||
| 114 | default='127.0.0.1', | ||
| 115 | help="Server IP / hostname") | ||
| 116 | |||
| 117 | parser.add_argument('-P', '--port', | ||
| 118 | metavar='PORT', | ||
| 119 | type=int, | ||
| 120 | dest='port', | ||
| 121 | default='9998', | ||
| 122 | help="Server port") | ||
| 123 | |||
| 124 | parser.add_argument('-p', '--password', | ||
| 125 | metavar='PASSWORD', | ||
| 126 | type=str, | ||
| 127 | dest='password', | ||
| 128 | help="Access password for the BOINS server") | ||
| 129 | |||
| 130 | parser.add_argument('-v', '--version', | ||
| 131 | action='version', | ||
| 132 | version='%(prog)s {0}'.format(__VERSION__), | ||
| 133 | help='display program-version and exit') | ||
| 134 | |||
| 135 | |||
| 136 | |||
| 137 | sys.exit(0) | ||
| 138 | |||
| 139 | if __name__ == "__main__": | ||
| 140 | main() | ||
