diff options
Diffstat (limited to 'beinc_server.py')
| -rwxr-xr-x | beinc_server.py | 255 |
1 files changed, 122 insertions, 133 deletions
diff --git a/beinc_server.py b/beinc_server.py index ad81ce9..0f6c248 100755 --- a/beinc_server.py +++ b/beinc_server.py | |||
| @@ -1,8 +1,8 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | 2 | # -*- coding: utf-8 -*- |
| 3 | 3 | ||
| 4 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v3.0 | 4 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v4.0 |
| 5 | # Copyright (C) 2013-2018 Simeon Simeonov | 5 | # Copyright (C) 2013-2020 Simeon Simeonov |
| 6 | 6 | ||
| 7 | # This program is free software: you can redistribute it and/or modify | 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 | 8 | # it under the terms of the GNU General Public License as published by |
| @@ -29,26 +29,16 @@ import sys | |||
| 29 | 29 | ||
| 30 | from functools import wraps | 30 | from functools import wraps |
| 31 | from logging.config import fileConfig | 31 | from logging.config import fileConfig |
| 32 | 32 | from http.server import BaseHTTPRequestHandler, HTTPServer | |
| 33 | PY2 = sys.version_info[0] == 2 | ||
| 34 | PY3 = sys.version_info[0] == 3 | ||
| 35 | |||
| 36 | if PY3: | ||
| 37 | from http.server import BaseHTTPRequestHandler, HTTPServer | ||
| 38 | else: | ||
| 39 | from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer | ||
| 40 | 33 | ||
| 41 | try: | 34 | try: |
| 42 | if PY3: | 35 | import notify2 as pynotify |
| 43 | import notify2 as pynotify | 36 | except ImportError: |
| 44 | else: | ||
| 45 | import pynotify | ||
| 46 | except ImportError as e: | ||
| 47 | pynotify = None | 37 | pynotify = None |
| 48 | 38 | ||
| 49 | 39 | ||
| 50 | __author__ = 'Simeon Simeonov' | 40 | __author__ = 'Simeon Simeonov' |
| 51 | __version__ = '3.0' | 41 | __version__ = '4.0' |
| 52 | __license__ = 'GPL3' | 42 | __license__ = 'GPL3' |
| 53 | 43 | ||
| 54 | 44 | ||
| @@ -59,28 +49,30 @@ BEINC_CURRENT_CONFIG_VERSION = 3 | |||
| 59 | 49 | ||
| 60 | 50 | ||
| 61 | class BEINCError401(Exception): | 51 | class BEINCError401(Exception): |
| 62 | pass | 52 | """BEINCError401""" |
| 63 | 53 | ||
| 64 | 54 | ||
| 65 | class BEINCError403(Exception): | 55 | class BEINCError403(Exception): |
| 66 | pass | 56 | """BEINCError403""" |
| 67 | 57 | ||
| 68 | 58 | ||
| 69 | class BEINCError404(Exception): | 59 | class BEINCError404(Exception): |
| 70 | pass | 60 | """BEINCError404""" |
| 71 | 61 | ||
| 72 | 62 | ||
| 73 | class BEINCError405(Exception): | 63 | class BEINCError405(Exception): |
| 74 | pass | 64 | """BEINCError405""" |
| 75 | 65 | ||
| 76 | 66 | ||
| 77 | def beinc_login_required(method): | 67 | def eprint(*arg, **kwargs): |
| 78 | """ | 68 | """stdderr print wrapper""" |
| 79 | Decorator for checking login credentials | 69 | print(*arg, file=sys.stderr, flush=True, **kwargs) |
| 80 | """ | 70 | |
| 81 | 71 | ||
| 72 | def beinc_login_required(method): | ||
| 73 | """Decorator for checking login credentials""" | ||
| 82 | @wraps(method) | 74 | @wraps(method) |
| 83 | def wrapper(self, data, *args, **kwargs): | 75 | def wrapper(self, data, *arg, **kwargs): |
| 84 | if data.get('resource_name') is None: | 76 | if data.get('resource_name') is None: |
| 85 | raise BEINCError403('Resource-name missing') | 77 | raise BEINCError403('Resource-name missing') |
| 86 | if data.get('password') is None: | 78 | if data.get('password') is None: |
| @@ -91,122 +83,122 @@ def beinc_login_required(method): | |||
| 91 | raise BEINCError401('Wrong instance or password') | 83 | raise BEINCError401('Wrong instance or password') |
| 92 | if not instance.password_match(data.get('password')): | 84 | if not instance.password_match(data.get('password')): |
| 93 | raise BEINCError401('Wrong instance or password') | 85 | raise BEINCError401('Wrong instance or password') |
| 94 | return method(self, data, *args, **kwargs) | 86 | return method(self, data, *arg, **kwargs) |
| 95 | return wrapper | 87 | return wrapper |
| 96 | 88 | ||
| 97 | 89 | ||
| 98 | class BEINCInstance(object): | 90 | class BEINCInstance: |
| 99 | """ | 91 | """Represents a single server-instance""" |
| 100 | Represents a single server-instance | ||
| 101 | """ | ||
| 102 | 92 | ||
| 103 | def __init__(self, instance_dict): | 93 | def __init__(self, instance_dict): |
| 104 | """ | 94 | """ |
| 105 | instance_dict: the config-dictionary node that represents this instance | 95 | instance_dict: the config-dictionary node that represents this instance |
| 106 | """ | 96 | """ |
| 107 | self.__message_queue = list() | 97 | self._message_queue = [] |
| 108 | self.__osd_type = BEINC_OSD_TYPE_NONE | 98 | self._osd_type = BEINC_OSD_TYPE_NONE |
| 109 | self.__osd_notification = None | 99 | self._osd_notification = None |
| 110 | 100 | ||
| 111 | self.__name = instance_dict.get('name') | 101 | self._name = instance_dict.get('name') |
| 112 | self.__password = instance_dict.get('password', '') | 102 | self._password = instance_dict.get('password', '') |
| 113 | self.__queue_size = int(instance_dict.get('queue_size', 3)) | 103 | self._queue_size = int(instance_dict.get('queue_size', 3)) |
| 114 | if instance_dict['osd_system'].lower() == 'pynotify': | 104 | if instance_dict['osd_system'].lower() == 'pynotify': |
| 115 | self.__queue_size = 0 # disable queueing | 105 | self._queue_size = 0 # disable queueing |
| 116 | if pynotify is None: | 106 | if pynotify is None: |
| 117 | sys.stderr.write( | 107 | eprint('This server does not possess pynotify capability') |
| 118 | 'This server does not possess pynotify capability\n') | 108 | eprint(f'Remove the instance {self._name} or define it with ' |
| 119 | sys.stderr.write( | 109 | f'"osd_system": "none" or other ' |
| 120 | 'Remove the instance {0}'.format(self.__name)) | 110 | f'available backend') |
| 121 | sys.stderr.write( | ||
| 122 | 'or define it with "osd_system": "none" ' | ||
| 123 | 'or other available backend\n') | ||
| 124 | sys.exit(errno.EPERM) | 111 | sys.exit(errno.EPERM) |
| 125 | try: | 112 | try: |
| 126 | self.__osd_notification = pynotify.Notification(' ') | 113 | self._osd_notification = pynotify.Notification(' ') |
| 127 | if PY3: | 114 | self._osd_notification.timeout = 1000 * int( |
| 128 | self.__osd_notification.timeout = 1000 * int( | 115 | instance_dict.get('osd_timeout', 5)) |
| 129 | instance_dict.get('osd_timeout', 5)) | 116 | self._osd_notification.set_category('im.received') |
| 130 | self.__osd_notification.set_category('im.received') | 117 | self._osd_type = BEINC_OSD_TYPE_PYNOTIFY |
| 131 | else: | ||
| 132 | self.__osd_notification.set_timeout( | ||
| 133 | 1000 * int(instance_dict.get('osd_timeout', 5))) | ||
| 134 | self.__osd_notification.set_property( | ||
| 135 | 'app_name', | ||
| 136 | '{0} {1}'.format(sys.argv[0], __version__)) | ||
| 137 | self.__osd_type = BEINC_OSD_TYPE_PYNOTIFY | ||
| 138 | except Exception as e: | 118 | except Exception as e: |
| 139 | sys.stderr.write( | 119 | eprint(f'Unable to set up a pynotify notification object ' |
| 140 | 'Unable to set up a ' | 120 | f'for "{self._name}" ({e})') |
| 141 | 'pynotify notification object for "{0}" ({1})\n'.format( | ||
| 142 | self.__name, | ||
| 143 | e)) | ||
| 144 | sys.exit(errno.EPERM) | 121 | sys.exit(errno.EPERM) |
| 145 | 122 | ||
| 146 | @property | 123 | @property |
| 147 | def name(self): | 124 | def name(self): |
| 148 | """ | 125 | """name-property for the server instance (read-only)""" |
| 149 | name-property for the server instance (read-only) | 126 | return self._name |
| 150 | """ | ||
| 151 | return self.__name | ||
| 152 | 127 | ||
| 153 | @property | 128 | @property |
| 154 | def queueable(self): | 129 | def queueable(self): |
| 155 | """ | 130 | """True if this instance has a queueing capability (read-only)""" |
| 156 | True if this instance has a queueing capability (read-only) | 131 | return bool(self._queue_size) |
| 157 | """ | ||
| 158 | return bool(self.__queue_size) | ||
| 159 | 132 | ||
| 160 | def password_match(self, password): | 133 | def password_match(self, password): |
| 161 | """ | 134 | """ |
| 162 | Returns True if 'passowrd' matches the instance-password, | 135 | Returns True if 'passowrd' matches the instance-password, |
| 163 | otherwise - False | 136 | otherwise - False |
| 137 | |||
| 138 | :param password: The password to compare | ||
| 139 | :type password: str | ||
| 140 | |||
| 141 | :return: True if the password matches, False otherwise | ||
| 142 | :rtype: bool | ||
| 164 | """ | 143 | """ |
| 165 | return True if self.__password == password else False | 144 | return self._password == password |
| 166 | 145 | ||
| 167 | def send_message(self, title, message): | 146 | def send_message(self, title, message): |
| 168 | """ | 147 | """ |
| 169 | Displays or enqueues the message, | 148 | Displays or enqueues the message, |
| 170 | depending on the instance's type in regard to the osd_system | 149 | depending on the instance's type in regard to the osd_system |
| 150 | |||
| 151 | :param title: The title | ||
| 152 | :type title: str | ||
| 153 | |||
| 154 | :param message: The message | ||
| 155 | :type message: str | ||
| 171 | """ | 156 | """ |
| 172 | if self.__osd_type == BEINC_OSD_TYPE_PYNOTIFY: | 157 | if self._osd_type == BEINC_OSD_TYPE_PYNOTIFY: |
| 173 | self.__send_pynotify_messaage(title, message) | 158 | self._send_pynotify_messaage(title, message) |
| 174 | else: | 159 | else: |
| 175 | self.__send_message_to_queue(title, message) | 160 | self._send_message_to_queue(title, message) |
| 176 | 161 | ||
| 177 | def get_queue(self): | 162 | def get_queue(self): |
| 178 | """ | 163 | """Returns a list of dict representation of the message queue""" |
| 179 | Returns a list of dict representation of the message queue | 164 | r_value = self._message_queue |
| 180 | """ | 165 | self._message_queue = [] |
| 181 | r_value = self.__message_queue | ||
| 182 | self.__message_queue = list() | ||
| 183 | return r_value | 166 | return r_value |
| 184 | 167 | ||
| 185 | def __send_pynotify_messaage(self, title, message): | 168 | def _send_pynotify_messaage(self, title, message): |
| 186 | """ | 169 | """ |
| 187 | Displays pynotify message | 170 | Displays pynotify message |
| 171 | |||
| 172 | :param title: The title | ||
| 173 | :type title: str | ||
| 174 | |||
| 175 | :param message: The message | ||
| 176 | :type message: str | ||
| 188 | """ | 177 | """ |
| 189 | self.__osd_notification.update(summary=title, message=message) | 178 | self._osd_notification.update(summary=title, message=message) |
| 190 | self.__osd_notification.show() | 179 | self._osd_notification.show() |
| 191 | 180 | ||
| 192 | def __send_message_to_queue(self, title, message): | 181 | def _send_message_to_queue(self, title, message): |
| 193 | """ | 182 | """ |
| 194 | Enqueues the message | 183 | Enqueues the message |
| 184 | |||
| 185 | :param title: The title | ||
| 186 | :type title: str | ||
| 187 | |||
| 188 | :param message: The message | ||
| 189 | :type message: str | ||
| 195 | """ | 190 | """ |
| 196 | if len(self.__message_queue) >= self.__queue_size: | 191 | if len(self._message_queue) >= self._queue_size: |
| 197 | self.__message_queue.pop(0) | 192 | self._message_queue.pop(0) |
| 198 | self.__message_queue.append({'title': title, 'message': message}) | 193 | self._message_queue.append({'title': title, 'message': message}) |
| 199 | 194 | ||
| 200 | 195 | ||
| 201 | class BEINCCustomHandler(BaseHTTPRequestHandler): | 196 | class BEINCCustomHandler(BaseHTTPRequestHandler): |
| 202 | """ | 197 | """Custom handler""" |
| 203 | """ | ||
| 204 | def do_POST(self): | 198 | def do_POST(self): |
| 205 | """ | 199 | """Handle POST requests""" |
| 206 | Handle POST requests | ||
| 207 | """ | ||
| 208 | if self.path.strip('/') not in ('beinc/push', 'beinc/pull'): | 200 | if self.path.strip('/') not in ('beinc/push', 'beinc/pull'): |
| 209 | self.__generate_json_error(404, 'Invalid resource path') | 201 | self._generate_json_error(404, 'Invalid resource path') |
| 210 | return | 202 | return |
| 211 | form = cgi.FieldStorage( | 203 | form = cgi.FieldStorage( |
| 212 | fp=self.rfile, | 204 | fp=self.rfile, |
| @@ -222,43 +214,38 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 222 | try: | 214 | try: |
| 223 | result = {} | 215 | result = {} |
| 224 | if self.path.strip('/') == 'beinc/push': | 216 | if self.path.strip('/') == 'beinc/push': |
| 225 | result = self.__handle_push(POST_data) | 217 | result = self._handle_push(POST_data) |
| 226 | elif self.path.strip('/') == 'beinc/pull': | 218 | elif self.path.strip('/') == 'beinc/pull': |
| 227 | result = self.__handle_pull(POST_data) | 219 | result = self._handle_pull(POST_data) |
| 228 | self.__render_to_JSON_response(result) | 220 | self._render_to_JSON_response(result) |
| 229 | except BEINCError401 as e: | 221 | except BEINCError401 as e: |
| 230 | self.__generate_json_error(401, str(e)) | 222 | self._generate_json_error(401, str(e)) |
| 231 | except BEINCError403 as e: | 223 | except BEINCError403 as e: |
| 232 | self.__generate_json_error(403, str(e)) | 224 | self._generate_json_error(403, str(e)) |
| 233 | except BEINCError404 as e: | 225 | except BEINCError404 as e: |
| 234 | self.__generate_json_error(404, str(e)) | 226 | self._generate_json_error(404, str(e)) |
| 235 | except BEINCError405 as e: | 227 | except BEINCError405 as e: |
| 236 | self.__generate_json_error(405, str(e)) | 228 | self._generate_json_error(405, str(e)) |
| 237 | except Exception as e: | 229 | except Exception as e: |
| 238 | self.__generate_json_error(500, | 230 | self._generate_json_error(500, f'Unexpected error: {e}') |
| 239 | 'Unexpected error: {}'.format(str(e))) | ||
| 240 | 231 | ||
| 241 | def do_GET(self): | 232 | def do_GET(self): |
| 242 | """ | 233 | """Handle GET Requests""" |
| 243 | Handle GET Requests | 234 | self._generate_json_error(405, 'Unsupported method') |
| 244 | """ | ||
| 245 | self.__generate_json_error(405, 'Unsupported method') | ||
| 246 | 235 | ||
| 247 | @beinc_login_required | 236 | @beinc_login_required |
| 248 | def __handle_push(self, data): | 237 | def _handle_push(self, data): |
| 249 | """ | 238 | """Handle push""" |
| 250 | """ | ||
| 251 | instance = self.server.instances[data.get('resource_name')] | 239 | instance = self.server.instances[data.get('resource_name')] |
| 252 | try: | 240 | try: |
| 253 | instance.send_message(data.get('title'), data.get('message')) | 241 | instance.send_message(data.get('title'), data.get('message')) |
| 254 | return {'message': 'OK. Sent.'} | 242 | return {'message': 'OK. Sent.'} |
| 255 | except Exception as e: | 243 | except Exception as e: |
| 256 | self.__generate_json_error(500, str(e)) | 244 | self._generate_json_error(500, str(e)) |
| 257 | 245 | ||
| 258 | @beinc_login_required | 246 | @beinc_login_required |
| 259 | def __handle_pull(self, data): | 247 | def _handle_pull(self, data): |
| 260 | """ | 248 | """Handle pull""" |
| 261 | """ | ||
| 262 | instance = self.server.instances[data.get('resource_name')] | 249 | instance = self.server.instances[data.get('resource_name')] |
| 263 | try: | 250 | try: |
| 264 | if not instance.queueable: | 251 | if not instance.queueable: |
| @@ -267,13 +254,12 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 267 | return {'message': 'OK. Fetched.', | 254 | return {'message': 'OK. Fetched.', |
| 268 | 'data': {'messages': instance.get_queue()}} | 255 | 'data': {'messages': instance.get_queue()}} |
| 269 | except Exception as e: | 256 | except Exception as e: |
| 270 | self.__generate_json_error(500, str(e)) | 257 | self._generate_json_error(500, str(e)) |
| 271 | 258 | ||
| 272 | def __generate_json_error(self, code, message): | 259 | def _generate_json_error(self, code, message): |
| 273 | """ | 260 | """ |
| 274 | Generates response header and json content for errors | 261 | Generates response header and json content for errors |
| 275 | 262 | ||
| 276 | Keyword Arguments: | ||
| 277 | :param code: the HTTP code | 263 | :param code: the HTTP code |
| 278 | :type code: int | 264 | :type code: int |
| 279 | 265 | ||
| @@ -288,9 +274,8 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 288 | sort_keys=True, | 274 | sort_keys=True, |
| 289 | indent=4).encode('utf-8')) | 275 | indent=4).encode('utf-8')) |
| 290 | 276 | ||
| 291 | def __render_to_JSON_response(self, context): | 277 | def _render_to_JSON_response(self, context): |
| 292 | """ | 278 | """ |
| 293 | Keyword Arguments: | ||
| 294 | :param context: the context-dict to be converted to json | 279 | :param context: the context-dict to be converted to json |
| 295 | :type context: dict | 280 | :type context: dict |
| 296 | """ | 281 | """ |
| @@ -305,31 +290,36 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 305 | 290 | ||
| 306 | 291 | ||
| 307 | class BEINCNotifyServer(HTTPServer): | 292 | class BEINCNotifyServer(HTTPServer): |
| 308 | """ | 293 | """BEINCNotifyServer class""" |
| 309 | """ | 294 | def __init__(self, *arg, **kwargs): |
| 295 | """Default constructor""" | ||
| 296 | super().__init__(*arg, **kwargs) | ||
| 297 | self._config = None | ||
| 298 | self._instances = {} | ||
| 299 | |||
| 310 | def set_config(self, config): | 300 | def set_config(self, config): |
| 311 | """ | 301 | """ |
| 312 | Sets the configuration dict for the server, instantiates | 302 | Sets the configuration dict for the server, instantiates |
| 313 | the BEINC instances and initiates the defined OSD backends | 303 | the BEINC instances and initiates the defined OSD backends |
| 314 | """ | 304 | """ |
| 315 | self.__config = config | 305 | self._config = config |
| 316 | self.__instances = dict() | ||
| 317 | # initialize pynotify if the module exists and if needed | 306 | # initialize pynotify if the module exists and if needed |
| 318 | if pynotify: | 307 | if pynotify: |
| 319 | for instance in self.__config['server']['instances']: | 308 | for instance in self._config['server']['instances']: |
| 320 | # check if we have at least one instance that uses pynotify | 309 | # check if we have at least one instance that uses pynotify |
| 321 | # before initializing it | 310 | # before initializing it |
| 322 | if instance.get('osd_system', '').lower() == 'pynotify': | 311 | if instance.get('osd_system', '').lower() == 'pynotify': |
| 323 | if not pynotify.init('BEINC Notify'): | 312 | if not pynotify.init('BEINC Notify'): |
| 324 | sys.stderr.write('pynotify.init failed! Exiting...\n') | 313 | eprint('pynotify.init failed! Exiting...') |
| 325 | sys.exit(1) | 314 | sys.exit(1) |
| 326 | break | 315 | break |
| 316 | instance = {'name': 'Invalid'} | ||
| 327 | try: | 317 | try: |
| 328 | for instance in self.__config['server']['instances']: | 318 | for instance in self._config['server']['instances']: |
| 329 | self.__instances[instance['name']] = BEINCInstance(instance) | 319 | self._instances[instance['name']] = BEINCInstance(instance) |
| 330 | logger.info('Instance "{0}" added'.format(instance['name'])) | 320 | logger.info('Instance %s added', instance['name']) |
| 331 | except Exception as e: | 321 | except Exception as e: |
| 332 | sys.stderr.write('Unable to create instance "{0}": {1}\n'.format( | 322 | eprint('Unable to create instance "{0}": {1}'.format( |
| 333 | instance['name'], | 323 | instance['name'], |
| 334 | e)) | 324 | e)) |
| 335 | sys.exit(1) | 325 | sys.exit(1) |
| @@ -339,7 +329,7 @@ class BEINCNotifyServer(HTTPServer): | |||
| 339 | """ | 329 | """ |
| 340 | a property that returns the instance list (read-only) | 330 | a property that returns the instance list (read-only) |
| 341 | """ | 331 | """ |
| 342 | return self.__instances | 332 | return self._instances |
| 343 | 333 | ||
| 344 | 334 | ||
| 345 | if __name__ == '__main__': | 335 | if __name__ == '__main__': |
| @@ -390,15 +380,14 @@ if __name__ == '__main__': | |||
| 390 | parser.add_argument( | 380 | parser.add_argument( |
| 391 | '-v', '--version', | 381 | '-v', '--version', |
| 392 | action='version', | 382 | action='version', |
| 393 | version='%(prog)s {0}'.format(__version__), | 383 | version=f'%(prog)s {__version__}', |
| 394 | help='Display program-version and exit') | 384 | help='Display program-version and exit') |
| 395 | args = parser.parse_args() | 385 | args = parser.parse_args() |
| 396 | try: | 386 | try: |
| 397 | with open(args.config_file, 'r') as fp: | 387 | with open(args.config_file, 'r') as fp: |
| 398 | config_dict = json.load(fp) | 388 | config_dict = json.load(fp) |
| 399 | except Exception as e: | 389 | except Exception as e: |
| 400 | sys.stderr.write('Unable to parse {0}: {1}\n'.format(args.config_file, | 390 | eprint(f'Unable to parse {args.config_file}: {e}') |
| 401 | e)) | ||
| 402 | sys.exit(errno.EIO) | 391 | sys.exit(errno.EIO) |
| 403 | try: | 392 | try: |
| 404 | if os.path.isfile(args.logger_config): | 393 | if os.path.isfile(args.logger_config): |
| @@ -411,11 +400,11 @@ if __name__ == '__main__': | |||
| 411 | logger = logging.getLogger('beinc') | 400 | logger = logging.getLogger('beinc') |
| 412 | logger.info('BEINC starting. Loading config...') | 401 | logger.info('BEINC starting. Loading config...') |
| 413 | if config_dict.get('config_version') != BEINC_CURRENT_CONFIG_VERSION: | 402 | if config_dict.get('config_version') != BEINC_CURRENT_CONFIG_VERSION: |
| 414 | sys.stderr.write( | 403 | eprint( |
| 415 | 'WARNING: The version of the config-file: {0} ({1}) ' | 404 | 'WARNING: The version of the config-file: {0} ({1}) ' |
| 416 | 'does not correspond to the latest version supported ' | 405 | 'does not correspond to the latest version supported ' |
| 417 | 'by this program ({2})\nCheck beinc_config_sample.json ' | 406 | 'by this program ({2})\nCheck beinc_config_sample.json ' |
| 418 | 'for the newest features!\n'.format( | 407 | 'for the newest features!'.format( |
| 419 | args.config_file, | 408 | args.config_file, |
| 420 | config_dict.get('config_version', 'Not set'), | 409 | config_dict.get('config_version', 'Not set'), |
| 421 | BEINC_CURRENT_CONFIG_VERSION)) | 410 | BEINC_CURRENT_CONFIG_VERSION)) |
| @@ -441,6 +430,6 @@ if __name__ == '__main__': | |||
| 441 | except KeyboardInterrupt: | 430 | except KeyboardInterrupt: |
| 442 | print('\n\nTerminating...') | 431 | print('\n\nTerminating...') |
| 443 | except Exception as e: | 432 | except Exception as e: |
| 444 | sys.stderr.write('BEINCServer critical error: {0}\n'.format(e)) | 433 | eprint(f'BEINCServer critical error: {e}') |
| 445 | sys.exit(1) | 434 | sys.exit(1) |
| 446 | sys.exit(0) | 435 | sys.exit(0) |
