Exemple #1
0
class WebSocketThread(Thread):
    """Websocket thread."""
    def __init__(self, url, client, on_startup=None):
        super().__init__()
        self.ws = WebSocket(url)
        self._client = weakref.ref(client)
        self.on_startup = on_startup or (lambda: None)
        self.running = False
        self.ready_event = Event()
        self.error = None
        self.daemon = True

    @property
    def client(self):
        return self._client()

    def run(self):
        """Main thread loop."""
        try:
            with self.ws:
                for event in self.ws:
                    if event.name == 'rejected':
                        self.error = event.reason
                    elif event.name == 'disconnected':
                        if not event.graceful:
                            self.error = event.reason
                    elif event.name == 'ready':
                        self.running = True
                        self.on_startup()
                        self.ready_event.set()
                    elif event.name == 'binary':
                        self.on_binary(event.data)
        except Exception:
            log.exception('error in m2m thread')
        finally:
            self.running = False
            self.ready_event.set()

    def on_binary(self, data):
        """Called with a binary message."""
        if not self.client:
            log.warning('ws message %r ignored', data)
            return
        try:
            packet = M2MPacket.from_bytes(data)
        except PacketFormatError as packet_error:
            # We received a badly formatted packet from the server
            # Inconceivable!
            log.warning('bad packet (%s)', packet_error)
        else:
            log.debug(' <- %r', packet)
            self.client.dispatcher.dispatch_packet(packet)

    def send(self, data):
        """Send binary message (low level interface)."""
        self.ws.send_binary(data)

    def close(self):
        """Close the websocket."""
        self.ws.close()
Exemple #2
0
async def websocket_handler(uri, headers):
    websocket = WebSocket(uri)
    for header, value in headers.items():
        websocket.add_header(str.encode(header), str.encode(value))

    for msg in websocket.connect(ping_rate=5):
        if msg.name == "text":
            message = msg.text
            message = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", message)

            message_data = json.loads(message)
            logging.info(str(message_data).encode("utf-8"))

            if "error" in message_data and message_data["error"] == "Auth not valid":
                logging.info(message_data)
                raise RuntimeError("Connection settings invalid")
            elif message_data["type"] != "interaction":
                logging.info(message_data)
                if message_data["type"] == "question":
                    question_str = unidecode(message_data["question"])
                    answers = [unidecode(ans["text"]) for ans in message_data["answers"]]
                    print("\n" * 5)
                    print("Question detected.")
                    print(f"Question {message_data['questionNumber']} out of {message_data['questionCount']}")
                    print(f"{Fore.CYAN}{question_str}\n{answers}{Style.RESET_ALL}")
                    print()
                    await question.answer_question(question_str, answers, message_data['questionNumber'],{message_data['questionCount']})

    print("Socket closed")
    def __init__(self,
                 manager,
                 url,
                 uuid=None,
                 channel_callback=None,
                 control_callback=None,
                 **kwargs):
        super(WSClient, self).__init__()
        self.manager = manager
        self.url = url
        _user_agent = "Agent/{} {}".format(__version__, LOMOND_USER_AGENT)
        self.websocket = WebSocket(url, agent=_user_agent)
        self.channel_callback = channel_callback
        self.control_callback = control_callback

        self._closed = False
        self.identity = uuid
        self.channels = {}
        self.last_packet_time = time.time()

        self.callback_lock = threading.RLock()
        self.write_lock = threading.Lock()
        self.callbacks = defaultdict(list)
        self.hooks = defaultdict(list)

        self.dispatcher = Dispatcher(packet_cls=Packet,
                                     handler_instance=self,
                                     log=log)

        self.name = "m2m"  # Thread name
        self.daemon = True
