socketio.send() does not send data to client - python

I am trying to send data from server to flutter app using socketIO. Although I am able to connect and emit, the server is not able to send data to client side.
Server side code:
import cv2
import numpy as np
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
from threading import Lock,Timer as tmr
from engineio.payload import Payload
import base64
import io
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
someList = ['apple', 'peas', 'juice','orange']
i=0
#socketio.on('connect')
def connect():
print("a client connected")
#socketio.on('disconnect')
def disconnect():
print('Client disconnected')
#socketio.on('msg')
def handlemsg(msg):
print (msg)
socketio.send("msg from server")
#app.route('/')
def hello():
return "hii"
if __name__ == '__main__':
socketio.run(app,host= '0.0.0.0')
Client side (flutter)
#override
void initState() {
super.initState();
IO.Socket socket = IO.io('http://x.x.x.x:5000', <String, dynamic>{
'transports': ['websocket', 'polling']});
socket.connect();
socket.emit('msg', 'test');
socket.onConnect((_) {
print('connect');
socket.emit('msg', 'testing');
});
socket.onDisconnect((_) => print('disconnect'));
socket.on('*', (data) => print(data)); //nothing is printed
}
The result I get on the server-side:
a client connected
testing
However, I get no data on the client side. Where am I going wrong? Please help

I can't test it with flutter but I tested it with client create with python-socketio
Main problem can be that send() sends message with name "message" like emit("message", ...) but your on("msg", ...) expects message with name "msg", not "message".
So you should use emit("msg", ...) in Python and on("msg", ...) in flutter.
Or you should use send() in Python and on("message", ...) in flutter.
Other problem can be that it may need some time to send message and receive it - and it may need extra time after connecting and extra time befor disconnecting - at least in my example I had to sleep to get results.
Full working code.
I added more emit() with different names.
server.py
from flask import Flask
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('connect')
def connect():
print("client connected")
#socketio.on('disconnect')
def disconnect():
print('client disconnected')
#socketio.on('question')
def handle_questio(msg):
print('question msg:', msg)
socketio.emit("answer", "msg from server")
#socketio.on('help')
def handle_help(msg):
print('help msg:', msg)
socketio.emit("support", "help from server")
#app.route('/')
def hello():
return "hii"
if __name__ == '__main__':
print('start')
socketio.run(app, host='0.0.0.0')
client.py
import socketio
sio = socketio.Client()
#sio.on('connect')
def connect():
print('connected')
#sio.on('disconnect')
def disconnect():
print('disconnected')
#sio.on('answer')
def answer(data):
print('answer:', data)
#sio.on('support')
def support(data):
print('support:', data)
# --- main ---
print('start')
sio.connect('http://localhost:5000')
print('sleep')
sio.sleep(1)
print('emit question')
sio.emit('question', {'foo': 'bar'})
print('emit help')
sio.emit('help', 'can you help me')
print('sleep')
sio.sleep(1)
sio.disconnect()

Related

Socketio background task not running

I am creating a multiplayer online game, and am using socket io for the game server. Below is my server code
import socketio
import time
from aiohttp import web
sio = socketio.AsyncServer(async_mode='aiohttp', cors_allowed_origins='*', async_handlers=True)
app = web.Application()
sio.attach(app)
#sio.on('connect')
def connect(sid, environ):
print("connected: ", sid)
#sio.on('disconnect')
def disconnect(sid):
print('disconnect ', sid)
async def background_thread():
while True:
print("here")
sio.emit('message', {'data': 'Server generated event'})
time.sleep(5)
if __name__ == '__main__':
print ("Starting server")
sio.start_background_task(background_thread)
web.run_app(app, port=3000)
But the problem is the above code starts up the server but the background task is not running, where am I going wrong?

How to mount socket.io to fastapi app and send broadcast to all connected clients

