Running Asyncio and Socketio at the same time in python - python

I want to run two websockets on in my program, where one communicates to my Raspberry Pi (via websockets) and the other one to my browser via Flask-SocketIO.
Everything runs fine, when I run them in two different python files.
But I can't get them to run in the same file.
This is the Flask-SocketIO Server:
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#app.route('/hello')
def hello():
return 'Hello'
def main():
print("abc")
if __name__ == '__main__':
socketio.run(app, debug=True, port=5000)
print("defg")
Output:
* Restarting with stat
* Debugger is active!
* Debugger PIN: ...
(12444) wsgi starting up on http://...
Noting gets printed.
This is the websockets server: (You can find that piece of code when googleing OCPP Python on mobilityhouses github)
import asyncio
import logging
import websockets
from datetime import datetime
from ocpp.routing import on
from ocpp.v201 import ChargePoint as cp
from ocpp.v201 import call_result
logging.basicConfig(level=logging.INFO)
class ChargePoint(cp):
# One function was left out to decluster the question
async def on_connect(websocket, path):
try:
requested_protocols = websocket.request_headers[
'Sec-WebSocket-Protocol']
except KeyError:
logging.info("Client hasn't requested any Subprotocol. "
"Closing Connection")
if websocket.subprotocol:
logging.info("Protocols Matched: %s", websocket.subprotocol)
else:
# In the websockets lib if no subprotocols are supported by the
# client and the server, it proceeds without a subprotocol,
# so we have to manually close the connection.
logging.warning('Protocols Mismatched | Expected Subprotocols: %s,'
' but client supports %s | Closing connection',
websocket.available_subprotocols,
requested_protocols)
return await websocket.close()
charge_point_id = path.strip('/')
cp = ChargePoint(charge_point_id, websocket)
await cp.start()
async def main():
server = await websockets.serve(
on_connect,
'0.0.0.0',
9000,
subprotocols=['ocpp2.0.1']
)
logging.info("WebSocket Server Started")
print("456")
await server.wait_closed()
if __name__ == '__main__':
asyncio.run(main())
print("123")
Output
INFO:root:WebSocket Server Started
456
I tried pasting it all in the same document and just doing this:
if __name__ == '__main__':
asyncio.run(main())
print("123")
socketio.run(app, debug=True, port=5000)
print("456")
But this just runs the first asyncio.run(main()) and doesnt print 123 etc.
If I switch it up, it will also just run the first .run and than stop.
I tried threading, but that had the same results.
Does anyone know how I can run these two at the same time?

Related

Start multiple vunicorn apps in python

I need to create a Python application that handles both API (fastAPI) and sockets (socketio). I can't find a way to start both the vunicorn applications in the same python script. Note that I can replace vunicorn with any other library that would allow me to fix this.
Code:
import json
from fastapi import FastAPI
import socketio
import uvicorn
# create API app
app_api = FastAPI()
# create a Socket.IO server and wrap with a WSGI application
sio = socketio.Server(port=8001)
app_sio = socketio.WSGIApp(sio)
#app_api.get("/")
def read_root():
return {"Hello": "World"}
#sio.on('*', namespace="/aws-iam")
def catch_all(event, sid, data):
print(event, sid, data)
I am not sure how I can start both app_api and app_sio. I can't start both from the main thread because uvicorn.run(...) is blocking and only the first call would run.
I tried to start them in two different threads but I got errors:
if __name__ == "__main__":
def start_api():
uvicorn.run("testing.mock_api:app_api", host='127.0.0.1', port=8000, reload=True, debug=True) #, workers=3)
def start_sio():
uvicorn.run("testing.mock_api:app_sio", host='127.0.0.1', port=8001, reload=True, debug=True) # , workers=3)
from threading import Thread
import time
threads = [
Thread(target=start_sio),
Thread(target=start_api),
]
for thread in threads:
thread.start()
time.sleep(999999999999)
With multiple thread I get the errors:
File "/src/testing/mock_api.py", line 55, in start_api
uvicorn.run("testing.mock_api:app_api", host='127.0.0.1', port=8000, reload=True, debug=True) #, workers=3)
File "/usr/local/lib/python3.6/dist-packages/uvicorn/main.py", line 447, in run
ChangeReload(config, target=server.run, sockets=[sock]).run()
File "/usr/local/lib/python3.6/dist-packages/uvicorn/supervisors/basereload.py", line 43, in run
self.startup()
File "/usr/local/lib/python3.6/dist-packages/uvicorn/supervisors/basereload.py", line 62, in startup
signal.signal(sig, self.signal_handler)
File "/usr/lib/python3.6/signal.py", line 47, in signal
handler = _signal.signal(_enum_to_int(signalnum), _enum_to_int(handler))
ValueError: signal only works in main thread
Instead of running the two apps separatly, what about only running the FastAPI application & mount the socketio app on this one ?
To illustrate with an example from this github issue, you could do the following :
import socketio
from fastapi import FastAPI
import uvicorn
app = FastAPI()
sio = socketio.AsyncServer(async_mode='asgi')
socket_app = socketio.ASGIApp(sio)
#sio.on('*', namespace="/aws-iam")
async def catch_all(event, sid, data):
print(event, sid, data)
#app.get("/hello")
async def root():
return {"message": "Hello World"}
app.mount('/', socket_app)
if __name__ == "__main__":
uvicorn.run("main:app", reload=True, port=8080)
It includes switching socketio app to async too

