def run_callback(self, obj, args=None): try: assert hasattr(self, 'on%s' % obj) f = getattr(self, 'on%s' % obj) if args is not None: return f(args) else: return f() except WebSocketError as e: if is_ws_error_abnormal(e): log.warn('WebSocket fault: %s' % e.message) log.error(format_exception(e, None), extra=self.channel_history) report_exception(e, extra=self.channel_history) except Exception as e: self.onerror(e) if not self.ws.closed: try: self.ws.close() except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) finally: if USE_ALCHEMY_MW: session_handler.close()
def close(self, data): if not data.get('channel'): raise Exception('No channel name, exit') handler = self.channel_handlers.get(data['channel']) if not handler: return self.channel_404(data['channel']) if self.check_permissions and not self.validate_close(data['channel']): return self.send_error_code(403, 'open', data['channel']) if not handler.closable and not self.ws.closed: try: self.ws.send( json.dumps({ 'pkg': { 'action': 'close', 'data': { 'channel': data['channel'], 'result': 501 }, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) return handler.onclose() del self.channel_handlers[data['channel']] if not self.ws.closed: try: self.ws.send( json.dumps({ 'pkg': { 'action': 'close', 'data': { 'channel': data['channel'], 'result': 200 }, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def onerror(self, e): """Send here Exception and traceback by Error channel """ f = Formatter() history = json.dumps(self.channel_history, indent=2, default=datahandler) data = (history, xml_escape(f.formatException(sys.exc_info())),) if EXCEPTION_FLAVOR == 'html': traceback = '<pre>%s\n\n%s</pre>' % data else: traceback = '%s\n%s' % data if DEBUG: err_message = {'channel': WS_CHANNELS['ERROR_CHID'], 'pkg': {'exception': repr(e), 'tb': traceback}} else: err_message = {'channel': WS_CHANNELS['ERROR_CHID'], 'pkg': {'exception': 'error 500', 'tb': 'an error occurred'}} log.error(format_exception(e, None), extra=self.channel_history) report_exception(e, extra=self.channel_history) if not self.ws.closed: try: self.ws.send(json.dumps(err_message, separators=(', ', ':'))) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def channel_404(self, channel): try: return self.ws.send(json.dumps({'channel': channel, 'action': 'no-such-channel', 'note': 'Channel with ID=%s not ' 'found' % channel, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def close(self, data): if not data.get('channel'): raise Exception('No channel name, exit') handler = self.channel_handlers.get(data['channel']) if not handler: return self.channel_404(data['channel']) if self.check_permissions and not self.validate_close(data['channel']): return self.send_error_code(403, 'open', data['channel']) if not handler.closable and not self.ws.closed: try: self.ws.send( json.dumps({'pkg': {'action': 'close', 'data': {'channel': data['channel'], 'result': 501}, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) return handler.onclose() del self.channel_handlers[data['channel']] if not self.ws.closed: try: self.ws.send( json.dumps({'pkg': {'action': 'close', 'data': {'channel': data['channel'], 'result': 200}, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def channel_404(self, channel): try: return self.ws.send( json.dumps({ 'channel': channel, 'action': 'no-such-channel', 'note': 'Channel with ID=%s not ' 'found' % channel, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def bad_request(self, message="Bad request"): if not self.ws.closed: try: self.ws.send( json.dumps({'pkg': {'action': 'open', 'data': {'result': 400, 'message': message, }, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def send_error_code(self, code, act, channel): if not self.ws.closed: try: self.ws.send(json.dumps({'pkg': {'action': act, 'data': {'channel': channel, 'result': code, }, }, })) self.ws.close() except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def _send_ws(self, data): if type(data) != dict: raise TypeError("data is %s not dict" % type(data)) package_to_send = {'channel': self.channel, 'pkg': data, 'session_params': self.session.params, } data = json.dumps(package_to_send, default=datahandler) try: self.ws.send(data) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) self.onclose()
def _send_ws(self, data): if type(data) != dict: raise TypeError("data is %s not dict" % type(data)) package_to_send = { 'channel': self.channel, 'pkg': data, 'session_params': self.session.params, } data = json.dumps(package_to_send, default=datahandler) try: self.ws.send(data) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) self.onclose()
def bad_request(self, message="Bad request"): if not self.ws.closed: try: self.ws.send( json.dumps({ 'pkg': { 'action': 'open', 'data': { 'result': 400, 'message': message, }, }, })) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def open(self, data): self.propagate_greenlet_data(data) if not data.get('token'): self.bad_request(message='No access token, exit') return if not data.get('channel'): self.bad_request(message='No channel name') return self.access_token = data.get('token') self.reopen = data.get('reopen', False) self.pre_open() handler = self.allowed_channels.get(data.get('channel')) if not handler: return self.channel_404(data['channel']) if self.check_permissions \ and not self.validate_open(data.get('channel')): return self.send_error_code(403, 'open', data.get('channel')) if not self.is_auth: return self.send_error_code(403, 'open', data.get('channel')) handler = self.register_channel(data.get('channel'), handler) self.run_callback('open') pkg = { 'action': 'open', 'data': { 'closable': handler.closable, 'result': 200 }, } package_to_send = { 'channel': data.get('channel'), 'pkg': pkg, 'session_params': self.session.params } raw_data = json.dumps(package_to_send, default=datahandler) self.after_open() try: self.ws.send(raw_data) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def send_error_code(self, code, act, channel): if not self.ws.closed: try: self.ws.send( json.dumps({ 'pkg': { 'action': act, 'data': { 'channel': channel, 'result': code, }, }, })) self.ws.close() except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def onerror(self, e): """Send here Exception and traceback by Error channel """ f = Formatter() history = json.dumps(self.channel_history, indent=2, default=datahandler) data = ( history, xml_escape(f.formatException(sys.exc_info())), ) if EXCEPTION_FLAVOR == 'html': traceback = '<pre>%s\n\n%s</pre>' % data else: traceback = '%s\n%s' % data if DEBUG: err_message = { 'channel': WS_CHANNELS['ERROR_CHID'], 'pkg': { 'exception': repr(e), 'tb': traceback } } else: err_message = { 'channel': WS_CHANNELS['ERROR_CHID'], 'pkg': { 'exception': 'error 500', 'tb': 'an error occurred' } } log.error(format_exception(e, None), extra=self.channel_history) report_exception(e, extra=self.channel_history) if not self.ws.closed: try: self.ws.send(json.dumps(err_message, separators=(', ', ':'))) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def open(self, data): self.propagate_greenlet_data(data) if not data.get('token'): self.bad_request(message='No access token, exit') return if not data.get('channel'): self.bad_request(message='No channel name') return self.access_token = data.get('token') self.reopen = data.get('reopen', False) self.pre_open() handler = self.allowed_channels.get(data.get('channel')) if not handler: return self.channel_404(data['channel']) if self.check_permissions \ and not self.validate_open(data.get('channel')): return self.send_error_code(403, 'open', data.get('channel')) if not self.is_auth: return self.send_error_code(403, 'open', data.get('channel')) handler = self.register_channel(data.get('channel'), handler) self.run_callback('open') pkg = {'action': 'open', 'data': {'closable': handler.closable, 'result': 200}, } package_to_send = {'channel': data.get('channel'), 'pkg': pkg, 'session_params': self.session.params} raw_data = json.dumps(package_to_send, default=datahandler) self.after_open() try: self.ws.send(raw_data) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history)
def __call__(self, env, start_response): websocket = env.get('wsgi.websocket') if not websocket: self.bad_request() self.ws = websocket # Endless event loop while 1: try: data = self.ws.receive() self.clear_test_data() except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) break except Exception: f = Formatter() traceback = f.formatException(sys.exc_info()) log.error('Servlet fault: \n%s' % traceback, extra=self.channel_history) break if data: jd = json.loads(data) if jd.get('pkg') \ and jd['pkg'].get('data') \ and isinstance(jd['pkg']['data'], dict)\ and jd['pkg']['data'].get('testData'): self.write_test_data(jd['pkg']['data']['testData']) del jd['pkg']['data']['testData'] self.channel_history['messages'].append(jd) if hasattr(self.session, 'sess') and self.session.sess: self.channel_history['session_id'] = self.session.sess.id self.channel_history['user_id'] = self.session.sess.user_id if not jd.get('channel') and jd.get('pkg'): act = jd['pkg'].get('action') assert not act.startswith('_'), "security violation" try: handler = getattr(self, act) except WebSocketError as e: if is_ws_error_abnormal(e): f = Formatter() traceback = f.formatException(sys.exc_info()) log.error('Global channel action error: \n%s' % traceback, extra=self.channel_history) break assert handler.__name__ == "action_wrapper", \ "%s is not allowed to be executed externally." % act handler(jd['pkg']['data']) continue if self.check_permissions \ and not self.validate_send(jd.get('channel')): jd['result'] = 403 if not self.ws.closed: try: self.ws.send(json.dumps(jd)) except WebSocketError as e: if is_ws_error_abnormal(e): log.error('WebSocket fault: %s' % e.message, extra=self.channel_history) continue else: self.run_callback('message', ApiSocketMessage(data)) else: log.debug('Web Socket is disconnected') self.close_event.set() if self.close_event.is_set(): break self.run_callback('close')