def __init__(self, logger: AbstractLogger = Logger()): if WebSocketClient.__instance: raise Exception('Use get_instance() instead!') self.__ws = WebSocketApp( 'wss://jqbx.fm/socket.io/?EIO=3&transport=websocket') self.__logger = logger WebSocketClient.__instance = self
def start(self): self.ws = WebSocketApp(self.url, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close) self.ws.on_open = self.on_open self.ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE})
def run(self): """ Run the bot with a live game websocket """ if not self.config.has_section('Auth'): exit('Error: Config file \'config.ini\' with [Auth] section not found. Please run generate-token.') while True: self.current_game = '' self.broadcast_ended = False socket_url = self.get_socket_url(self.headers) if socket_url: print('CONNECTING TO UK SHOW: %s' % socket_url) web_socket = WebSocketApp(socket_url, on_open=lambda _ws: print('CONNECTION SUCCESSFUL'), on_message=self.on_message, on_error=lambda _ws, err: print('ERROR: %s' % err), on_close=lambda _ws: print('SOCKET CLOSED'), header=self.headers) while not self.broadcast_ended: try: web_socket.run_forever(ping_interval=5) except (WebSocketException, WebSocketTimeoutException): print('CONNECTION LOST. RECONNECTING...') elif self.next_show_time: next_show_time = parser.parse(self.next_show_time) seconds_until_show = (next_show_time - datetime.now(utc)).total_seconds() if seconds_until_show < 0: print('\nGame should have started. Sleeping for 10 seconds.') sleep(10) else: print('\nSleeping until {} ({} seconds)'.format(next_show_time.strftime('%c'), seconds_until_show)) sleep(seconds_until_show) else: print(f'Could not connect to API at {self.api_url}. Sleeping for 10 seconds.') sleep(10)
def start(self): self.ws = WebSocketApp(self.url, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close) self.ws.on_open = self.on_open self.ws.run_forever()
def __init__(self, parent_app, url, *args): WebSocketApp.__init__(self, url, on_open=self.ws_open, on_error=self.ws_error, on_message=self.on_msg_func, *args) self.segments = [] self.max_symbols = 0 self.remaining_symbols = 0 self.valid_until = '' self.contract_mapping = {} self.subscription_type = '' self.confirm_heartbeats = 1 self.store_last_n_heartbeats = self.confirm_heartbeats + 7 self.heartbeat_interval = 5 self.heartbeat_buffer = 0.5 time_of_creation = datetime.now() self.last_n_heartbeat = [ time_of_creation - relativedelta(seconds=i * self.heartbeat_interval) for i in range(-self.store_last_n_heartbeats, 0) ] self.parent_app = parent_app self.disconnect_flag = False self.heartbeat_check_thread = Thread(target=self.check_heartbeat) if self.parent_app.live_port == 8086 or self.parent_app.live_port == 8084: self.heartbeat_check_thread.start()
def connect(self, socket): assert socket, "Must connect to a url" self.connect_attempt += 1 self.disconnect() def on_connect(ws): self.connect_attempt = 0 self.connected = True self.send_config() self.socket = WebSocketApp(socket, on_open=on_connect, on_close=lambda message: self.attempt_reconnect(), on_message=lambda ws, message: self.parse_message(message), on_error=lambda ws, error: self.process_error(error)) self.socket_thread = threading.Thread(target=self.socket.run_forever) # override default join behavior to shut down thread properly when exiting program join = self.socket_thread.join def thread_close(): self.socket.keep_running = False self.socket.close() join() self.socket_thread.join = thread_close self.socket_thread.start()
class gdax_websocket: _current = {} _ws = {} def on_message(self, ws, message): msg = loads(message) if 'product_id' in msg: self._current[msg['product_id']] = msg def on_open(self, socket): params = { "type": "subscribe", "channels": [{ "name": "ticker", "product_ids": ["BTC-USD", "ETH-USD", "LTC-USD", "BCH-USD"] }] } socket.send(dumps(params)) def start(self): url = "wss://ws-feed.gdax.com" self._ws = WebSocketApp(url, on_open=self.on_open, on_message=self.on_message) thread = threading.Thread(target=self._ws.run_forever) thread.start() def stop(self): self._ws.close() def get(self, product_id, key): return self._current[product_id][key]
def start(self): url = "wss://ws-feed.gdax.com" self._ws = WebSocketApp(url, on_open=self.on_open, on_message=self.on_message) thread = threading.Thread(target=self._ws.run_forever) thread.start()
def watchover(): os.chdir(os.getcwd()) cmd = "export SUDO_ASKPASS=./pwd.sh && sudo -A ./activate.sh" p = Popen(cmd, shell=True) # p.wait(60) time.sleep(17) while 1: logger.info("start connection") while 1: # 保证socket持续运行 before = time.time() ws = WebSocketApp(SKT_ADDR) ws.run_forever() end = time.time() if end - before < 2: break logger.info("portia disconnected") print("portia disconnected") p.kill() os.popen( "export SUDO_ASKPASS=./pwd.sh && sudo -A docker stop $(sudo -A docker ps)" ) time.sleep(10) p = Popen(cmd, shell=True) # p.wait(60) time.sleep(17)
def __init__(self, api_key, api_secret, should_auth=False, heartbeat=True, ping_interval=10, ping_timeout=9): self.api_key = api_key self.api_secret = api_secret self.ping_timeout = ping_timeout self.ping_interval = ping_interval self.should_auth = should_auth self.heartbeat = heartbeat self.channels = [] self.reconnect_count = 0 EventEmitter.__init__(self) WebSocketApp.__init__( self, url=self.gen_url(), header=self.header(), on_message=self.on_message, on_close=self.on_close, on_open=self.on_open, on_error=self.on_error, on_pong=self.on_pong ) self.on('subscribe', self.on_subscribe)
def main(): ##Main function while (True): try: URL = 'wss://ws-feed.gdax.com' ws = WebSocketApp(URL, on_open=on_open, on_close=on_close, on_error=on_error, on_message=on_message) ws.run_forever() except WebSocketConnectionClosedException as e: print( "WebSocketConnectionClosedException:Failed to recreate connection to host, please ensure network connection to host: {}" .format(URL)) print(e) print(os.sys.exc_info()[0:2]) except WebSocketTimeoutException as e: print( "WebSocketTimeoutException: Failed to recreate connection to hos, please ensure network connection to host: {}" .format(URL)) print(e) print(os.sys.exc_info()[0:2]) except Exception as e: print( "Exception: Failed to (re-)create connection to host, please ensure network connection to host: {}" .format(URL)) print(e) print(os.sys.exc_info()[0:2])
def _send_ack(ws: WebSocketApp, msg): envelope_id = msg.get('envelope_id') if envelope_id: # Send ACK ws.send(json.dumps({ 'envelope_id': envelope_id, }))
def run(self): self.EmbySession = EmbyHttp(self.ws_config) self.EmbySession.lang = self.ws_lang self.ws_user_info = self.EmbySession.user_info self.EmbySession.set_capabilities() uri = self.ws_config["emby_server"].replace('http://', 'ws://').replace( 'https://', 'wss://') uri = uri + '/?api_key=' + self.ws_user_info[ "AccessToken"] + '&deviceId=' 'Xnoppo' '' if self.ws_config["DebugLevel"] > 0: print(uri) self.ws = WebSocketApp(uri, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close) if self.ws_config["DebugLevel"] > 0: print('Ws:Fin open ws\n') self.emby_state = 'Run' while not self.stop_websocket: self.ws.run_forever(ping_interval=10) if self.ws_config["DebugLevel"] > 0: print("after run forever") if self.stop_websocket: break self.emby_state = 'On run_forever' #print("Reconnecting WebSocket") if self.ws_config["DebugLevel"] > 0: print("WebSocketClient Stopped")
def _ws_on_open(self, ws: websocket.WebSocketApp): """Callback for sending the initial authentication data This "payload" contains the required data to authenticate this websocket client as a suitable bot connection to the Discord websocket. Args: ws: websocket connection """ payload = { 'op': WebSocketEvent.IDENTIFY.value, 'd': { 'token': self.token, 'properties': { '$os': sys.platform, '$browser': 'Pycord', '$device': 'Pycord', '$referrer': '', '$referring_domain': '' }, 'compress': True, 'large_threshold': 250 } } self.logger.debug('Sending identify payload') ws.send(json.dumps(payload)) self.connected = True
def _run_websocket(self, ws: WebSocketApp): try: ws.run_forever() except Exception as e: raise Exception(f'Unexpected error while running websocket: {e}') finally: self._reconnect(ws)
def __init__(self, ws_url: str, *, name: str = None): super().__init__(daemon=True) self.logger = logging.getLogger(name or self.__class__.__name__) self._ws = WebSocketApp(url=ws_url, on_open=self.on_open, on_close=self.on_close, on_message=self.on_message, on_error=self.on_error) self.dom = DOM(command_func=self.command) self.input = Domain(command_func=self.command, name='Input') self.network = Network(command_func=self.command) self.page = Page(command_func=self.command) self.target = Domain(command_func=self.command, name='Target') self._domain_map = { 'DOM': self.dom, 'Input': self.input, 'Network': self.network, 'Page': self.page, 'Target': self.target, } self._seq_no = 0 self._send_command_lock = RLock() self._response_queues = OrderedDict() self._event_handlers = set() # type: Set[EventHandlerBase] self.start()
def _connect(self): self.ws = WebSocketApp(url=self.ws_url, on_open=self._on_open, on_message=self._on_message) self.ws_data = { 'trade.' + str(self.symbol): deque(maxlen=200), 'instrument.' + str(self.symbol): {}, 'order_book_25L1.' + str(self.symbol): pd.DataFrame(), 'position': {}, 'execution': deque(maxlen=200), 'order': deque(maxlen=200) } positions = self.get_position_http()['result'] if positions is None: pass else: for p in positions: if p['data']['symbol'] == self.symbol: self.ws_data['position'].update(p['data']) break Thread(target=self.ws.run_forever, daemon=True).start()
def connect(self): while True: self.error = False self.exception = None self.closed_code = None self.closed_reason = None try: self._app = WebSocketApp( self.url, on_open=self.opened, on_close=self.closed, on_error=self.errored, on_message=self.received_message ) self._app.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) except: if not self.server_restarted(): raise finally: self._app = None if self.server_restarted(): # Instead of trying to reconnect in a retry loop with backoff, run an # API call that will do the same and block while it retries. logger.warn("Server restart, reconnecting...") time.sleep(1) dxpy.describe(self.job_id) else: break
class LobbySocket: def __init__(self, cookie): self.lobby_socket = None self.cookie = cookie pass @staticmethod def on_open(ws): def run(*args): while (True): pass thread.start_new_thread(run, ()) def open_lobby(self): def on_recive(ws, message): message = json.loads(message) self.handle(message) pass self.lobby_socket = WebSocketApp("ws://localhost:8080/lobby", cookie=self.cookie, on_message=on_recive) self.lobby_socket.on_open = self.on_open self.lobby_socket.run_forever() def handle(self, message): print(message) pass
def __init__(self, api_key: str, api_secret: str, logger=None, debug=False): self._api_key = api_key self._api_secret = api_secret self._handlers = {} if logger is None: self.logger = logging.getLogger('WebsocketClient') stream_handler = logging.StreamHandler() formatter = logging.Formatter( fmt='%(asctime)s: %(levelname)s: %(message)s') stream_handler.setFormatter(formatter) self.logger.addHandler(stream_handler) self.logger.setLevel(logging.INFO if not debug else logging.DEBUG) else: if isinstance(logger, Logger): self.logger = logger else: raise ValueError( f'logger must be instance of logging.Logger, got {type(logger)}' ) self._wsa = WebSocketApp(self._CW_WEBSOCKET_ENDPOINT, on_open=self._on_open, on_message=self._on_message, on_error=self._on_error, on_close=self._on_close)
class Publisher(): def __init__(self): self._endpoint = None self._wsserver = None self._wsclient = None def bind(self, endpoint): self._endpoint = endpoint class WampApplication(WebSocketApplication): protocol_class = WampProtocol def on_open(self): wamp = self.protocol wamp.register_pubsub('http://topic1') ep = urlparse(self._endpoint) resource = Resource({'^%s$' % ep.path: WampApplication}) self._wsserver = WebSocketServer(ep.netloc, resource, debug=True) gevent.spawn(self._wsserver.serve_forever) self._wsclient = WebSocketClient(self._endpoint) gevent.spawn(self._wsclient.run_forever) def publish(self, topic, message): data = json.dumps([WampProtocol.MSG_PUBLISH, topic, message]) print data self._wsclient.send(data)
def _create_socket(self): self._websocket = WebSocketApp( self._aggregator_url + "?connectionType=service", header={"combilog-service-secret": self._service_secret}, on_close=self._generate_on_close(), on_open=self._generate_on_open(), on_error=self._generate_on_error(), )
def open_game(self): def on_recive(ws,message): message = json.loads(message) self.handle(message) pass self.game_socket = WebSocketApp("ws://localhost:8080/game",cookie=self.cookie, on_message=on_recive) self.game_socket.on_open = self.on_open self.game_socket.run_forever()
def start(self): "Start websocket" log.info("Starting websocket") self.ws = WebSocketApp(self.server, [], self.cb_on_open, self.cb_on_message, self.cb_on_error, self.cb_on_close) self.ws.run_forever()
def _run_websocket(self, ws: WebSocketApp) -> None: try: ws.on_open = self._wrap_callback(self._on_ws_open_callback) ws.run_forever(origin=self.ws_origin) except Exception as e: raise Exception(f'Unexpected error while running websocket: {e}') finally: self._reconnect(ws)
def on_connect(): #enableTrace(True) ws = WebSocketApp(SERVER_REMOTE_ADDRESS, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) ws.run_forever()
def connect_websocket(): ws = WebSocketApp("wss://api.upbit.com/websocket/v1", on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) start = time.time() ws.run_forever()
def main(): """Main function.""" ws = WebSocketApp(URL, on_open=on_open, on_message=on_message) ws.run_forever(sslopt={ "cert_reqs": ssl.CERT_NONE, "check_hostname": False }) print
class SessionWebSocket(Thread): sessions = {} def __init__(self, name, url): super(SessionWebSocket, self).__init__() if SessionWebSocket.sessions.get(url): raise DuplicatedSessionError("A session with " "this urls is already created!") SessionWebSocket.sessions[url] = self self.name = name self.url = url self.ws = None self.ignore_next_update = False def set_ws(self): self.ws = WebSocketApp(self.url, on_message=self.on_message, on_error=self.on_error) def run(self): while True: self.set_ws() self.ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) @classmethod def get_sws(cls, url): sws: SessionWebSocket = SessionWebSocket.sessions.get(url) if sws is None: raise SessionWebSocketNotFoundError(f'A SWS with the url {url} ' f'was not found!') return sws @staticmethod def on_message(ws: WebSocketApp, msg): sws: SessionWebSocket = SessionWebSocket.get_sws(ws.url) if not sws.ignore_next_update: msg = UpdateMessage.from_msg(sws.name, msg) logger.info(f'SessionUpdateMessage received from {msg.sws_name}') JackBot.instance().send_message(f'{msg}', parse_mode='HTML') else: sws.ignore_next_update = False @staticmethod def on_error(ws, error: Exception): sws: SessionWebSocket = SessionWebSocket.get_sws(ws.url) sws.ignore_next_update = True logger.warning(error) @classmethod def start_all(cls): for session in cls.sessions.values(): session.start() @classmethod def join_all(cls): for session in cls.sessions.values(): session.join()
def crawl_start(self, url, ws_headers): enableTrace(False) # 参数是True时,会显示发送的msg ws = WebSocketApp(url=url, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close, header=ws_headers) ws.on_open = self.on_open ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) # 忽略认证
def main(): sleep(0.5) url = 'ws://127.0.0.1:8181/core' print('Starting client on:', url) client = WebSocketApp(url=url, on_message=on_message) if mock: Thread(target=run_wifi_setup, args=[client, {}], daemon=True).start() client.run_forever() print('Client stopped.')
class ModelStateAdapter(Thread): msg_size_len = 10 msg_size_fmt = '{:0%d}' % msg_size_len def __init__(self, key, port): super(ModelStateAdapter, self).__init__() self.daemon = True self.key = key self.port = port self.read_fd, self.write_fd = os.pipe() def _send(self, msg): os.write(self.write_fd, self.msg_size_fmt.format(len(msg))) os.write(self.write_fd, msg) def stop(self): self.socket.close() def recv(self): msg_size = int(os.read(self.read_fd, self.msg_size_len)) return loads(os.read(self.read_fd, msg_size)) def authenticate(self, key, nonce): logging.debug('authenticating...') mac = hmac.new(str(key), str(nonce)).digest().encode('hex') self.socket.send(dumps({ 'msg': 'auth_response', 'mac': mac, })) def request_state(self, active_tag): logging.debug('requesting state...') self.socket.send(dumps({ 'msg': 'request_state', 'tag': active_tag, })) def push_commands(self, cmds): logging.debug('pushing commands...') self.socket.send(dumps({ 'msg': 'push_commands', 'cmds': map(str, cmds), })) def _on_message(self, socket, message): self._send(message) def run(self): self.socket = WebSocketApp( 'ws://127.0.0.1:{}/gtd'.format(self.port), on_message=self._on_message) self.socket.run_forever()
class WebSocketService(): def __init__( self, url, onMessage ): def runWS( service ): service._wsapp.run_forever() self._wsapp = WebSocketApp( url, on_message=onMessage ) thread.start_new_thread( runWS, ( self, ) ) def stop( self ): self._wsapp.close()
def __init__(self): super(Firebase, self).__init__() self.sock = WebSocketApp(url='ws://%s.ws' % BASE_URL, on_message=self.msg_handler, on_open=self.connect_handler, on_error=self.err_handler) self.ready = Event() self._rn = 0
def run_socket(self, rpc, process_monitor, push_interval, url, token): while True: try: print('WebsocketManager.run_socket: create_connection') WebSocketConnection.process_monitor = process_monitor WebSocketConnection.push_interval = push_interval WebSocketConnection.rpc = rpc ws = WebSocketApp('{0}/supervisor/'.format(url.strip('/')), header=['authorization: {0}'.format(token)], on_message=WebSocketConnection.on_message, on_error=WebSocketConnection.on_error, on_open=WebSocketConnection.on_open, on_close=WebSocketConnection.on_close) ws.run_forever() except Exception as e: print("Exception: %s" % e) time.sleep(60) # Wait 60 seconds before attemping to reconnect
def start(self): self.ws_url = "ws://%s:%s/devtools/page/%s" % (self.host, self.port, self.page_num) self.ws = WebSocketApp(self.ws_url, on_open = self.onOpen, on_message = self.onMessage, on_error = self.onError, on_close = self.onClose, ipv6 = self.ios) self.ws.run_forever()
def main(server, key): for i in range(10): sys.stdout.write('Connecting... \r') sys.stdout.flush() try: ws = WebSocketApp(server, on_message=on_message, on_error=on_error, on_close=on_close, on_open=wrapper(key)) ws.run_forever(ping_interval=15) except KeyboardInterrupt: break except: pass time.sleep(i * 1.5 + 1.5) else: click.echo(click.style('Failed to reconnect.', fg='red')) os._exit(1)
def try_connect(self) -> None: """Try establish connection with Slack websocket server.""" try: response = self.client.get('rtm.start') if 'url' not in response: raise Exception("url is not in the response. %s" % response) except Exception as e: raise SarahSlackException( "Slack request error on /rtm.start. %s" % e) else: self.ws = WebSocketApp(response['url'], on_message=self.message, on_error=self.on_error, on_open=self.on_open, on_close=self.on_close) self.ws.run_forever()
def bind(self, endpoint): self._endpoint = endpoint class WampApplication(WebSocketApplication): protocol_class = WampProtocol def on_open(self): wamp = self.protocol wamp.register_pubsub('http://topic1') ep = urlparse(self._endpoint) resource = Resource({'^%s$' % ep.path: WampApplication}) self._wsserver = WebSocketServer(ep.netloc, resource, debug=True) gevent.spawn(self._wsserver.serve_forever) self._wsclient = WebSocketClient(self._endpoint) gevent.spawn(self._wsclient.run_forever)
def connect(self) -> None: try: response = self.client.get("rtm.start") except Exception as e: raise SarahSlackException("Slack request error on /rtm.start. %s" % e) else: if "url" not in response: raise SarahSlackException("Slack response did not contain connecting url. %s" % response) self.ws = WebSocketApp( response["url"], on_message=self.message, on_error=self.on_error, on_open=self.on_open, on_close=self.on_close, ) self.ws.run_forever()
class Firebase(Thread): def __init__(self): super(Firebase, self).__init__() self.sock = WebSocketApp(url='ws://%s.ws' % BASE_URL, on_message=self.msg_handler, on_open=self.connect_handler, on_error=self.err_handler) self.ready = Event() self._rn = 0 def run(self): self.sock.run_forever() def connect_handler(self, sock): sock.send(u'version=1') def err_handler(self, exc): print exc def send(self, msg): self.sock.send(msg) @property def rn(self): self._rn = self._rn + 1 return self._rn def listen_to_channel(self, channel): print 'listening to %s' % channel self.send('1') data = { "rn": "%i" % self.rn, "payload": { "action": "listen", "path": channel } } self.send(json.dumps(data)) def close(self): self.sock.close()
def start(self, url, onopen, onclose): self.webSocket = ConnectionManager(url, on_message = self._on_message, on_error = self.print_error, on_close = onclose) self.webSocket.run_forever()
class XSocketsClient(object): def __init__(self, url, onerror = None, onopen = None, onclose = None): super(XSocketsClient, self).__init__() self.onerror = onerror self.onopen = onopen self.subscriptions = Subscriptions() self.webSocket = None self.bind(XSockets.Events.open, self._open_event_handler, opts = {"skip": True}) thread.start_new_thread(self.start, (url, onopen, onclose)) def _open_event_handler(self, data): log.DEBUG(data) data[u"clientType"] = u"RFC6455" self.connection = data self.XSocketsClientStorageGuid = data["StorageGuid"] for sub in self.subscriptions.getAll(): for callback in sub.callbacks: if sub.name and callback.state.get("options", {}).get("skip", False): continue self.trigger(Message( XSockets.Events.pubSub.subscribe, {"Event": sub.name, "Confim": False})) self.dispatchEvent(XSockets.Events.bindings.completed, self.subscriptions.getAll()) if self.onopen: self.onopen() def start(self, url, onopen, onclose): self.webSocket = ConnectionManager(url, on_message = self._on_message, on_error = self.print_error, on_close = onclose) self.webSocket.run_forever() def print_error(self, *args, **kwargs): print args, kwargs def __del__(self, *args): if self.webSocket is not None: self.webSocket.close() def _on_message(self, ws, message): cont = json.loads(message) log.DEBUG(cont) self.dispatchEvent(cont["event"], cont["data"]) if cont["event"] == XSockets.Events.onError: if self.onerror: self.onerror(message) self.dispatchEvent(cont["event"], cont["data"]) def bind(self, event, fn, opts = {}, callback = None): state = { "options": opts, "ready": self.webSocket is not None and self.webSocket.sock is not None, "confim": callback is not None } log.DEBUG("%s - %s" %(event, fn)) if state["ready"]: self.trigger(Message( XSockets.Events.pubSub.subscribe, {"Event": event, "Confim": state["confim"]})) if isinstance(fn, list): for f in fn: self.subscriptions.add(event, f, state) else: self.subscriptions.add(event, fn, state) return self on = bind subscribe = bind def trigger(self, event, json = {}, callback = None): if isinstance(event, Message): message = event else: event = event.lower() message = Message(event, json) log.DEBUG(message.to_json()) self.webSocket.send(message.to_json()) if callback is not None: callback() return self publish = trigger emit = trigger def dispatchEvent(self, event, message): if self.subscriptions.get(event) is None: return self.subscriptions.fire(event, json.loads(message)) def send(self, data, event): mes = Message(event, data) log.DEBUG(mes.to_json()) self.webSocket.send(mes.to_json())
class Slack(Base): def __init__(self, token: str = "", plugins: Sequence[PluginConfig] = None, max_workers: int = None) -> None: super().__init__(plugins=plugins, max_workers=max_workers) self.client = self.setup_client(token=token) self.message_id = 0 self.ws = None def setup_client(self, token: str) -> SlackClient: return SlackClient(token=token) def connect(self) -> None: try: response = self.client.get("rtm.start") except Exception as e: raise SarahSlackException("Slack request error on /rtm.start. %s" % e) else: if "url" not in response: raise SarahSlackException("Slack response did not contain connecting url. %s" % response) self.ws = WebSocketApp( response["url"], on_message=self.message, on_error=self.on_error, on_open=self.on_open, on_close=self.on_close, ) self.ws.run_forever() def add_schedule_job(self, command: Command) -> None: if "channels" not in command.config: logging.warning("Missing channels configuration for schedule job. %s. " "Skipping." % command.module_name) return def job_function() -> None: ret = command.execute() if isinstance(ret, SlackMessage): for channel in command.config["channels"]: # TODO Error handling data = dict({"channel": channel}) data.update(ret.to_request_params()) self.client.post("chat.postMessage", data=data) else: for channel in command.config["channels"]: self.enqueue_sending_message(self.send_message, channel, str(ret)) job_id = "%s.%s" % (command.module_name, command.name) logging.info("Add schedule %s" % id) self.scheduler.add_job(job_function, "interval", id=job_id, minutes=command.config.get("interval", 5)) @concurrent def message(self, _: WebSocketApp, event: str) -> None: decoded_event = json.loads(event) if "ok" in decoded_event and "reply_to" in decoded_event: # https://api.slack.com/rtm#sending_messages # Replies to messages sent by clients will always contain two # properties: a boolean ok indicating whether they succeeded and # an integer reply_to indicating which message they are in response # to. if decoded_event["ok"] is False: # Something went wrong with the previous message logging.error( "Something went wrong with the previous message. " "message_id: %d. error: %s" % (decoded_event["reply_to"], decoded_event["error"]) ) return # TODO organize type_map = { "hello": { "method": self.handle_hello, "description": "The client has successfully connected " "to the server", }, "message": {"method": self.handle_message, "description": "A message was sent to a channel"}, "user_typing": {"description": "A channel member is typing a " "message"}, } if "type" not in decoded_event: # https://api.slack.com/rtm#events # Every event has a type property which describes the type of # event. logging.error("Given event doesn't have type property. %s" % event) return if decoded_event["type"] not in type_map: logging.error("Unknown type value is given. %s" % event) return logging.debug( "%s: %s. %s" % (decoded_event["type"], type_map[decoded_event["type"]].get("description", "NO DESCRIPTION"), event) ) if "method" in type_map[decoded_event["type"]]: type_map[decoded_event["type"]]["method"](decoded_event) return def handle_hello(self, _: Dict) -> None: logging.info("Successfully connected to the server.") def handle_message(self, content: Dict) -> Optional[Future]: # content # { # "type":"message", # "channel":"C06TXXXX", # "user":"******", # "text":".bmw", # "ts":"1438477080.000004", # "team":"T06TXXXXX" # } required_props = ("type", "channel", "user", "text", "ts") missing_props = [p for p in required_props if p not in content] if missing_props: logging.error("Malformed event is given. Missing %s. %s" % (", ".join(missing_props), content)) return ret = self.respond(content["user"], content["text"]) if isinstance(ret, SlackMessage): # TODO Error handling data = dict({"channel": content["channel"]}) data.update(ret.to_request_params()) self.client.post("chat.postMessage", data=data) elif isinstance(ret, str): return self.enqueue_sending_message(self.send_message, content["channel"], ret) def on_error(self, _: WebSocketApp, error) -> None: logging.error(error) def on_open(self, _: WebSocketApp) -> None: logging.info("connected") def on_close(self, _: WebSocketApp) -> None: logging.info("closed") def send_message(self, channel: str, text: str, message_type: str = "message") -> None: params = {"channel": channel, "text": text, "type": message_type, "id": self.next_message_id()} self.ws.send(json.dumps(params)) def next_message_id(self) -> int: # https://api.slack.com/rtm#sending_messages # Every event should have a unique (for that connection) positive # integer ID. All replies to that message will include this ID. self.message_id += 1 return self.message_id def stop(self) -> None: super().stop() logging.info("STOP SLACK INTEGRATION") self.ws.close()
def connect(self, endpoint): self._endpoint = endpoint self._ws = WebSocketClient(self._endpoint, on_message=self._on_message) gevent.spawn(self._ws.run_forever, None, None, 10)
def run(self): self.socket = WebSocketApp( 'ws://127.0.0.1:{}/gtd'.format(self.port), on_message=self._on_message) self.socket.run_forever()
class TracerApp(object): """ Main tracer application. """ def __init__(self, options): self.counter = 0 self.host = options.host self.port = options.port self.ios = options.ios self.page_num = options.page_num self.timeStart = time.mktime(time.localtime()) self.shouldStep = True # If we should try to single step the debugger self._isStepping = False # If we are currently inside stepping self.ws_url = None self.ws = None self._requestDetails = {} # Map of details about a request def showConnectionList(self): """ Print out list of possible debugger connections """ # Mobile safari has a different listing page if self.ios: pages_url = "http://%s:%s/listing.json" % (self.host, self.port) else: pages_url = "http://%s:%s/json" % (self.host, self.port) pages = urllib2.urlopen(pages_url) pages_data = json.loads(pages.read()) for page in pages_data: print "----------------------------------------------------------" if self.ios: print "Page: ", page.get('pageTitle') print " id: ", page.get('pageId') print " url: ", page.get('pageURL') print " debug url: ", page.get('debugURL') else: print "Page: ", page.get('title', '') print " url: ", page.get('url', '') print " ws_debug_url: ", page.get('webSocketDebuggerUrl', '') def start(self): self.ws_url = "ws://%s:%s/devtools/page/%s" % (self.host, self.port, self.page_num) self.ws = WebSocketApp(self.ws_url, on_open = self.onOpen, on_message = self.onMessage, on_error = self.onError, on_close = self.onClose, ipv6 = self.ios) self.ws.run_forever() def send(self, method, params = None): self.counter += 1 # separators is important, you'll get "Message should be in JSON format." otherwise msg_data = {"id": self.counter, "method": method} if params is not None: msg_data['params'] = params message = json.dumps(msg_data, separators=(',', ':')) print "> %s" % (message,) self.ws.send(message) def recv(self): result = self.ws.recv() print "< %s" % (result,) return result # ---- PRIMARY CALLBACKS ---- # def onOpen(self, ws): #self.send('Runtime.evaluate', {'expression': '1+1'}) #self.send('Runtime.evaluate', {'expression': 'alert("hello from python")'}) #self.send('Timeline.start', {'maxCallStackDepth': 5}) #self.send('Network.enable') #self.send('Console.enable') #self.send('Timeline.start', {'maxCallStackDepth': 5}) self.send('Debugger.enable') def onMessage(self, ws, message): # Decode message into a bunch object to make easier to access attributes # but store original message so we can get to it msg = Bunch.loads(message) msg._rawMsg = json.loads(message) if hasattr(msg, 'result'): self.handleResultMsg(msg) elif hasattr(msg, 'method'): self.handleMethodMsg(msg) else: print "UNKNOWN MSG TYPE: " self.prettyPrintMsg(msg) def onError(self, ws, error): print "error: ", error def onClose(self, ws): print "CLOSED" # --- Helpers ---- # def prettyPrintMsg(self, msg): if type(msg) in types.StringTypes: msg = json.loads(msg) elif type(msg) == Bunch: msg = msg._rawMsg print json.dumps(msg, sort_keys=True, indent=3) # --- MSG Helpers --- # def handleResultMsg(self, msg): print "RESULT: [%s]" % msg.id print json.dumps(msg._rawMsg['result'], sort_keys=True, indent=3) def handleMethodMsg(self, msg): """ Try to map method name to a local handler. get name as: 'handle' + method in camel case and no .'s """ def replace(match): return match.group()[1].upper() method = msg.method handler_name = 'handle' + re.sub('\.\w', replace, method) handler_method = getattr(self, handler_name, self.handleNotificationDefault) handler_method(msg) def handleNotificationDefault(self, msg): """ By default just print the method name. """ print self.getMethodHeader(msg) # --- Console Notification Processing --- # def handleConsoleMessageAdded(self, msg): print self.getMethodHeader(msg) cmsg = msg.params.message print " msg: [%s] %s" % (cmsg.level, cmsg.text) # --- Timeline Notification Processing -- # def handleTimelineEventRecorded(self, msg): record = msg.params.record record_raw = msg._rawMsg.get('params').get('record') print "[%s] ==[ %s:%s ]=====" % ('', #self.getDeltaTsStr(record.endTime), msg.method, record.type) print " mem: %.2f/%.2f MB" % (record.usedHeapSize / (1024.0*1024.0), record.totalHeapSize / (1024.0*1024.0)) if record.has_key('endTime'): print " duration: ", (record.endTime - record.startTime) print " data: ", json.dumps(record_raw.get('data'), indent = 2) #print " children: ", json.dumps(record_raw.get('children'), indent = 2) # --- Network Notification Processing --- # def handleNetworkDataReceived(self, msg): print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) print " dataLen: ", msg.params.dataLength def handleNetworkLoadingFailed(self, msg): print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) print " error: ", msg.params.errorText def handleNetworkLoadingFinished(self, msg): print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) def handleNetworkRequestServedFromCache(self, msg): print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) def handleNetworkRequestServedFromMemoryCache(self, msg): print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) print " url: ", msg.params.documentURL def handleNetworkRequestWillBeSent(self, msg): request_id = msg.params.get_first('requestId', 'identifier') self._requestDetails[request_id] = Bunch(requestId = request_id, request = msg.params.request, loaderId = msg.params.loaderId, documentUrl = msg.params.documentURL, startTs = msg.params.timestamp, initiator = msg.params.get('initiator', None), stack = msg.params.stackTrace) print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) print " url: ", msg.params.documentURL def handleNetworkResponseReceived(self, msg): resp = msg.params.response print self.getMethodHeader(msg) print " request: ", self.getRequestSummary(msg) print " type: ", msg.params.type print " reused: ", resp.connectionReused print " from disk: ", resp.fromDiskCache print " mime: ", resp.mimeType print " status: [%s] %s" % (resp.status, resp.statusText) def handleDebuggerDebuggerWasEnabled(self, msg): print self.getMethodHeader(msg) if self.shouldStep: self.send('Debugger.pause') # self.send('Debugger.stepInto') # self._isStepping = True def handleDebuggerPaused(self, msg): print self.getMethodHeader(msg) print " reason: ", msg.params.reason params_raw = msg._rawMsg.get('params') print " data: ", json.dumps(params_raw.get('data'), indent = 2) print " frame: ", json.dumps(params_raw.get('callFrames'), indent = 2) if self.shouldStep: self.send('Debugger.stepInto') def handleDebuggerResumed(self, msg): print self.getMethodHeader(msg) def handleDebuggerScriptParsed(self, msg): print self.getMethodHeader(msg) print json.dumps(msg._rawMsg.get('params'), indent = 2) # ---- Helpers ---- # def getMethodHeader(self, msg): return "[%s] ==[ %s ]=====" % (self.getTS(msg), msg.method) def getRequestSummary(self, msg): request_id = msg.params.get_first('requestId', 'identifier') req_record = self._requestDetails.get(request_id, None) if req_record: return "[%s] %s" % (request_id, req_record.request.url) else: return "[%s] {unknown}" % request_id def getTS(self, msg): """ Returns a timestamp string to use as prefix """ ts_value = None if hasattr(msg, 'params'): ts_value = msg.params.get('timestamp', None) if ts_value is None: return '<nots>' else: return self.getDeltaTsStr(ts_value) def getDeltaTsStr(self, ts): ts_delta = ts - self.timeStart return "%8.4f" % ts_delta
class Slack(Base): """Provide bot for Slack.""" def __init__(self, token: str = '', plugins: Iterable[PluginConfig] = None, max_workers: int = None) -> None: """Initializer. :param token: Access token provided by Slack. :param plugins: List of plugin modules. :param max_workers: Optional number of worker threads. :return: None """ super().__init__(plugins=plugins, max_workers=max_workers) self.client = self.setup_client(token=token) self.message_id = 0 self.ws = None # type: WebSocketApp self.connect_attempt_count = 0 def setup_client(self, token: str) -> SlackClient: """Setup ClackClient and return its instance. :param token: Slack access token. :return: SlackClient instance """ return SlackClient(token=token) def connect(self) -> None: """Connect to Slack websocket server and start interaction. :return: None """ while self.connect_attempt_count < 10: try: self.connect_attempt_count += 1 self.try_connect() except KeyboardInterrupt: break except Exception as e: logging.error(e) time.sleep(self.connect_attempt_count) else: logging.error("Attempted 10 times, but all failed. Quitting.") def try_connect(self) -> None: """Try establish connection with Slack websocket server.""" try: response = self.client.get('rtm.start') if 'url' not in response: raise Exception("url is not in the response. %s" % response) except Exception as e: raise SarahSlackException( "Slack request error on /rtm.start. %s" % e) else: self.ws = WebSocketApp(response['url'], on_message=self.message, on_error=self.on_error, on_open=self.on_open, on_close=self.on_close) self.ws.run_forever() def generate_schedule_job(self, command: ScheduledCommand) \ -> Optional[Callable[..., None]]: """Generate callback function to be registered to scheduler. This creates a function that execute given command and then handle the command response. If the response is SlackMessage instance, it make HTTP POST request to Slack web API endpoint. If string is returned, then it submit it to the message sending worker. :param command: ScheduledCommand object that holds job information :return: Optional callable object to be scheduled """ channels = command.schedule_config.pop('channels', []) if not channels: logging.warning( 'Missing channels configuration for schedule job. %s. ' 'Skipping.' % command.module_name) return None def job_function() -> None: ret = command() if isinstance(ret, SlackMessage): for channel in channels: # TODO Error handling data = {'channel': channel} data.update(ret.to_request_params()) self.client.post('chat.postMessage', data=data) else: for channel in channels: self.enqueue_sending_message(self.send_message, channel, str(ret)) return job_function @concurrent def message(self, _: WebSocketApp, event: str) -> None: """Receive event from Slack and dispatch it to corresponding method. :param _: WebSocketApp instance. This is not to be used here. :param event: JSON string that contains event information. :return: None """ decoded_event = json.loads(event) if 'ok' in decoded_event and 'reply_to' in decoded_event: # https://api.slack.com/rtm#sending_messages # Replies to messages sent by clients will always contain two # properties: a boolean ok indicating whether they succeeded and # an integer reply_to indicating which message they are in response # to. if decoded_event['ok'] is False: # Something went wrong with the previous message logging.error( 'Something went wrong with the previous message. ' 'message_id: %s. error: %s' % ( decoded_event['reply_to'], decoded_event.get('error', ""))) return None # TODO organize type_map = { 'hello': { 'method': self.handle_hello, 'description': "The client has successfully connected to the " "server"}, 'message': { 'method': self.handle_message, 'description': "A message was sent to a channel"}, 'user_typing': { 'description': "A channel member is typing a message"}, 'presence_change': { 'description': "A team member's presence changed"}, 'team_migration_started': { 'method': self.handle_team_migration, 'description': "The team is being migrated between servers"} } # type: EventTypeMap if 'type' not in decoded_event: # https://api.slack.com/rtm#events # Every event has a type property which describes the type of # event. logging.error("Given event doesn't have type property. %s" % event) return None if decoded_event['type'] not in type_map: logging.error('Unknown type value is given. %s' % event) return None logging.debug( '%s: %s. %s' % ( decoded_event['type'], type_map[decoded_event['type']].get('description', 'NO DESCRIPTION'), event)) method = type_map[decoded_event['type']].get('method', None) if method: method(decoded_event) return None def handle_hello(self, _: Dict) -> None: """Handle hello event. This is called when connection is established. :param _: Dictionary that represent event. This is not used here. :return: None """ self.connect_attempt_count = 0 # Reset retry count logging.info('Successfully connected to the server.') def handle_message(self, content: Dict) -> Optional[Future]: """Handle message event. :param content: Dictionary that represent event. :return: Optional Future instance that represent message sending result. """ # content # { # "type":"message", # "channel":"C06TXXXX", # "user":"******", # "text":".bmw", # "ts":"1438477080.000004", # "team":"T06TXXXXX" # } required_props = ('type', 'channel', 'user', 'text', 'ts') missing_props = [p for p in required_props if p not in content] if missing_props: logging.error('Malformed event is given. Missing %s. %s' % ( ', '.join(missing_props), content)) return None ret = self.respond(content['user'], content['text']) if isinstance(ret, SlackMessage): # TODO Error handling data = {'channel': content["channel"]} data.update(ret.to_request_params()) self.client.post('chat.postMessage', data=data) return None elif isinstance(ret, str): return self.enqueue_sending_message(self.send_message, content['channel'], ret) def handle_team_migration(self, _: Dict) -> None: """Handle team_migration_started event. https://api.slack.com/events/team_migration_started "When clients recieve this event they can immediately start a reconnection process by calling rtm.start again." :param _: Dictionary that represent event. :return: None """ logging.info("Team migration started.") def on_error(self, _: WebSocketApp, error: Exception) -> None: """Callback method called by WebSocketApp when error occurred. :param _: WebSocketApp instance that is not currently used. :param error: Exception instance :return: None """ logging.error("error %s", error) def on_open(self, _: WebSocketApp) -> None: """Callback method called by WebSocketApp on connection establishment. :param _: WebSocketApp instance that is not currently used. :return: None """ logging.info('connected') def on_close(self, _: WebSocketApp, code: int, reason: str) -> None: """Callback method called by WebSocketApp when connection is closed. :param _: WebSocketApp instance that is not currently used. :param code: Closing code described in RFC6455. https://tools.ietf.org/html/rfc6455#section-7.4 :param reason: Closing reason. :return: None """ logging.info('connection closed. code: %d. reason: %s', code, reason) def send_message(self, channel: str, text: str, message_type: str = 'message') -> None: """Send message to Slack via websocket connection. :param channel: Target channel to send message. :param text: Sending text. :param message_type: Message type. Default is "message." :return: None """ params = {'channel': channel, 'text': text, 'type': message_type, 'id': self.next_message_id()} self.ws.send(json.dumps(params)) def next_message_id(self) -> int: """Return unique ID for sending message. https://api.slack.com/rtm#sending_messages Every event should have a unique (for that connection) positive integer ID. All replies to that message will include this ID. :return: Unique ID as int """ self.message_id += 1 return self.message_id
def on_open(ws): #send('Runtime.evaluate', {'expression': '1+1'}) #send('Runtime.evaluate', {'expression': 'alert("hello from python")'}) #send('Timeline.start', {'maxCallStackDepth': 5}) send('Network.enable') gCounter = 0 def send(method, params = None): global gCounter gCounter += 1 # separators is important, you'll get "Message should be in JSON format." otherwise msg_data = {"id": gCounter, "method": method} if params is not None: msg_data['params'] = params message = json.dumps(msg_data, separators=(',', ':')) print "> %s" % (message,) ws.send(message) def recv(): result = ws.recv() print "< %s" % (result,) ws = WebSocketApp(ws_url, on_open = on_open, on_message = on_message, on_error = on_error, on_close = on_close) ws.run_forever()
class DXJobLogStreamClient: def __init__( self, job_id, input_params=None, msg_output_format="{job} {level} {msg}", msg_callback=None, print_job_info=True ): self.job_id = job_id self.input_params = input_params self.msg_output_format = msg_output_format self.msg_callback = msg_callback self.print_job_info = print_job_info self.seen_jobs = {} self.error = False self.exception = None self.closed_code = None self.closed_reason = None self.url = "{protocol}://{host}:{port}/{job_id}/getLog/websocket".format( protocol='wss' if dxpy.APISERVER_PROTOCOL == 'https' else 'ws', host=dxpy.APISERVER_HOST, port=dxpy.APISERVER_PORT, job_id=job_id ) self._app = None def connect(self): while True: self.error = False self.exception = None self.closed_code = None self.closed_reason = None try: self._app = WebSocketApp( self.url, on_open=self.opened, on_close=self.closed, on_error=self.errored, on_message=self.received_message ) self._app.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) except: if not self.server_restarted(): raise finally: self._app = None if self.server_restarted(): # Instead of trying to reconnect in a retry loop with backoff, run an # API call that will do the same and block while it retries. logger.warn("Server restart, reconnecting...") time.sleep(1) dxpy.describe(self.job_id) else: break def server_restarted(self): return ( self.closed_code == 1001 and self.closed_reason == "Server restart, please reconnect later" ) def opened(self): args = { "access_token": dxpy.SECURITY_CONTEXT['auth_token'], "token_type": dxpy.SECURITY_CONTEXT['auth_token_type'] } if self.input_params: args.update(self.input_params) self._app.send(json.dumps(args)) def errored(self, exception=None): self.error = True self.exception = exception def closed(self, code=None, reason=None): if code: self.closed_code = code self.closed_reason = reason elif not self.error: self.closed_code = 1000 self.closed_reason = "Normal" elif self.exception and type(self.exception) in {KeyboardInterrupt, SystemExit}: self.closed_code = 1000 self.closed_reason = "Connection terminated by client" else: self.closed_code = 1006 self.closed_reason = str(self.exception) if self.exception else "Abnormal" if self.closed_code != 1000: try: error = json.loads(self.closed_reason) raise DXJobLogStreamingException( "Error while streaming job logs: {type}: {message}\n".format( **error ) ) except (KeyError, ValueError): raise DXJobLogStreamingException( "Error while streaming job logs: {code}: {reason}\n".format( code=self.closed_code, reason=self.closed_reason ) ) elif self.print_job_info: if self.job_id not in self.seen_jobs: self.seen_jobs[self.job_id] = {} for job_id in self.seen_jobs.keys(): self.seen_jobs[job_id] = dxpy.describe(job_id) print( get_find_executions_string( self.seen_jobs[job_id], has_children=False, show_outputs=True ) ) else: self.seen_jobs[self.job_id] = dxpy.describe(self.job_id) if self.seen_jobs[self.job_id].get('state') in {'failed', 'terminated'}: err_exit(code=3) def received_message(self, message): message_dict = json.loads(message) if ( self.print_job_info and 'job' in message_dict and message_dict['job'] not in self.seen_jobs ): self.seen_jobs[message_dict['job']] = dxpy.describe(message_dict['job']) print( get_find_executions_string( self.seen_jobs[message_dict['job']], has_children=False, show_outputs=False ) ) if ( message_dict.get('source') == 'SYSTEM' and message_dict.get('msg') == 'END_LOG' ): self._app.keep_running = False elif self.msg_callback: self.msg_callback(message_dict) else: print(self.msg_output_format.format(**message_dict))
class Client(object): def __init__(self, server, token=""): "Initialize" self.server = server self.token = token self.callbacks = {} self.ws = None def send(self, path, value): "Send msg (a dict) to the server" msg = {"key": self.token} set_value(msg, path, value) if not self.ws: return self.ws.send(json.dumps(msg)) def start(self): "Start websocket" log.info("Starting websocket") self.ws = WebSocketApp(self.server, [], self.cb_on_open, self.cb_on_message, self.cb_on_error, self.cb_on_close) self.ws.run_forever() def on_message(self, path): "Decore a funcion to make it a callback" def decorator(f): self.callbacks[path] = f return decorator def cb_on_message(self, ws, message): "Dispatch messages to callbacks" for path in self.callbacks: value = get_value(json.loads(message), path) if value != {}: self.callbacks[path](value) def cb_on_error(self, ws, error): "Restart websocket" log.error("Error: %s", error) time.sleep(1) log.info("Reconnecting...") self.start() def cb_on_close(self, ws): "On connection close, cleanup things" log.info("Connection closed") def cb_on_open(self, ws): "Send empty jsons to keep alive the connection, on an separate thread" def channel(): while True: ws.send("{}") # ping to avoid timeout time.sleep(15) Thread(target=channel).start()
class Subscriber(): def __init__(self): self._endpoint = None # we actually just use the constant definitions self._wamp = WampProtocol(None) self._ws = None self._session_id = None self._handlers_table = {'': set()} self._received = list() def connect(self, endpoint): self._endpoint = endpoint self._ws = WebSocketClient(self._endpoint, on_message=self._on_message) gevent.spawn(self._ws.run_forever, None, None, 10) def subscribe(self, topic, handler): #self._ws.send(json.dumps([self._wamp.MSG_PREFIX, topic.split(':')[0], topic])) self._ws.send(json.dumps([self._wamp.MSG_SUBSCRIBE, topic])) # TODO wait for SUBSCRIBED if handler: self._add_handler(topic, handler) def unsubscribe(self, topic): self._ws.send([self._wamp.MSG_UNSUBSCRIBE, topic]) # TODO wait for UNSUBSCRIBED return self._handlers_table.pop(topic, set()) def receive(self): return self._received.pop(0) def run(self): self._ws = WebSocketClient(self._endpoint, on_message=self._on_message) gevent.spawn(self._receiver) gevent.spawn(self._ws.run_forever, None, None, 10) def _receiver(self): while True: topic, message = self.receive() handlers = self._handlers_table.get(topic, set()) for handler in handlers: handler(topic, message) def _on_message(self, sock, msg): data = json.loads(msg) if data[0] == self._wamp.MSG_WELCOME and len(data) > 1: self._session_id = data[1] elif data[0] == self._wamp.MSG_EVENT and len(data) >= 3: topic, message = data[1], data[2] # TODO list length limit self.received.append((topic, message)) else: raise Exception('Unexpected message received') def _add_handler(self, topic, handler): def _add_topic_handler(topic, handler): handlers = self._handlers_table.get(topic, set()) handlers |= set([handler]) self._handlers_table[topic] = handlers if callable(handler): if topic == '': for tpc in self._handlers_table.keys(): _add_topic_handler(tpc, handler) else: _add_topic_handler(topic, handler) else: raise ValueError('invalid handler')
def run(self): self._ws = WebSocketClient(self._endpoint, on_message=self._on_message) gevent.spawn(self._receiver) gevent.spawn(self._ws.run_forever, None, None, 10)