execute a specific method into sgx using gramine

I have an application which is using gRPC, client.py and server.py , I want to use gramine in order to execute the service inside SGX.
how can I run a specific method not the whole script inside sgx using gramine?
client.py:
"""The Python implementation of the GRPC helloworld.Greeter client."""
from __future__ import print_function
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
print("Will try to greet world ...")
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print("Greeter client received: " + response.message)
if __name__ == '__main__':
logging.basicConfig()
run()
and server.py:
from concurrent import futures
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
def serve():
port = '50051'
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:' + port)
server.start()
print("Server started, listening on " + port)
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
let say I want to execute sayhello inside SGX when I run client.py
currently I am running gramine-sgx ./python client.py that is going to execute only client inside SGX or is it going to also run sayhello from server.py inside SGX?

Closing flask-socket io server programmatically

I am new to server development so please be kind...
I am developing a test application that starts a flask-socketio server and after interacting with a clients, it needs to shutdown and open another instance.
However this is not possible
I get error
File "C:\Python39\lib\site-packages\eventlet\convenience.py", line 78, in listen
sock.bind(addr)
OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted
How can I programmatically shutdown the server?
I looked in answers here How to stop flask application without using ctrl-c and using a process indeed does the trick.
But I don't really want to have a separate process because sharing the variables between process is too tricky.
I also didn't understand from the same post how to send a request from the server to the server itself in order to shutdown the flask application.
This is an example of my code
import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time
ip_addr=socket.gethostbyname(socket.gethostname())
appFlask = Flask(__name__)
sio = socketio.Server( ) #engineio_logger=True,logger=True)
# wrap Flask application with engineio's middleware
app = socketio.Middleware(sio, appFlask)
#sio.on('connect')
def connect(sid, environ):
print('connect ', sid)
#sio.on('message')
def message(sid, data):
print('message '+data, data)
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
#sio.on('result')
def result(sid,data):
print('result ', sid)
def worker1():
socket_port=3000
eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)
if __name__ == '__main__':
sio.start_background_task(worker1)
# do some stuff and interact with the client
sio.sleep(2)
# how can I close the server so that I can do the following?
sio.start_background_task(worker1)
EDITED wit flask socket io functionality
import socketio
import eventlet
import eventlet.wsgi
from flask import Flask, render_template
import socket
import threading
import time
import requests
from flask import request
from flask_socketio import SocketIO
ip_addr=socket.gethostbyname(socket.gethostname())
socket_port=3000
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
sio = SocketIO(app)
#app.route('/stop')
def stop():
sio.stop()
#sio.on('connect')
def connect(sid, environ):
print('connect ', sid)
#sio.on('message')
def message(sid, data):
print('message '+data, data)
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
#sio.on('result')
def result(sid,data):
print('result ', sid)
def worker1():
eventlet.wsgi.server(eventlet.listen((ip_addr, socket_port)), app)
if __name__ == '__main__':
eventlet_thr=sio.start_background_task(worker1)
# do some stuff and interact with the client
sio.sleep(2)
# now wait that the server is stopped
# invoke in a different process a request to stop
eventlet_thr.join()
# how can I close the server so that I can do the following?
sio.start_background_task(worker1)
You are using the eventlet web server is seems, so the question is how to stop the eventlet web server, Flask-SocketIO has nothing to do with the server.
As a convenience, Flask-SocketIO provides the stop() method, which you have to call from inside a handler. I'm not sure if that will work when the server is running on a thread that is not the main thread though, you'll have to test that out.
So basically what you need to do is add an endpoint that forces the server to exit, maybe something like this:
#app.route('/stop')
def stop():
sio.stop()
return ''
So then you can start and stop the server as follows:
if __name__ == '__main__':
thread = sio.start_background_task(worker1)
# do some stuff and interact with the client
requests.get('http://localhost:5000/stop')
thread.join()