Exemple #4
0
class WsClient(threading.Thread):
    """
    Web Socket Client
    Establishes a persistent WSS client that launches a separate thread to handle WSS operations.
    Spools incoming messages to the q_rx Queue, and sends any messages placed into the q_tx Queue.
    """
    def __init__(self, cfg, q):
        """
        Class Initializer
        :param cfg: {dict} Emulator's configuration dictionary
        :param q: {Queue} WSS RX/TX Message Queue
        """
        self.q_rx = q['rx']
        self.q_tx = q['tx']
        self.stop = False
        self.ready = False
        self.ws = WebSocket(url=cfg['SERVICE.STATUS_SERVICE_URL'] + '/' +
                            cfg['SESSION.WS_TOKEN'],
                            protocols=['glowforge'],
                            agent=cfg['SESSION.USER_AGENT'])
        self.ignore_events = [
            'ping', 'pong', 'poll', 'connecting', 'connected'
        ]
        threading.Thread.__init__(self)

    def run(self):
        """
        Thread loop
        Listens for WS messages, and adds them the q_rx Queue.
        Monitors the q_tx, and sends any messages it finds.
        Handles PING, PONG, and POLL messages.
        :return:
        """
        for event in persist(self.ws):
            logging.info('RX-EVENT: ' + event.name)
            logging.debug(event)
            if self.stop:
                logging.info('STOP REQUESTED')
                break
            # WS reporting session is established
            if event.name == 'ready':
                self.ready = True
            # Service has sent us a text message
            elif event.name == 'text':
                logging.debug(event.text)
                self.q_rx.put(event.text)
            elif event.name not in self.ignore_events:
                logging.error('UNKNOWN RX-EVENT: ' + event.name)
            while self.ready:
                if not self.q_tx.empty():
                    send_msg = self.q_tx.get()
                    logging.info('TX-EVENT: ' + send_msg)
                    self.ws.send_text(send_msg)
                    self.q_tx.task_done()
                else:
                    break
        logging.info('CLOSING')
        self.ws.close()
Exemple #5
0
 def __init__(self, url, client, on_startup=None):
     super().__init__()
     self.ws = WebSocket(url)
     self._client = weakref.ref(client)
     self.on_startup = on_startup or (lambda: None)
     self.running = False
     self.ready_event = Event()
     self.error = None
     self.daemon = True
Exemple #6
0
async def websocket_lives_handler(uri, bearers, broadid):
    for bearer in bearers:
        headers = {
            "Authorization": "Bearer %s" % bearer,
            "x-hq-client": "Android/1.3.0"
        }
        websocket = WebSocket(uri)
        for header, value in headers.items():
            websocket.add_header(str.encode(header), str.encode(value))
        first = True
        for msg in websocket.connect(ping_rate=5):
            if msg.name == "text":
                message = msg.text
                message = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", message)
                message_data = json.loads(message)

                if "error" in message_data and message_data[
                        "error"] == "Auth not valid":
                    print("Connection settings invalid")

                if first == True:
                    websocket.send_json({
                        "authToken": bearer,
                        "type": "subscribe",
                        "broadcastId": broadid
                    })
                    first = False
                else:
                    websocket.close()
Exemple #7
0
    def mainloop(self):
        input("<press enter>")
        print(TO_STOP_PRESS)
        srv = random.choice(self.SERVERS)
        logger.debug(srv)
        conn = WebSocket(srv)
        corrects = 0
        last_answer = None
        for msg in conn.connect():
            if msg.name == "text":
                a = json.loads(msg.text)
                if a["method"] == "round_question":
                    b = a["params"]["answers"]
                    googler = KleverGoogler(a["params"]["text"], [b[i]["text"] for i in range(4)],
                                            int(time.time()), a["params"]["number"])
                    googler.search()
                    c = googler.genQuestion()
                    last_answer = int(c.best[0])

                    message = QUESTION % (str(c.id), c.question)
                    message += "\n==============================\n"
                    for i in range(4):
                        message += ("[~]" if i + 1 == last_answer else "[ ]") + "Answer " + str(i + 1) + ":" + str(c.answers[i])
                    message += "\n\n==============================\n"
                    print(message)
                    if config["Config"]["debug_mode"] in ("basic", "verbose"):
                        logger.info("Query for custom question:\n" + str(c))
                        logger.info("Optimized question:" + c.optimized)
                    if config["Config"]["answer_ui"] == "on" and config["Social"]["telegram_auto"] == "on" \
                            or config["Social"]["telegram"] == "on":
                        send_to_telegram(message)
                elif a["method"] == "round_result":
                    b = a["params"]
                    c = a["params"]["answers"]
                    message = ANSWER_FOR_QUESTION % (b["number"], b["text"])
                    message += "\n==============================\n"
                    correct = -1
                    for q in c:
                        d = False
                        if q["correct"]:
                            d = True
                            correct = q["number"]
                        message += ("[x]" if d else "[ ]") + ANSWER + " %s: %s" % (q["number"], q["text"]) + "\n"
                    message += "\n=============================="
                    if last_answer == correct:
                        corrects += 1
                    message += BOT_STATUS + (CORRECT if last_answer == correct else INCORRECT) + ", " + \
                               str(corrects) + "/" + str(b["number"])

            elif msg.name == "disconnected":
                print("disconnected")