I tried to create fastapi application that uses websockets and could broadcast messages to all connected clients. I found out that it's not possible with websockets but found briliant library - socket.io. However I am not sure how could I use it and integrate it with my existing fastapi app.
# server.py
from typing import Any
import uvicorn
from fastapi import FastAPI
import socketio
sio: Any = socketio.AsyncServer(async_mode="asgi")
socket_app = socketio.ASGIApp(sio)
app = FastAPI()
#app.get("/test")
async def test():
print("test")
return "WORKS"
app.mount("/", socket_app) # Here we mount socket app to main fastapi app
#sio.on("connect")
async def connect(sid, env):
print("on connect")
#sio.on("direct")
async def direct(sid, msg):
print(f"direct {msg}")
await sio.emit("event_name", msg, room=sid) # we can send message to specific sid
#sio.on("broadcast")
async def broadcast(sid, msg):
print(f"broadcast {msg}")
await sio.emit("event_name", msg) # or send to everyone
#sio.on("disconnect")
async def disconnect(sid):
print("on disconnect")
if __name__ == "__main__":
kwargs = {"host": "0.0.0.0", "port": 5000}
kwargs.update({"debug": True, "reload": True})
uvicorn.run("server:app", **kwargs)
# client.py
import requests
import socketio
r = requests.get("http://127.0.0.1:5000/test") # server prints "test"
cl = socketio.Client()
cl2 = socketio.Client()
#cl.on("event_name")
def foo(data):
print(f"client 1 {data}")
#cl2.on("event_name")
def foo2(data):
print(f"client 2 {data}")
cl.connect("http://127.0.0.1:5000/") # server prints "on connect"
cl2.connect("http://127.0.0.1:5000/")
cl.emit("direct", "msg_1") # prints client 1 msg_1
cl2.emit("broadcast", "msg_2") # prints client 2 msg_2 and client 1 msg_2
At the end install proper dependencies:
# server.py
pip install python-socketio uvicorn fastapi
# client.py
pip install requests websocket-client

Flask Socket-IO Server Client Not Communicating (with tweepy and twilio)

I am trying to have a Flask Server that allows me to launch a tweepy stream and on every message received in the stream listener, it sends that message to a socketio client. The Flask server is at the same time supposed to allow Twilio to post to it, and route that message to the client—so that the client is receiving messages from both Twilio and twitter.
I have been trying to get the server to send messages over to the client for the data incoming from twitter, the code for Twilio works just fine. It sends data over to the client on message receipt. The main loop in tweepy is also not locking up the program—I can test print statements and see tweets and the incoming sms's being printed in the handle_message(msg) function asynchronously. I feel like there must be something really simple that I am missing here since the SMS's are emitted to the client, but the incoming tweets are not, even though they are propagating through to the handle_message(msg) function. What gives?
server.py
from flask import Flask, json, request
from twilio.twiml.messaging_response import Message, MessagingResponse
from flask_socketio import SocketIO
import tweepy
import json
PATH = '/path/to/credentials/'
with open(PATH, "r") as file:
credentials = json.load(file)
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'abc123'
sio = SocketIO(app, cors_allowed_origins="*")
auth = tweepy.OAuthHandler(credentials['CONSUMER_KEY'], credentials['CONSUMER_SECRET'])
auth.set_access_token(credentials['ACCESS_TOKEN'], credentials['ACCESS_SECRET'])
api = tweepy.API(auth)
class MyListener(tweepy.StreamListener):
def on_status(self, status):
print('status')
def on_data(self, data):
handle_message(data)
def on_error(self, status):
print('error')
print(status)
stream_listener = MyListener()
# twilio sms route
#app.route('/sms', methods=['POST'])
def sms():
number = request.form['From']
message_body = request.form['Body']
message_data = {"number": number, "msg": message_body}
resp = MessagingResponse()
resp.message('Hello {}, you said: {}'.format(number, message_body))
handle_message(message_data)
return str(resp)
# flask-socketio stuff
#sio.on('connect')
def connect():
print('connected')
sio.emit('client_connected', "you connected")
search_term = "#mysearchterm"
stream = tweepy.Stream(auth=api.auth, listener=stream_listener)
stream.filter(track=[search_term], is_async=True)
sio.emit('client_connected', "the search term is {}".format(search_term))
#sio.on('disconnect')
def disconnect():
print('Client Diconnected')
#sio.event
def handle_message(message):
print("This is the message received: ", message)
sio.emit('handle_message', message)
if __name__ == '__main__':
sio.run(app)
client.py
import socketio
client = socketio.Client()
#client.on('client_connected')
def on_connect(message):
print(message)
#client.on('handle_message')
def message(data):
print(data)
client.connect('http://localhost:5000/')
Twilio developer evangelist here.
You've decorated the handle_message function as #sio.event but as far as I can see in the docs, you should only do that to have the handle_message method respond to events on the socket called "handle_message".
I'd start be removing the #sio.event decorator.
I'm not a Python expert, but I also wonder whether there is a scope issue here. You define your MyListener class and create an instance of it before you define the handle_message method. Just to test, can you try emitting to the socket directly within the on_data method:
def on_data(self, data):
sio.emit('handle_message', data)
If that works, consider moving the definition of handle_message above the definition of MyListener.
I solved my problem! As I noted in this comment, the issue was with multithreading and passing information between the threads. With tweepy, the parameter is_async=True, which in 4.1.0 is threading=True, opens up a new thread once the stream is run.
Instead of trying to deal with passing information around, I exploited the extant flask-socketio functionality by using a local redis server as a message queue (start from the section "Using Multiple Workers" if you are setting this up for the first time, also be sure to install redis).
Here is the updated server.py code. The client.py code remained essentially unchanged:
import eventlet
eventlet.monkey_patch()
from flask import Flask, json, request
from twilio.twiml.messaging_response import Message, MessagingResponse
from flask_socketio import SocketIO
import tweepy
import json
PATH = '/PATH/TO/CREDENTIALS'
with open(PATH, "r") as file:
credentials = json.load(file)
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'abc123'
sio = SocketIO(app, message_queue='redis://', cors_allowed_origins="*")
class MyStream(tweepy.Stream):
def __init__(self, consumer_key, consumer_secret, access_token, access_secret):
super(MyStream, self).__init__(consumer_key, consumer_secret, access_token, access_secret)
self.stream_sio = SocketIO(message_queue='redis://')
def on_status(self, status):
print('status')
def on_data(self, data):
json_data = json.loads(data)
self.stream_sio.emit('handle_message', json_data['text'])
# TODO: Send along all necessary information
#app.route('/sms', methods=['POST'])
def sms():
number = request.form['From']
message_body = request.form['Body']
message_data = {"number": number, "msg": message_body}
resp = MessagingResponse()
resp.message('Hello {}, you said: {}'.format(number, message_body))
handle_message(message_data)
return str(resp)
#sio.on('connect')
def connect():
print('connected')
sio.emit('client_connected', "you connected")
search_term = "#testingtesting123"
stream = MyStream(credentials['CONSUMER_KEY'], credentials['CONSUMER_SECRET'],
credentials['ACCESS_TOKEN'], credentials['ACCESS_SECRET'])
stream.filter(track=[search_term], threaded=True)
sio.emit('client_connected', "the search term is {}".format(search_term))
#sio.on('disconnect')
def disconnect():
print('Client disconnected')
def handle_message(message):
sio.emit('handle_message', message)
if __name__ == '__main__':
sio.run(app)