How to exec code after uvicorn.run() in python socketio server?

I need to run some code after waking up a webserver. In the example it's "start_my_thing()".
import asyncio
import sys
import uvicorn
import socketio
#sio.on('connect')
async def test_connect(sid, environ):
pass
app = socketio.ASGIApp(sio, static_files={
'/': 'app.html',
'/static/': 'static/',
})
if __name__ == '__main__':
uvicorn.run(app, host='0.0.0.0', port=8080)
start_my_thing()
The line with start_my_thing() will never be reached out because uvicorn.run() starts infinite loop.
But is there any trick to run some code when a webserver is already accessible?

How can I run a python script from within Flask

I have a Flask script which creates a website and prints some data dynamically. - The data which it prints should come from another python script.
The current problem that I'm facing is that if I put the line that executes the python script before the line that executes the Flask app, it will run the Python script without running Flask; and vice versa.
Python script:
import websocket
from bitmex_websocket import Instrument
from bitmex_websocket.constants import InstrumentChannels
from bitmex_websocket.constants import Channels
import json
websocket.enableTrace(True)
sells = 0
buys = 0
channels = [
InstrumentChannels.trade,
]
XBTUSD = Instrument(symbol='XBTUSD',
channels=channels)
XBTUSD.on('action', lambda msg: test(msg))
def test(msg):
parsed = json.loads(json.dumps(msg))
print(parsed)
XBTUSD.run_forever()
Flask script (NB: price should be the variable 'parsed' from the other script):
# Start with a basic flask app webpage.
from flask_socketio import SocketIO, emit
from flask import Flask, render_template, url_for, copy_current_request_context
from random import random
from time import sleep
from threading import Thread, Event
import requests, json
import time
__author__ = 'slynn'
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
app.config['DEBUG'] = True
#turn the flask app into a socketio app
socketio = SocketIO(app)
#random number Generator Thread
thread = Thread()
thread_stop_event = Event()
class RandomThread(Thread):
def __init__(self):
self.delay = 1
super(RandomThread, self).__init__()
def randomNumberGenerator(self):
while not thread_stop_event.isSet():
socketio.emit('newnumber', {'number': parsed}, namespace='/test')
sleep(self.delay)
def run(self):
self.randomNumberGenerator()
#app.route('/')
def index():
#only by sending this page first will the client be connected to the socketio instance
return render_template('index.html')
#socketio.on('connect', namespace='/test')
def test_connect():
# need visibility of the global thread object
global thread
print('Client connected')
#Start the random number generator thread only if the thread has not been started before.
if not thread.isAlive():
print("Starting Thread")
thread = RandomThread()
thread.start()
#socketio.on('disconnect', namespace='/test')
def test_disconnect():
print('Client disconnected')
if __name__ == '__main__':
socketio.run(app)
Using import:
Wrap what the python script (e.g. website_generator.py) is generating into a function.
Place it in the same directory as your app.py or flask.py.
Use from website_generator import function_name in flask.py
Run it using function_name()
You can use other functions such as subprocess.call et cetera; although they might not give you the response.
Example using import:
from flask import Flask
import your_module # this will be your file name; minus the `.py`
app = Flask(__name__)
#app.route('/')
def dynamic_page():
return your_module.your_function_in_the_module()
if __name__ == '__main__':
app.run(host='0.0.0.0', port='8000', debug=True)
try this:
from flask import Flask
app = Flask(__name__)
#app.route('/')
def run_script():
file = open(r'/path/to/your/file.py', 'r').read()
return exec(file)
if __name__ == "__main__":
app.run(debug=True)

Categories

Resources