Exemple #8
0
def copy_to_websocket(
    ws: lomond.WebSocket, f: io.RawIOBase, ready_sem: threading.Semaphore
) -> None:
    ready_sem.acquire()

    try:
        while True:
            chunk = f.read(4096)
            if not chunk:
                break
            ws.send_binary(chunk)
    finally:
        f.close()
        ws.close()
 def test_broken(self):
     """Test server that closes gracefully."""
     ws = WebSocket(self.WS_URL + 'broken')
     events = list(ws.connect(ping_rate=0))
     assert len(events) == 7
     assert events[0].name == 'connecting'
     assert events[1].name == 'connected'
     assert events[2].name == 'ready'
     assert events[3].name == 'poll'
     assert events[4].name == 'text'
     assert events[4].text == u'foo'
     assert events[5].name == 'protocol_error'
     assert not events[5].critical
     assert events[6].name == 'disconnected'
     assert not events[6].graceful
Exemple #10
0
def copy_from_websocket(
    f: io.RawIOBase,
    ws: lomond.WebSocket,
    ready_sem: threading.Semaphore,
    cert_file: Optional[str],
    cert_name: Optional[str],
) -> None:
    try:
        for event in ws.connect(
            ping_rate=0,
            session_class=lambda socket: CustomSSLWebsocketSession(socket, cert_file, cert_name),
        ):
            if isinstance(event, lomond.events.Binary):
                f.write(event.data)
            elif isinstance(event, lomond.events.Ready):
                ready_sem.release()
            elif isinstance(
                event,
                (lomond.events.ConnectFail, lomond.events.Rejected, lomond.events.ProtocolError),
            ):
                raise Exception("Connection failed: {}".format(event))
            elif isinstance(event, (lomond.events.Closing, lomond.events.Disconnected)):
                break
    finally:
        f.close()
Exemple #11
0
def update_report():
    """Tell wstest to update reports."""
    print("Updating reports...")
    qs = urlencode({'agent': USER_AGENT})
    url = server + "/updateReports?{}".format(qs)
    for _ in WebSocket(url):
        pass
 def runWebsocketThread(self):
     attempt = 0
     while self.running:
         if attempt > 0:
             time.sleep(0.25)
         attempt = attempt + 1
         self.websocket = WebSocket(self.uri)
         for event in self.websocket:
             if event.name == 'text':
                 packetObj = None
                 try:
                     packetObj = json.loads(event.text)
                 except:
                     print("Failed parsing a Websocket event as JSON: " + event.text)
                     continue
                 if packetObj == None:
                     print("Got a NULL event for some reason.")
                     continue
                 self.packetsLock.acquire()
                 self.packets.append(packetObj)
                 self.packetsLock.release()
             else:
                 if not self.running:
                     print("Websocket client thread exiting.")
                     return
Exemple #13
0
    def test_non_graceful(self):
        """Test server that closes socket."""
        ws = WebSocket(self.WS_URL + 'non-graceful')
        events = list(ws.connect(ping_rate=0))

        assert len(events) == 7
        assert events[0].name == 'connecting'
        assert events[1].name == 'connected'
        assert events[2].name == 'ready'
        assert events[3].name == 'poll'
        assert events[4].name == 'text'
        assert events[4].text == u'foo'
        assert events[5].name == 'binary'
        assert events[5].data == b'bar'
        assert events[6].name == 'disconnected'
        assert not events[6].graceful
