Create PIPE between web socket and tcp socket - websocket

My service already uses Websockets to communicate with webserver
It also connects to the other tcp endpoint.
It does two things
1/
=> Reads the data from the webserver
=> write it to the tcp endpoint
2/
=> Reads the data from the tcp endpoint
=> write it to the webserver.
I have the following code to serve the purpose
import websocket
import asyncio
def open_remote(reader):
print("open remote")
do_remote_read(reader)
def on_message(ws, message):
print("message recieved")
print(message)
writer.write(message)
def on_error(ws, error):
print(error)
def on_close(ws):
print("### closed ###")
async def do_remote_read(reader):
print("remote read")
data = await reader.read(1000)
ws.send(data)
print(data.decode())
print ("remote exit")
def on_open(ws):
print("websocket opened")
loop = asyncio.get_event_loop();
reader, writer = asyncio.open_connection('127.0.0.1', 2000,
loop=loop)
asyncio.sleep(3)
loop.run_until_complete(open_remote(reader))
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://x.x.x.x:/abc",
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
In this code once the websocket is opened, callback on_open gets called
where it tries to open other remote endpoint and it gets me the following error.
websocket opened
error from callback <function on_open at 0x7f398e3d96a8>: yield from wasn't used with future
File "/usr/local/lib/python3.6/dist-packages/websocket/_app.py", line 345, in _callback
callback(self, *args)
File "websocket_python.py", line 40, in on_open
loop=loop)
File "/usr/lib/python3.6/asyncio/streams.py", line 81, in open_connection
lambda: protocol, host, port, **kwds)
File "/usr/lib/python3.6/asyncio/base_events.py", line 748, in create_connection
yield from tasks.wait(fs, loop=self)
File "/usr/lib/python3.6/asyncio/tasks.py", line 313, in wait
return (yield from _wait(fs, timeout, return_when, loop))
File "/usr/lib/python3.6/asyncio/tasks.py", line 396, in _wait
yield from waiter

The immediate cause of error is that asyncio.open_connection is a coroutine, so you must await it or, since on_open is not async, run it with run_until_complete:
reader, writer = loop.run_until_complete(asyncio.open_connection(...))
Also note that just calling asyncio.sleep(3) does nothing unless you await it from a coroutine. (Calling loop.run_until_complete(asyncio.sleep(3)) is possible, but it boils down to a very fancy way of writing time.sleep(3).)

Related

How to add new thread for every new client in python websockets?

import asyncio
import websockets
import threading
async def server_handle(websocket,path):
print("Server is waiting!!!!")
while True:
msg = await websocket.recv()
print(f"Client : {msg}")
await websocket.send(input("Server : "))
def add_new_clients():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
start_server = websockets.serve(server_handle, "localhost", 1234)
loop.run_until_complete(start_server)
loop.run_forever()
loop.close()
total_clients = 0
if __name__ == "__main__":
# daemon server thread:
server = threading.Thread(target=add_new_clients, daemon=True)
server.start()
total_clients+=1
print(f"total clients : {total_clients}")
Here i am trying to add new thread to handle each clients request seperately using python websockets . for example if client1 connects to the server one thread should be created and sholud take care of the request and responce of that particular client. is there any way?.

Voila, jupyter and websockets: how to print?

