Flask Socket.io doesn't work when emitting from thread - python

Description
The client side has 2 buttons:
One makes the server to send periodic messages
The other, stops the sending of periodic messages
This problem is a proxy of the real problem I am trying to solve.
I build the app, and in the server side it seems to work, but the client doesn't receive the server push, but is able to start the push and kill it!
What I tried
Server Side
import random
from threading import Thread
from time import sleep
from flask import Flask
from flask_socketio import SocketIO
SOCKET_NAMESPACE = '/test'
is_pushing = False
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!!'
socketio = SocketIO(app)
def server_push(fps):
dt = 1 / fps
global is_pushing
while is_pushing:
with app.test_request_context('/'):
sent = f"Server Pushed!! {random.random()}"
print(sent)
socketio.emit("serverResponse", sent, namespace=SOCKET_NAMESPACE)
sleep(dt)
#socketio.on('connect', namespace=SOCKET_NAMESPACE)
def on_connect():
print("connected server!!")
socketio.emit("serverResponse", "First Push", namespace=SOCKET_NAMESPACE)
#socketio.on('disconnect', namespace=SOCKET_NAMESPACE)
def on_disconnect():
print("disconnected server!!")
#socketio.on('startServerPush', namespace=SOCKET_NAMESPACE)
def on_start_server_push(fps=1):
print("Sever push start!!")
global is_pushing
is_pushing = True
socketio.emit("serverResponse", "Start Push", namespace=SOCKET_NAMESPACE)
Thread(target=lambda: server_push(fps)).start()
#socketio.on("killServerPush", namespace=SOCKET_NAMESPACE)
def on_kill_server_push():
print("Server push stop!!")
global is_pushing
is_pushing = False
socketio.emit("serverResponse", "Kill Push", namespace=SOCKET_NAMESPACE)
def main():
socketio.run(app, port=8082, debug=True)
if __name__ == '__main__':
main()
Client Side
import openSocket from 'socket.io-client';
import React, { Component } from 'react';
class Test extends Component {
state = {
pushedFromServer: [],
socket: null
};
componentDidMount() {
const url = 'localhost:8082/test';
const socket = openSocket(url);
socket.on('connect', () => console.log('Test connected!!'));
socket.on('disconnect', () => console.log('Test disconnected!!'));
socket.on('serverResponse', response => {
console.log(response);
const pushedFromServer = [...this.state.pushedFromServer];
pushedFromServer.push(response);
this.setState({ pushedFromServer });
});
this.setState({ socket });
}
killServerPush = () => {
this.state.socket.emit('killServerPush');
};
startServerPush = () => {
this.state.socket.emit('startServerPush');
};
render() {
return (
<div>
<button onClick={this.startServerPush}>
<h3>Start push from server</h3>
</button>
<button onClick={this.killServerPush}>
<h3>Kill push from server</h3>
</button>
<ul>
{this.state.pushedFromServer.map(value => (
<li>{value}</li>
))}
</ul>
</div>
);
}
}
export default Test;
Final Notes
In the client, I could receive the First Push, and the Start Push, I am also able to stop the periodic process from the client and restart it. I am not able to receive the periodic messages on the client.
Thanks

By looking at https://github.com/miguelgrinberg/python-socketio/issues/99, I found a solution to the issue.
Just need to change the server side.
Change line:
Thread(target=lambda: server_push(fps)).start()
to
socketio.start_background_task(target=lambda: server_push(fps))
And instead of using python sleep, use:
socketio.sleep(dt)

Related

Python SocketIO-client doesn't receive emits from nodeJS server

So this is what I am trying to do, I want to be able to send a message in a browser towards a python script. I've got to the point where I can send a message in the browser and the server sees it. For testing purposes I used io.emit('input', data) to send the data towards my python script but nothing happens on the python side.
script.py:
import socketio
sio = socketio.Client()
#sio.event
def connect():
print('connected')
#sio.on("input")
def on_input(key):
print(key)
sio.connect('http://192.168.2.9:5000', namespaces=['/justin'])
server.js:
const express = require('express')
const app = express();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
var justin = null;
app.use(express.static('public'));
io.of('/justin').on('connection', function(socket){
console.log('justin connected');
justin = socket;
});
io.on('connection', function(socket){
console.log('a user connected');
socket.on('event', (data) => {
io.emit('input', data)
})
socket.on('disconnect', () => {
//
})
});
http.listen(5000, function(){
console.log('listening on *:5000');
});
Is there something I'm not seeing or is this just not possible?
Thanks in advance!

Python: Push Notifications to Node.js Socket.io using Redis PubSub