def test_bad_proxy():
    proc = subprocess.Popen(['proxy.py', '--port', '8888'])
    try:
        time.sleep(0.1)
        ws = WebSocket('wss://echo.websocket.org',
                       proxies={'https': 'http://bad.test:8888'})
        events = []
        for event in ws:
            events.append(event)
            if event.name == 'ready':
                ws.close()

        assert len(events) == 2
        assert events[0].name == 'connecting'
        assert events[1].name == 'connect_fail'
    finally:
        os.kill(proc.pid, 3)
    def test_echo_no_pong(self):
        """Test echo server."""
        # No way to disable pongs from tornado, so we will set the
        # ping timeout to so low it couldn't get the pong in time
        ws = WebSocket(self.WS_URL + 'echo')
        events = []
        for event in ws.connect(poll=60, ping_rate=1, auto_pong=False, ping_timeout=0.000001):
            events.append(event)

        assert len(events) == 6
        assert events[0].name == 'connecting'
        assert events[1].name == 'connected'
        assert events[2].name == 'ready'
        assert events[3].name == 'poll'
        assert events[4].name == 'unresponsive'
        assert events[5].name == 'disconnected'
        assert not events[5].graceful
Exemple #16
0
def connect_websocket(socket_url, auth_token):
    headers = {
        "Authorization": f"Bearer {auth_token}",
        "x-hq-client": "iPhone8,2"
    }

    websocket = WebSocket(socket_url)

    for header, value in headers.items():
        websocket.add_header(str.encode(header), str.encode(value))

    for msg in websocket.connect(ping_rate=5):
        if msg.name == "text":
            message = msg.text
            message = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", message)
            message_data = json.loads(message)

            if message_data['type'] == 'question':
                question = message_data['question']
                qcnt = message_data['questionNumber']
                Fullcnt = message_data['questionCount']

                print(f"\nQuestion number {qcnt} out of {Fullcnt}\n{question}")
                #open_browser(question)
                answers = [
                    unidecode(ans["text"]) for ans in message_data["answers"]
                ]
                print(f"\n{answers[0]}\n{answers[1]}\n{answers[2]}\n")
                Google_Search.answer_question(question, answers)

            elif message_data["type"] == "questionSummary":

                answer_counts = {}
                correct = ""
                for answer in message_data["answerCounts"]:
                    ans_str = unidecode(answer["answer"])

                    if answer["correct"]:
                        correct = ans_str
                advancing = message_data['advancingPlayersCount']
                eliminated = message_data['eliminatedPlayersCount']

                print(colored(correct, "blue"))
                print(advancing)
                print(eliminated)
Exemple #17
0
 def __init__(self, cfg, q):
     """
     Class Initializer
     :param cfg: {dict} Emulator's configuration dictionary
     :param q: {Queue} WSS RX/TX Message Queue
     """
     self.q_rx = q['rx']
     self.q_tx = q['tx']
     self.stop = False
     self.ready = False
     self.ws = WebSocket(url=cfg['SERVICE.STATUS_SERVICE_URL'] + '/' +
                         cfg['SESSION.WS_TOKEN'],
                         protocols=['glowforge'],
                         agent=cfg['SESSION.USER_AGENT'])
     self.ignore_events = [
         'ping', 'pong', 'poll', 'connecting', 'connected'
     ]
     threading.Thread.__init__(self)
Exemple #18
0
 def __init__(self, api: HQApi):
     self.api = api
     self.authtoken = HQApi.api(api).authtoken
     self.region = HQApi.api(api).region
     self.headers = {
         "x-hq-stk": base64.b64encode(str(self.region).encode()).decode(),
         "x-hq-client": "Android/1.20.1",
         "Authorization": "Bearer " + self.authtoken}
     if HQApi.get_show(api)["active"]:
         self.socket = HQApi.get_show(api)["broadcast"]["socketUrl"].replace("https", "wss")
         self.broadcast = HQApi.get_show(api)['broadcast']['broadcastId']
     else:
         print("Using demo websocket!")
         self.socket = "ws://hqecho.herokuapp.com"  # Websocket with questions 24/7
         self.broadcast = 1
     self.ws = WebSocket(self.socket)
     for header, value in self.headers.items():
         self.ws.add_header(str.encode(header), str.encode(value))
     for _ in self.ws.connect():
         self.success = 1
Exemple #19
0
def get_test_count():
    """Gets the number of test cases."""
    ws = WebSocket(server + '/getCaseCount')
    case_count = None
    for event in ws:
        if event.name == 'text':
            case_count = json.loads(event.text)
    if case_count is None:
        print('Could not get case count. Is the test server running?')
        sys.exit(-1)
    return case_count
