def test_secure_websocket_connection(self): ws = WebSocketClient('wss://127.0.0.1:5443/ws') ws.connect() print("Sending: 'Hello, World'...") ws.send("Hello, World") print("Sent") print("Receiving...") result = ws.receive() print("Received: {}".format(result)) ws.close() self.assertEqual("Hello, World", str(result))
def proxy(url): with app.test_request_context(): if websocket: while True: data = websocket.receive() websocket_url = 'ws://{}/{}'.format(PROXY_DOMAIN, url) if websocket_url not in websockets: client = WebSocketClient(websocket_url, protocols=['http-only', 'chat']) websockets[websocket_url] = client else: client = websockets[websocket_url] client.connect() if data: client.send(data) client_data = client.receive() if client_data: websocket.send(client_data) return Response() if request.method == "GET": url_ending = "%s?%s" % (url, request.query_string) url = PROXY_FORMAT % url_ending resp = requests.get(url) elif request.method == "POST": if url == 'kernels': url_ending = "%s?%s" % (url, request.query_string) url = PROXY_FORMAT % url_ending else: url = PROXY_FORMAT % url resp = requests.post(url, request.data) else: url = PROXY_FORMAT % url resp = requests.request(url, request.method, request.data) content = resp.content if content: content = PROXY_REWRITE_REGEX.sub(r'\1/proxy/', content) headers = resp.headers if "content-type" in headers: mimetype = headers["content-type"].split(";")[0].split(",")[0] else: mimetype = None response = Response( content, headers=dict(headers), mimetype=mimetype, status=resp.status_code ) return response
def proxy(url): with app.test_request_context(): if websocket: while True: data = websocket.receive() websocket_url = 'ws://{}/{}'.format(PROXY_DOMAIN, url) if websocket_url not in websockets: client = WebSocketClient(websocket_url, protocols=['http-only', 'chat']) websockets[websocket_url] = client else: client = websockets[websocket_url] client.connect() if data: client.send(data) client_data = client.receive() if client_data: websocket.send(client_data) return Response() if request.method == "GET": url_ending = "%s?%s" % (url, request.query_string) url = PROXY_FORMAT % url_ending resp = requests.get(url) elif request.method == "POST": if url == 'kernels': url_ending = "%s?%s" % (url, request.query_string) url = PROXY_FORMAT % url_ending else: url = PROXY_FORMAT % url resp = requests.post(url, request.data) else: url = PROXY_FORMAT % url resp = requests.request(url, request.method, request.data) content = resp.content if content: content = PROXY_REWRITE_REGEX.sub(r'\1/proxy/', content) headers = resp.headers if "content-type" in headers: mimetype = headers["content-type"].split(";")[0].split(",")[0] else: mimetype = None response = Response(content, headers=dict(headers), mimetype=mimetype, status=resp.status_code) return response
class WebsocketTransport(Transport): name = 'websocket' def __init__(self, *args, **kwargs): super(WebsocketTransport, self).__init__(*args, **kwargs) self.websocket = None self.read_job = None def do_open(self): url = self.uri() self.websocket = WebSocketClient(url) self.websocket.connect() self.on_open() self.read_job = gevent.spawn(self._read) def _read(self): while True: msg = self.websocket.receive() if msg is not None: if msg.is_text: self.on_data(str(msg.data)) else: self.on_data(bytearray(msg.data)) else: break def write(self, packets): self.writable = False for packet in packets: encoded_packet = parser.Parser.encode_packet( packet, self.supports_binary) try: binary = type(encoded_packet) is bytearray self.websocket.send(encoded_packet, binary=binary) except RuntimeError, e: self.on_error( 'The websocket clsoed without a close packet (%s)', e) self.on_drain()
class WebsocketTransport(Transport): name = 'websocket' def __init__(self, *args, **kwargs): super(WebsocketTransport, self).__init__(*args, **kwargs) self.websocket = None self.read_job = None def do_open(self): url = self.uri() self.websocket = WebSocketClient(url) self.websocket.connect() self.on_open() self.read_job = gevent.spawn(self._read) def _read(self): while True: msg = self.websocket.receive() if msg is not None: if msg.is_text: self.on_data(str(msg.data)) else: self.on_data(bytearray(msg.data)) else: break def write(self, packets): self.writable = False for packet in packets: encoded_packet = parser.Parser.encode_packet(packet, self.supports_binary) try: binary = type(encoded_packet) is bytearray self.websocket.send(encoded_packet, binary=binary) except RuntimeError, e: self.on_error('The websocket clsoed without a close packet (%s)', e) self.on_drain()
ws.close() break else: break print("Connection closed!") def outgoing(ws): for i in range(0, 40, 5): ws.send("*" * i) # We won't get this back ws.send("Foobar") if __name__ == '__main__': ws = WebSocketClient('ws://127.0.0.1:8080/websocket', protocols=['http-only', 'chat']) ws.connect() for n in range(50): msg = json.dumps(dict(msg="Hello world", no=n)) ws.send(msg) resp = str(ws.receive()) print json.loads(resp) ws.close() # greenlets = [ # gevent.spawn(incoming, ws), # gevent.spawn(outgoing, ws), # ] # gevent.joinall(greenlets)
class TunnelClient(Service): def __init__(self, local_port, name, broker_address): self.local_port = local_port self.ws = WebSocketClient('http://%s/t/%s' % (broker_address, name)) self.connections = {} self._send_lock = Semaphore() def do_start(self): self.ws.connect() self.spawn(self.listen) #gevent.spawn(self.visual_heartbeat) def visual_heartbeat(self): while True: print "." gevent.sleep(1) def listen(self): while True: msg = self.ws.receive(msg_obj=True) if msg is None: print "Trying to stop" self.stop() if msg.is_text: parsed = json.loads(str(msg)) print str(msg) conn_id, event = parsed[0:2] if event == 'open': self.local_open(conn_id) elif event == 'closed': self.local_close(conn_id) elif msg.is_binary: conn_id, data = decode_data_packet(msg.data) self.local_send(conn_id, data) def local_open(self, conn_id): socket = create_connection(('0.0.0.0', self.local_port)) self.connections[conn_id] = socket self.spawn(self.local_recv, conn_id) def local_close(self, conn_id): socket = self.connections.pop(conn_id) try: socket.shutdown(0) socket.close() except: pass def local_send(self, conn_id, data): self.connections[conn_id].send(data) def local_recv(self, conn_id): while True: data = self.connections[conn_id].recv(1024) if not data: break self.tunnel_send(conn_id, data) self.tunnel_send(conn_id, open=False) def tunnel_send(self, conn_id, data=None, open=None): if open is False: msg = [conn_id, 'closed'] with self._send_lock: self.ws.send(json.dumps(msg)) elif data: msg = encode_data_packet(conn_id, data) with self._send_lock: self.ws.send(msg, binary=True) else: return
class TunnelClient(Service): def __init__(self, local_port, name, broker_address): self.local_port = local_port self.ws = WebSocketClient('http://%s/t/%s' % (broker_address, name)) self.connections = {} self._send_lock = Semaphore() def do_start(self): self.ws.connect() self.spawn(self.listen) #gevent.spawn(self.visual_heartbeat) def visual_heartbeat(self): while True: print "." gevent.sleep(1) def listen(self): while True: msg = self.ws.receive(msg_obj=True) if msg is None: print "Trying to stop" self.stop() if msg.is_text: parsed = json.loads(str(msg)) print str(msg) conn_id, event = parsed[0:2] if event == 'open': self.local_open(conn_id) elif event == 'closed': self.local_close(conn_id) elif msg.is_binary: conn_id, data = decode_data_packet(msg.data) self.local_send(conn_id, data) def local_open(self, conn_id): socket = create_connection(('0.0.0.0', self.local_port)) self.connections[conn_id] = socket self.spawn(self.local_recv, conn_id) def local_close(self, conn_id): socket = self.connections.pop(conn_id) try: socket.shutdown(0) socket.close() except: pass def local_send(self, conn_id, data): self.connections[conn_id].send(data) def local_recv(self, conn_id): while True: data = self.connections[conn_id].recv(1024) if not data: break self.tunnel_send(conn_id, data) self.tunnel_send(conn_id, open=False) def tunnel_send(self, conn_id, data=None, open=None): if open is False: msg = [conn_id, 'closed'] with self._send_lock: self.ws.send(json.dumps(msg)) elif data: msg = encode_data_packet(conn_id, data) with self._send_lock: self.ws.send(msg, binary=True) else: return
if len(m) == 35: ws.close() break else: break print("Connection closed!") def outgoing(ws): for i in range(0, 40, 5): ws.send("*" * i) # We won't get this back ws.send("Foobar") if __name__ == '__main__': ws = WebSocketClient('ws://127.0.0.1:8080/websocket', protocols=['http-only', 'chat']) ws.connect() ws.send("Hello world") print(ws.receive()) ws.send("Hello world again") print(ws.receive()) greenlets = [ gevent.spawn(incoming, ws), gevent.spawn(outgoing, ws), ] gevent.joinall(greenlets)
# -*- coding: utf-8 -*- from gevent import monkey; monkey.patch_all() import gevent from ws4py.client.geventclient import WebSocketClient if __name__ == '__main__': ws = WebSocketClient('ws://localhost:9000/ws', protocols=['http-only', 'chat']) ws.connect() ws.send("Hello world") print((ws.receive(),)) ws.send("Hello world again") print((ws.receive(),)) def incoming(): while True: m = ws.receive() if m is not None: m = str(m) print((m, len(m))) if len(m) == 35: ws.close() break else: break print(("Connection closed!",)) def outgoing(): for i in range(0, 40, 5):
class WebSocketThread(WorkerThread): """ Websocket.receive() blocks until there is a response. It also hangs indefinitely until there is socket.close() call in the server side If the server shuts down unexpectedly the client socket.recieve() will hang forever. """ def __init__(self, notify_window): #self.webSocketReconnect() #because threads have been "geventified" they no longer run in parallel, but rather asynchronously. So if this runs not within a greenlet, it will block the mainloop... gevent.sleep(1) only yields to another greenlet or couroutine (like wx.Yield) when it is called from within a greenlet. self.last_sent = self.last_alive = datetime.datetime.now() self.containers_in_server = {} WorkerThread.__init__(self, notify_window) def webSocketReconnect(self): """ WSock.receive sometimes hangs, as in the case of a disconnect Receive blocks, but send does not, so we use send as a tester An ideal connection will have a 1:1 ratio of send and receive However, bad connections will have poorer ratios such as 10:1 If ratio reaches 20:1 then this function will force reconnect This function is triggered when CLIENT_LATEST_CLIP is set, but SERVER_LATEST_CLIP is not, and the outgoing loop keeps calling """ while 1: if self.KEEP_RUNNING: try: self.wsock.close_connection( ) # Terminate Nones the environ and stream attributes, which is for servers except AttributeError: pass try: self.last_sent = self.last_alive = datetime.datetime.now() login = self._notify_window.getLogin() self.wsock = WebSocketClient( URL( "ws", DEFAULT_DOMAIN, DEFAULT_PORT, "ws", email=login.get("email") or "", password=login.get("password" or ""), ) ) #email="*****@*****.**", password="******" #keep static to guarantee one socket for all instances self.wsock.connect() break except (SocketError, exc.HandshakeError, RuntimeError): print "no connection..." self._notify_window.destroyBusyDialog() self._notify_window.sb.toggleStatusIcon( msg="Unable to connect to the internet.", icon="bad") gevent.sleep(1) def keepAlive(self, heartbeat=100, timeout=1000 ): #increment of 60s times 20 unresponsive = 20 minutes """ Since send is the only way we can test a connection's status, and since send is only triggered when CLIENT_LATEST_CLIP has a change, we need to test the connection incrementally too, and therefore we can account for when the user is idle. """ now = datetime.datetime.now() if self.FORCE_RECONNECT or (now - self.last_alive).seconds > timeout: self.webSocketReconnect() self.FORCE_RECONNECT = False elif (now - self.last_sent).seconds > heartbeat: self.last_sent = datetime.datetime.now() return True return False def incoming(self): #pdb.set_trace() #print "start incoming..." while 1: if self.KEEP_RUNNING: #if CLIENT_LATEST_CLIP.get() != SERVER_LATEST_CLIP.get(): #print "getting... c:%s, s:%s"%(CLIENT_LATEST_CLIP.get(),SERVER_LATEST_CLIP.get()) try: received = self.wsock.receive( ) #WebSocket run method is implicitly called, "Performs the operation of reading from the underlying connection in order to feed the stream of bytes." According to WS4PY This method is blocking and should likely be run in a thread. if received == None: raise SocketError #disconnected! delivered = json.loads( str(received) ) #EXTREME: this can last forever, and when creating new connection, this greenlet will hang forever. #receive returns txtmessage object, must convert to string!!! if delivered["message"] == "Error!": print delivered["data"] self.pause() self._notify_window.sb.toggleStatusIcon( msg=delivered["data"], icon="bad") if delivered["message"] == "Salt!": print "\nSalt! %s\n" % delivered["data"] self.ACCOUNT_SALT = delivered["data"] if delivered["message"] == "Update!": server_latest_clip_rowS = delivered['data'] server_latest_clip_row = server_latest_clip_rowS[0] #print server_latest_clip_row SERVER_LATEST_CLIP.set( server_latest_clip_row ) #should move this to after postevent or race condition may occur, but since this is gevent, it might not be necessary CLIENT_LATEST_CLIP.set(server_latest_clip_row) #print "GET %s"% server_latest_clip_row['clip_hash_fast'] wx.PostEvent(self._notify_window, EVT_RESULT(server_latest_clip_rowS)) elif delivered["message"] == "Upload!": self.containers_in_server.update(delivered['data']) elif delivered["message"] == "Alive!": print "Alive!" self.last_alive = datetime.datetime.now() #except (SocketError, RuntimeError, AttributeError, ValueError, TypeError): #gevent traceback didn't mention it was a socket error, just "error", but googling the traceback proved it was. #if received is not None: #test if socket can send except: #print "can't get...%s"%str(sys.exc_info()[0]) self.webSocketReconnect() gevent.sleep(0.25) def outgoing(self): #pdb.set_trace() #print "start outgoing..." while 1: if self.KEEP_RUNNING: sendit = False if self.keepAlive( ): #also send alive messages and reset connection if receive block indefinitely sendit = dict(message="Alive?") if not self.ACCOUNT_SALT: print "Salt?" sendit = dict(message="Salt?", ) elif CLIENT_LATEST_CLIP.get().get( 'clip_hash_secure') != SERVER_LATEST_CLIP.get().get( 'clip_hash_secure' ): #start only when there is something to send send_clip = CLIENT_LATEST_CLIP.get() #print "sending...%s"%send_clip container_name = send_clip['container_name'] container_path = os.path.join(TEMP_DIR, container_name) #response = requests.get(URL(arg="file_exists/%s"%container_name,port=8084,scheme="http")) #file_exists = json.loads(response.content) if not container_name in self.containers_in_server: print "UPLOAD? %s" % container_name sendit = dict( message="Upload?", data=container_name, ) else: try: if self.containers_in_server[ container_name] == False: r = requests.post(URL("http", DEFAULT_DOMAIN, DEFAULT_PORT, "upload"), files={ "upload": open( container_path, 'rb') }) print r except requests.exceptions.ConnectionError: #self.destroyBusyDialog() #self.sb.toggleStatusIcon(msg="Unable to connect to the internet.", icon=False) self.webSocketReconnect() else: sendit = dict( message="Update?", data=CLIENT_LATEST_CLIP.get(), ) print "\nSEND %s... %s\n" % ( CLIENT_LATEST_CLIP.get().get( 'clip_hash_secure'), SERVER_LATEST_CLIP.get().get( 'clip_hash_secure')) if sendit: try: self.wsock.send(json.dumps(sendit)) self.last_sent = datetime.datetime.now() #except (SocketError, RuntimeError, AttributeError, ValueError, TypeError): #if self.wsock.stream: #test if socket can get except: #print "can't send...%s"%str(sys.exc_info()[0]) self.webSocketReconnect() gevent.sleep(0.25) #yield to next coroutine. def run(self): greenlets = [ gevent.spawn(self.outgoing), gevent.spawn(self.incoming), ] gevent.joinall(greenlets)
# -*- coding: utf-8 -*- from gevent import monkey; monkey.patch_all() import gevent from ws4py.client.geventclient import WebSocketClient if __name__ == '__main__': ws = WebSocketClient('ws://127.0.0.1:9000/ws', protocols=['http-only', 'chat']) ws.connect() ws.send("Hello world") print((ws.receive(),)) ws.send("Hello world again") print((ws.receive(),)) def incoming(): while True: m = ws.receive() if m is not None: m = str(m) print((m, len(m))) if len(m) == 35: ws.close() break else: break print(("Connection closed!",)) def outgoing(): for i in range(0, 40, 5):