Now my project use Django as API and NodeJs (SocketIO) as server which require Realtime for pushing Notifications
I try pushing Notifications to Node.js Socket.io using Redis PubSub but not success. Please check out my code error:
My Python code. I publish to myChannel sample message:
def test_vew(request):
REDIS_SERVER = redis.Redis(host='localhost', port=6379, db=0)
REDIS_SERVER.publish("myChannel", "Demo Message")
return Response({ "success": True }, status=200)
My NodeJS Code:
var app = require('http').createServer()
const PORT = process.env.PORT || 3000;
var redis = require('redis').createClient();
const server = app.listen(3000, () => console.log('listening on port 3000'))
//sockets
const io = require('socket.io').listen(app)
redis.subscribe('myChannel', (message) => {
console.log(`Got message ` + message)
})
io.sockets.on("connection", function(socket) {
console.log("A User Connected to SocketIO");
redis.on("pmessage", function(pattern, channel, message) {
console.log(channel, message);
});
});
When I run function in Django, My NodeJS Socket Subcribe can't grab message (Nothing log in console). I don't know the reason.

WebSocket with angular 6 gets destroyed

I'm trying to learn how to use WebSocket with a python backend and an Angular 6 front end.
It looks like the WebSocket connection gets destroy as the updates does only work when I put a breakpoint on the following line:
ngOnInit() {
this.sub = this.socketService.getQuotes()
.subscribe(quote => {
console.log('got price: ' + quote);
this.price = quote;
});
} // breakpoint
The backend is pretty simple:
def send_market_price():
threading.Timer(5.0, send_market_price).start()
print('sending price ws')
socketio.emit('market', market.update_market())
if __name__ == '__main__':
send_market_price()
print('starting')
socketio.run(app)
the service is basic too:
#Injectable()
export class SocketService {
public socket;
public observer: Observer<number>;
getQuotes(): Observable<number> {
this.socket = socketio(SERVER_URL);
this.socket.on('market', (res) => {
this.observer.next(res);
});
return this.createObservable();
}
createObservable(): Observable<number> {
return new Observable(observer => {
this.observer = observer;
});
}
Is there anything wrong in my code to do this basic feature?
EDIT
after some tests, it looks like that the backend is bugged. I did the same thing getting a Node.js code and it works great.
What is wrong with this python code:
import threading
from flask import Flask, jsonify
from flask_cors import CORS
from flask_socketio import SocketIO
from market_engine import market
from market_engine.market import RandomMarket
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
CORS(app)
market = RandomMarket()
#socketio.on('connect')
def connect():
print('Client connected')
#socketio.on('disconnect')
def disconnect():
print('Client disconnected')
def send_market_price():
threading.Timer(5.0, send_market_price).start()
print('sending price ws')
socketio.emit('market', market.update_market())
if __name__ == '__main__':
send_market_price()
print('starting')
socketio.run(app)

Using websocket to connect Unity(client) and Python(server)

I have made a program which allow me to send a message each time I pressed a space in a unity, and send it to python server using cherrpy.
The problem is though my 'websocket.py' successfully serving on localhost as followed, once i started unity player it just Close instantly with the error.Hope some one help!!
websocket.py
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
class Root(object):
#cherrypy.expose
def index(self):
return 'some HTML with a websocket javascript connection'
#cherrypy.expose
def ws(self):
# you can access the class instance through
handler = cherrypy.request.ws_handler
class AgentServer(WebSocket):
def opened(self):
print("Opened!")
def closed(self, code, reason):
print("Closed!")
def received_message(self,m):
self.send(m.data,m.is_binary)
if __name__ == "__main__":
cherrypy.config.update({
"server.socket_host": "127.0.0.1",
"server.socket_port": 3000,
})
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()
cherrypy.quickstart(Root(), "/", config={
"/ws": {
"tools.websocket.on": True,
"tools.websocket.handler_cls": AgentServer,
}
})
Client.cs
using UnityEngine;
using System.Collections;
using WebSocketSharp;
public class Client : MonoBehaviour {
private WebSocket ws;
// Use this for initialization
void Start () {
this.ws = new WebSocket("ws://127.0.0.1:3000");
this.ws.OnOpen += (sender, e) => {
Debug.Log("Opened");
};
ws.OnMessage += (sender, e) =>
{
Debug.Log("WebSocket Message Type: " + e.Type + ", Data: " + e.Data);
};
this.ws.OnClose += (sender, e) => {
Debug.Log("Closed");
};
this.ws.Connect();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyUp(KeyCode.Space))
{
Debug.Log ("Pressed");
ws.Send("Test Message");
}
}
void OnDestroy()
{
ws.Close();
ws = null;
}
}
ErrorCode in Unity
Closed
UnityEngine.Debug:Log(Object)
client:<Start>m__3E(Object, CloseEventArgs) (at Assets/client.cs:18)
WebSocketSharp.Ext:Emit(EventHandler`1, Object, CloseEventArgs) (at Assets/Packages/websocket-sharp/Ext.cs:1101)
WebSocketSharp.WebSocket:close(CloseEventArgs, Boolean, Boolean, Boolean) (at Assets/Packages/websocket-sharp/WebSocket.cs:917)
WebSocketSharp.WebSocket:fatal(String, CloseStatusCode) (at Assets/Packages/websocket-sharp/WebSocket.cs:1128)
WebSocketSharp.WebSocket:doHandshake() (at Assets/Packages/websocket-sharp/WebSocket.cs:1085)
WebSocketSharp.WebSocket:connect() (at Assets/Packages/websocket-sharp/WebSocket.cs:958)
WebSocketSharp.WebSocket:Connect() (at Assets/Packages/websocket-sharp/WebSocket.cs:2472)
client:Start() (at Assets/client.cs:20)
Anaconda Prompt -python websocket.py
[03/Oct/2016:22:11:59] ENGINE Listening for SIGTERM.
[03/Oct/2016:22:11:59] ENGINE Bus STARTING
[03/Oct/2016:22:11:59] ENGINE Set handler for console events.
[03/Oct/2016:22:11:59] ENGINE Starting WebSocket processing
[03/Oct/2016:22:11:59] ENGINE Started monitor thread '_TimeoutMonitor'.
[03/Oct/2016:22:11:59] ENGINE Started monitor thread 'Autoreloader'.
[03/Oct/2016:22:11:59] ENGINE Serving on http://127.0.0.1:3000
[03/Oct/2016:22:11:59] ENGINE Bus STARTED
127.0.0.1 - - [03/Oct/2016:22:12:03] "GET / HTTP/1.1" 200 48 "" "websocket-sharp/1.0"

Passing variables between clients with Flask

I'm trying to get some code to work but can't seem to get it right, The intention is that all the clients can see when a button is pushed.
At the moment I can get the client that presses the button to see the message but no other.
Py:
pushedDict = {}
#app.route('/buttons/')
def index():
return flask.render_template('index.html', port=port)
def wsgi_app(environ, start_response):
path = environ["PATH_INFO"]
if path == "/buttons/":
return app(environ, start_response)
elif path == "/websocket/":
handle_websocket(environ["wsgi.websocket"])
else:
return app(environ, start_response)
def handle_websocket(ws):
while True:
pushRecieve = ws.receive() # Receive pushed Buttons
gap = "Button" # Placeholder for later
pushedDict.update({gap:pushRecieve}) # Add to Dictionary
pushSend = json.loads(pushedDict[gap]) # Get from Dictionary
ws.send(json.dumps({'output': pushSend['output']})) # Send
pushedDict.update({gap:""}) # Clear Dictionary
JS Receive:
$(document).ready(function(){
$(function() {
if ("WebSocket" in window) {
ws = new WebSocket("ws://" + document.domain + ":{{port}}/websocket/");
ws.onmessage = function (msg) {
var getButtons = JSON.parse(msg.data);
$("p#log").html(getButtons.output );
};
};
});
JS Send:
var buttonQueue = [];
$("a.button1").mousedown(function(e){
e.preventDefault();
buttonQueue.push("button1")
ws.send(JSON.stringify({'output': buttonQueue}));
});
$("a.button1").mouseup(function(e){
e.preventDefault();
remove(buttonQueue, "button1");
ws.send(JSON.stringify({'output': buttonQueue}));
});
$("a.button2").mousedown(function(e){
e.preventDefault();
buttonQueue.push("button2")
ws.send(JSON.stringify({'output': buttonQueue}));
});
$("a.button2").mouseup(function(e){
e.preventDefault();
remove(buttonQueue, "button2");
ws.send(JSON.stringify({'output': buttonQueue}));
});
});
Appreciate a fresh point of view.
I'm no expert on WebSockets, but my impression is that the ws protocol only establishes an ongoing connection between client and server, allowing data to be sent from the server without constant requests from the client. Your Flask app doesn't know about any other clients connected; it only uses handle_websocket(ws) to talk to one client at a time. You have to tell your Flask app which clients are currently connected, then ws.send() the button press updates to all of them. I don't have any experience with this, but it looks like the most popular way to track ws-connected clients and send them updates is redis. I also found an example chat application that you could adapt for your needs. Hope this helps!

Categories