Exemple #20
0
def connect_websocket(socket_url, auth_token):
    headers = {"Authorization": f"Bearer {auth_token}",
               "x-hq-client": "Android/1.3.0"}

    websocket = WebSocket(socket_url)

    for header, value in headers.items():
        websocket.add_header(str.encode(header), str.encode(value))

    for msg in websocket.connect(ping_rate=5):
        if msg.name == "text":
            message = msg.text
            message = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", message)
            message_data = json.loads(message)

            if message_data['type'] == 'question':
                question = message_data['question']
                cnt = message_data['questionCount']
                print('{}. {}'.format(cnt, question))
                open_browser(question)
 def __init__(self, q_rx: Queue, q_tx: Queue):
     """
     Class Initializer
     :param q_rx: WSS RX Message Queue
     :type q_rx: Queue
     :param q_tx: WSS TX Message Queue
     :type q_tx: Queue
     """
     self.msg_q_rx = q_rx
     self.msg_q_tx = q_tx
     self.stop = False
     self.ready = False
     self.ws = WebSocket(url=get_cfg('SERVICE.STATUS_SERVICE_URL') + '/' +
                         get_cfg('SESSION.WS_TOKEN'),
                         protocols=['glowforge'],
                         agent=get_cfg('SESSION.USER_AGENT'))
     self.ignore_events = [
         'ping', 'pong', 'poll', 'connecting', 'connected'
     ]
     Thread.__init__(self)
Exemple #22
0
 def __init__(self, api: HQApi, demo: bool = False, proxy: str = None):
     self.api = api
     self.handlers = {}
     self.authtoken = self.api.authtoken
     self.headers = self.api.headers
     self.use_demo = False
     try:
         self.headers["Authorization"]
     except:
         if demo:
             self.use_demo = True
         else:
             raise WebSocketNotAvailable(
                 "You can't use websocket without bearer")
     try:
         self.show = HQApi.get_show(api)
         self.socket = self.show["broadcast"]["socketUrl"].replace(
             "https", "wss")
         self.broadcast = self.show['broadcast']['broadcastId']
     except BannedIPError or ApiResponseError:
         if demo:
             self.use_demo = True
         else:
             raise WebSocketNotAvailable(
                 "You can't use websocket with banned IP or invalid auth")
     except:
         if demo:
             self.use_demo = True
         else:
             raise NotLive("Show isn't live and demo mode is disabled")
     if self.use_demo:
         print(
             "[HQApi] Using demo websocket! Don't create issues with this websocket"
         )
         self.socket = "wss://hqecho.herokuapp.com"  # Websocket with questions 24/7
         self.broadcast = 1
         self.ws = WebSocket(self.socket)
     else:
         self.ws = WebSocket(self.socket)
         for header, value in self.headers.items():
             self.ws.add_header(str.encode(header), str.encode(value))
Exemple #23
0
def main():
    websocket = WebSocket(ARGS.server)
    # TODO: compress?
    print_output("Connecting to '%s'..." % websocket.url)

    vad_audio = VADAudio(aggressiveness=ARGS.aggressiveness)
    print_output("Listening (ctrl-C to exit)...")
    audio_consumer_thread = threading.Thread(
        target=lambda: audio_consumer(vad_audio, websocket))
    audio_consumer_thread.start()

    websocket_runner(websocket)
Exemple #24
0
async def websocket_handler(uri, headers):
    websocket = WebSocket(uri)
    for header, value in headers.items():
        websocket.add_header(str.encode(header), str.encode(value))

    for msg in websocket.connect(ping_rate=5):
        if msg.name == "text":
            message = msg.text
            message = re.sub(r"[\x00-\x1f\x7f-\x9f]", "", message)

            message_data = json.loads(message)

            if "error" in message_data and message_data[
                    "error"] == "Auth not valid":
                raise RuntimeError("Connection settings invalid")
            elif message_data["type"] != "interaction":
                if message_data["type"] == "question":
                    question_str = unidecode(message_data["question"])
                    answers = [
                        unidecode(ans["text"])
                        for ans in message_data["answers"]
                    ]
                    print("\n" * 5)
                    print("Question detected.")
                    print("Question %s out of %s" %
                          (message_data['questionNumber'],
                           message_data['questionCount']))
                    with open("uk.txt", "w") as uk:
                        uk.write("\nQuestion %s out of %s" %
                                 (message_data['questionNumber'],
                                  message_data['questionCount']))
                    aMsg = Fore.CYAN + question_str + "\n"
                    for a in answers:
                        aMsg = aMsg + "\n" + a
                    aMsg = aMsg + Style.RESET_ALL
                    print()
                    await question.answer_question(question_str, answers)

    print("Socket closed")