How do i run a Python script on a dynamic webpage with Flask and Socketio?

I'm trying to use Flask and SocketIO, i found this example where some random numbers are printed dynamically in real time on a 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
__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):
"""
Generate a random number every 1 second and emit to a socketio instance (broadcast)
Ideally to be run in a separate thread?
"""
#infinite loop of magical random numbers
print("Making random numbers")
while not thread_stop_event.isSet():
number = round(random()*10, 3)
print(number)
socketio.emit('newnumber', {'number': number}, 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)
I have a Python script which connects to a Websocket, receives data and prints this data.
import websocket
from bitmex_websocket import Instrument
from bitmex_websocket.constants import InstrumentChannels
from bitmex_websocket.constants import Channels
import json
websocket.enableTrace(True)
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()
I now want to print this data on my webpage, i tried to "merge" these two scripts but apparently i can't, because to run the Websocket connector i have to run XBTUSD.run_forever(), which will start the process but it won't run the rest of the code, including the Flask part which generates the webpage, so only one at time can run.
Is there a way to make the Websocket connector communicate with the Flask/Socketio part so that the data from the Websocket connector is printed on the webpage?

Send WebSocket message from Flask view

I'm trying to make a Flask app that uses WebSockets. The example from Flask-sockets works but how would I send a message from a regular view?
Similarly to how Flask-SocketIO use .emit() and .send()-methods.
In the example below (from the Flask-Sockets example) I would for instance like to be able to broadcast a message from the hello-view.
from flask import Flask
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
#sockets.route('/echo')
def echo_socket(ws):
while not ws.closed:
message = ws.receive()
ws.send(message)
#app.route('/')
def hello():
# How can I send a WebSocket message from here?
return 'Hello World!'
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
You can use a global socket list of all client. Traverse all list and send message to all ws instance.
Example code;
from flask import Flask, render_template
from flask_sockets import Sockets
app = Flask(__name__)
sockets = Sockets(app)
ws_list = []
#sockets.route('/echo')
def echo_socket(ws):
ws_list.append(ws)
while not ws.closed:
message = ws.receive()
ws.send(message)
#app.route('/')
def hello():
# How can I send a WebSocket message from here?
return render_template('index.html')
#app.route('/send_message_to_all_client')
def broadcast():
for ws in ws_list:
if not ws.closed:
ws.send("broadcast message")
else:
# Remove ws if connection closed.
ws_list.remove(ws)
return "ok"
if __name__ == "__main__":
from gevent import pywsgi
from geventwebsocket.handler import WebSocketHandler
server = pywsgi.WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()

Categories