Although the question might seem simple I can't see to find a viable way or anyway of printing the incoming messages from a threaded websocket.
Basically, I've created a jupyterlab notebook that lets me connect to a local websocket server and echo messages sent from a firecamp websocket connection. When running it on a cell (without the run button and run A.start()) I can see the prints but as soon as I hit the run button after restarting the kernal I can't see incoming messages.
Normally I would expect something like:
Function started
Someone said: test 1
Someone said: test 2
In the prints but nothing seems to apperas when hitting the run button.
The main objective is to be able to run the notebook with voila to upload to heroku but I canĀ“t seem to make the prints work. If anybody has a clue or a better idea, I'm all ears.
Thanks in advance.
PD: Code
import ipywidgets as widgets
from IPython.display import Javascript, display
import websocket
import asyncio
import nest_asyncio
import threading
import websocket
import time
import sys
import trace
import logging
from time import sleep
output_box = widgets.Output()
class KThread(threading.Thread):
"""A subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run
threading.Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
ws.close()
self.killed = True
def on_message(ws, message):
print(message)
def on_open(ws):
ws.send("Connected Test")
def on_close(ws, close_status_code, close_msg):
print("### closed ###")
def on_error(ws, error):
print(error)
#This illustrates running a function in a separate thread. The thread is killed before the function finishes.
def func():
print('Function started')
ws.run_forever()
ws = websocket.WebSocketApp("ws://localhost:7890", on_open=on_open,on_message = on_message, on_close = on_close,on_error = on_error)
A = KThread(target=func)
websocket.enableTrace(True)
run_button = widgets.Button(
description='Run Button',
disabled=False,
button_style='info', # 'success', 'info', 'warning', 'danger' or ''
tooltip='Run button function',
icon='play'
)
def on_run_button_clicked(b):
with output_box:
A.start()
run_button.on_click(on_run_button_clicked)
display(run_button,output_box)
This is the websocket server:
# Importing the relevant libraries
import websockets
import asyncio
# Server data
PORT = 7890
print("Server listening on Port " + str(PORT))
# A set of connected ws clients
connected = set()
# The main behavior function for this server
async def echo(websocket, path):
print("A client just connected")
# Store a copy of the connected client
print(websocket)
connected.add(websocket)
# Handle incoming messages
try:
async for message in websocket:
print("Received message from client: " + message)
# Send a response to all connected clients except sender
for conn in connected:
if conn != websocket:
await conn.send("Someone said: " + message)
# Handle disconnecting clients
except websockets.exceptions.ConnectionClosed as e:
print("A client just disconnected")
finally:
connected.remove(websocket)
# Start the server
start_server = websockets.serve(echo, "localhost", PORT)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

Change log level dynamically from asyncio outside module

I need to dynamically change log level without reloading any modules. For this, I am using a combination of asyncio and multiprocessing (both for the bigger program that I am writing).
log_config.py
def setupLogging(log_level=None): # load custom logger
with open(os.path.join(LOG_PATH,'log_config.yaml'), 'rt') as file_:
config = yaml.safe_load(file_.read())
logging.config.dictConfig(config)
logging.Formatter.converter = time.gmtime
if not log_level:
log_level = 'preview'
return logging.getLogger(log_level)
logger=setupLogging() # global var that needs dynamic updation
async def logger_changes(): # socket listener that changes the logger object
global logger
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 9999))
sock.listen()
sock.setblocking(0)
while True:
try:
conn, addr = sock.accept()
data = conn.recv(1024)
conn.send(data)
logger = setupLogging(data.decode('utf8'))
except Exception as e:
pass
await asyncio.sleep(5)
async def logger_handler():
t1 = asyncio.create_task(logger_changes())
await t1
def start_logger():
start_func = asyncio.run(logger_handler())
pLOGGER = Process(name="__startLOGGER__", target=start_logger, daemon=False)
pLOGGER.start()
Main Functionality
import log_config
logger=log_config.logger
async def core_func():
for i in range(10):
logger.debug("sample debug log")
logger.info("sample info log")
logger.warning("Watch out!")
logger.error("Heading for trouble!")
logger.critical("Seriously, do something!")
print("#"*80)
await asyncio.sleep(5)
async def core_func_parent():
t1 = asyncio.create_task(core_func())
await t1
def core_func_handler():
start_func = asyncio.run(core_func_parent())
if __name__=='__main__':
pMODULE = Process(name="__startMODULE__", target=core_func_handler, daemon=False)
pMODULE.start()
Trigger Log Level Change
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect(('localhost', 9999))
request = "test"
try:
server.send(request.encode('utf8'))
response = server.recv(255).decode('utf8')
print(response)
except Exception as e:
print(e)
server.close()
Steps
Run main functionality python script. Automatically invoked log_config from inside, starts the socket listener and instantiates the logger object
Run trigger log level change that sends a message to the web socket with the updated logger setting
Challenge
Once I run step 1, the logging level is INFO (which is exactly what I want)
But once I run step 2, I am expecting the logging level to change to DEBUG which is not happening.
Any help is appreciated.

TypeError: object NoneType can't be used in 'await' expression

function i am trying to call from my flask-socketio server
from flask_socketio import emit
import asyncio
async def myfunc():
for i in range(10):
j = 1*3
await emit('update', {'j':j})
in my server function i am running
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
task = asyncio.gather(myfunc())
loop.run_until_complete(task)
I am getting an error on the 1st iteration of the loop one successful emit.
File "path\to\Python\Python37-32\Lib\threading.py", line 917, in _bootstrap_inner
self.run()
File "path\to\Python\Python37-32\Lib\threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "path\to\lib\site-packages\socketio\server.py", line 636, in _handle_event_internal
r = server._trigger_event(data[0], namespace, sid, *data[1:])
File "path\to\lib\site-packages\socketio\server.py", line 665, in _trigger_event
return self.handlers[namespace][event](*args)
File "path\to\lib\site-packages\flask_socketio\__init__.py", line 280, in _handler
*args)
File "path\to\lib\site-packages\flask_socketio\__init__.py", line 694, in _handle_event
ret = handler(*args)
File "path\to\server.py", line 127, in print_message
loop.run_until_complete(task)
File "path\to\Python\Python37-32\Lib\asyncio\base_events.py", line 584, in run_until_complete
return future.result()
File "path\to\script.py", line 261, in fun
await emit('update', {'j':j})
TypeError: object NoneType can't be used in 'await' expression
I want to be able to call myfunc() and emit an update to my socketio client on each iteration of for loop
I also got this same error when I called await on a non async function.
e.g.
def do_something():
print("Do Something")
async erroneous_function():
await do_something()
The solution is simple, remove the await in front of the do_something() since it's not async.
Flask and Flask-SocketIO do not work with asyncio. Either remove the asyncio stuff, or else drop Flask and Flask-SocketIO and use python-socketio, which does have support for asyncio.

Can't exit asynchronous process

I have a problem with the exiting from the asynchronous process which is handled by asyncio. This is the ftp server + client project and I want to kill the client process after 'exit' command.
The most important part of this code is here:
class FtpCommandsReceiver:
def __init__(self, loop, sock):
self.loop = loop
self.sock = sock
self.loop.create_task(self.recieve_data())
self.commands_to_handle = {
'exit': self.exit_handler
}
async def recieve_data(self):
while True:
self.data_to_send = input('ftp> ')
if self.data_to_send == '':
continue
await self.loop.sock_sendall(self.sock, self.data_to_send.encode())
try:
await self.commands_to_handle.get(self.data_to_send)()
except TypeError:
pass
self.received_data = await self.loop.sock_recv(self.sock, 10000)
print(self.received_data.decode())
if not self.received_data:
break
print('Connection closed by the server')
self.sock.close()
async def exit_handler(self):
self.loop.stop()
self.loop.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
FTP_connection = FtpConnection(loop)
task = loop.create_task(FTP_connection.connect())
try:
loop.run_forever()
finally:
loop.close()
When it calls exit_handler method, the exception raises:
Task exception was never retrieved
future: exception=RuntimeError('Cannot close a running event loop',)>
Traceback (most recent call last):
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "FTPclient.py", line 54, in recieve_data
await self.commands_to_handle.get(self.data_to_send)()
File "FTPclient.py", line 66, in exit_handler
self.loop.close()
File "/usr/lib/python3.5/asyncio/unix_events.py", line 56, in close
super().close()
File "/usr/lib/python3.5/asyncio/selector_events.py", line 94, in close
raise RuntimeError("Cannot close a running event loop")
RuntimeError: Cannot close a running event loop
I will be grateful for your help and thank you in advance!

Resources