def test_proxy():
    proc = subprocess.Popen(['proxy.py', '--port', '8888'])
    try:
        time.sleep(1)
        ws = WebSocket('wss://echo.websocket.org',
                       proxies={'https': 'http://127.0.0.1:8888'})
        events = []
        for event in ws:
            events.append(event)
            if event.name == 'ready':
                ws.close()

        assert len(events) == 6
        assert events[0].name == 'connecting'
        assert events[1].name == 'connected'
        assert events[1].proxy == 'http://127.0.0.1:8888'
        assert events[2].name == 'ready'
        assert events[3].name == 'poll'
        assert events[4].name == 'closed'
        assert events[5].name == 'disconnected'
    finally:
        os.kill(proc.pid, 3)
Exemple #26
0
    def __init(self, cookie):
        self.websocket = WebSocket(self.websocket_uri)
        self.websocket.add_header("Cookie".encode("utf-8"),
                                  cookie.encode("utf-8"))
        self.socket_ready = threading.Event()
        self.event_ready = threading.Event()
        self.stopper = threading.Event()

        t = threading.Thread(name="iris_listener", target=self.__socket_run)
        r = threading.Timer(1.0, self.__refresh_database)
        self.workers = [t, r]

        #handler = SignalHandler(self.stopper, self.workers)
        #signal.signal(signal.SIGINT, handler)

        for i, worker in enumerate(self.workers):
            print('Starting worker {}'.format(i))
            worker.start()

        if self.socket_ready.wait(5):
            session = Session(self)
            session.SetActivePlace(placeId=self.place_id)
            if session.success:
                self.account = Account(self)
                self.place = Place(self)
                self.rule = Rule(self)
                self.scene = Scene(self)
                db.prepare_database()
                self.__configure_database()
                self.place.GetHub()
                if self.place.success:
                    self.hub_address = self.place.response["payload"][
                        "attributes"]["hub"]["base:address"]
                    self.time_ready = utils.now()
                else:
                    # use an exception
                    print("failed to get the hub's address")
                    self.stop()
def run_ws(url):
    """Run a websocket until close."""
    ws = WebSocket(url, compress=True)
    for event in ws.connect(ping_rate=0):
        try:
            if event.name == 'text':
                ws.send_text(event.text, compress=True)
            elif event.name == 'binary':
                ws.send_binary(event.data, compress=True)
        except Exception:
            log.exception('error running websocket')
            break
Exemple #28
0
    def start_websocket(self):
        self.websocket = WebSocket(f'ws://{self.address}/')

        for event in persist(self.websocket):

            if event.name == 'ready':
                self.websocket.send_json(command='join_group',
                                         data=dict(key=self.key))

            if event.name == 'text':
                if event.json['command'] == 'new_id':
                    self.websocket_id = event.json['id']

                if event.json['command'] == 'new_view':
                    print('New view')
                    print(event.json['source'])
                    print(self.websocket_id)
                    if event.json['source'] != self.websocket_id:
                        flare.invoke_later(target=self.set_camera,
                                           args=(event.json['view'], ))

            if self.thread_exit:
                self.thread_exit = False
                break
Exemple #29
0
    def websocket_task(self) -> None:
        """
        Runs the websocket task.
        """
        ws = WebSocket(self.url, agent=USER_AGENT)
        self._ws = ws
        # generate poll events every 0.5 seconds to see if we can cancel
        websocket = persist(ws,
                            ping_rate=0,
                            poll=1,
                            exit_event=self._cancelled)
        for event in websocket:
            self._portal.run(self._queue.put, event)

        # signal the end of the queue
        self._portal.run(self._queue.put, self._done)
Exemple #30
0
def run_ws(url):
    """Run a websocket until close."""
    ws = WebSocket(url)
    for event in ws:
        try:
            if event.name == 'text':
                ws.send_text(event.text)
            elif event.name == 'binary':
                ws.send_binary(event.data)
        except:
            log.exception('error running websocket')
            break