Emit socket.io message with Python using nodejs as server - python

I need a bit of help.
I'm doing tests to learn how to build a realtime web, so I use node.js with socket.io. All works fun but if I try to publish some message in the channel that is listening node with a different source that isn't node or javascript it crashes.
Server side: (node that fails when a external publish is sended)
var app = require('express')();
var http = require('http').Server(app);
var pub = require('redis').createClient(6379, 'localhost', {detect_buffers: true, return_buffers: false});
var sub = require('redis').createClient(6379, 'localhost', {return_buffers: true});
var io = require('socket.io')(http);
var redis = require('socket.io-redis');
io.adapter(redis({pubClient: pub, subClient: sub, host: '127.0.0.1', port: 6379}));
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
console.log("something happens: " + msg);
});
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
You don't need the client-side code for try it, just put this code and run it with node. When it is running, try to publish on the channel with Redis directly and see whats happens.
Error: 5 trailing bytes
at Object.decode (.../node/node_modules/msgpack-js-v5/msgpack.js:266:47)
at Redis.onmessage (.../node/node_modules/socket.io-redis/index.js:93:24)
at emitTwo (events.js:87:13)
at RedisClient.emit (events.js:172:7)
at RedisClient.return_reply (.../node/node_modules/redis/index.js:654:22)
at .../node/node_modules/redis/index.js:307:18
at nextTickCallbackWith0Args (node.js:419:9)
at process._tickCallback (node.js:348:13)
enter code here
Somebody understands why this happen? How can I fix it?
Thank you!
NEW COMMENT:
Thanks to robertklep I know that it need to use the same protocol, so I wrote a simple Python script using it, but it fails with the same error.
import redis
import msgpack
text_packed = msgpack.packb('refresh', use_bin_type=True)
r = redis.StrictRedis(host='localhost', port=6379, db=0)
r.publish('socket.io#/#', text_packed)
I also tried this approach, I think Im passing some param wrong:
from emitter import Emitter
io = Emitter(dict(host='localhost', port=6379))
io.Emit('chat message', "message from python!")
# or specificating the room
io.To("socket.io#/#").Emit('chat message', "message from python!")
In this case, nothing arrives to redis.

socket.io-redis uses msgpack on top of Redis to pub/sub messages, so you can't just push regular strings to it and expect it to work. The client you're using needs to be talking the same protocol.

Related

Shutting down Flask application from C#?

I am relaying HTTP requests from a C# application by sending JSON data to a localhost flask application, sending the requests with python, and relaying the response back to my C# application. Needs to be done this way because the server I am dealing with is 3rd party and fingerprints SCHANNEL requests and sends back dummy data (Does this with Powershell as well, but not curl, Postman, or Python).
var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = #" /k python Assets\Scripts\server.py",
UseShellExecute = true
};
process.Start();
I found this solution, which uses an endpoint (/shutdown)
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
Get a warning that it is being deprecated. I can live with that, but my OCD makes me want to do this properly. The warning tells me this is a hacky solution.
I am new to python/flask. What would be a good way about going about this?
Sidenote: process.Kill() doesn't work. Wish it did.
process.CloseMainWindow() seems to do the trick from my initial tests. Why process.Close() or process.Kill() do not work, is beyond me.

How to setup SocketIO connection to NodeJS websocket from Python client?

I've got a simple nodejs server that runs socketio and I can do 2 way communication with the client from the HTML. Now I'm also trying to connect to the same nodejs websocket from a Python script, but not getting connected.
Simplified Node JS webserver:
var http = require('http').createServer(handler);
var fs = require('fs');
var io = require('socket.io')(http)
http.listen(8080);
function handler (req, res) {
fs.readFile(__dirname + '/public/index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
return res.end();
});
}
io.sockets.on('connection', function (socket) {
setInterval(() => {
socket.emit('temp', 'tempfromserver')
}, 1000)
});
The Python script that wants to connect to the nodejs with websocket:
import socketio
sio = socketio.Client();
sio.connect('http://localhost:8080')
#sio.event
def message(data):
print('received message')
def connect():
print('socketio connected')
Is it possible to connect with a websocket via socketio to the nodejs server? If so, what am I doing wrong?
End goal is to collect sensor data from python script on raspberry pi and send to nodejs server which in its turn saves it to DB and sends through to HTMl client. Perhaps there is a better setup to do this.
I believe I asked a similar question and got an answer. My setup was a little different, and used a web-socket, but it will at least allow you to connect between Node JS and Python, and then maybe you can build from there, Using Socket IO and aiohttp for data transfer between node JS and Python. The setup was also originally based off a html script on the node JS side, so that may help as well in comparing it to your setup.

react + socket.io emits not going through - basic error

There must be a simple mistake in my understanding of reactjs or socket.io. I have a server that sends "speed" values iterating from 2 to 5, and a client that receives them and displays them.
The issue:
Expected behavior: client displays numbers iterating from 1 to 5 every second and stops at 5. Client logs that it has received 4 messages with updated speed value (a new message every second)
Actual behavior: client displays a speed of 1. Client waits 4 seconds. Client displays a speed of 5 and, in that moment, logs having received the 4 messages with iterating speed from the server.
What is the issue? It's almost as if the server is sending all 4 speed messages at the same time.
Client code:
import React from 'react';
import {CircleGauge} from 'react-launch-gauge';
import io from 'socket.io-client';
class App extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
speed: 1
};
}
componentDidMount() {
const socket = io('http://localhost:5000');
socket.on('data update', data =>
this.setState( { speed: data },
() => console.log("got the speed: " + this.state.speed)));
socket.open();
}
render() {
return (
<div>
<p> The velocity received is: {this.state.speed} </p>
</div>
);
}
}
export default App;
Server Code:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
import time
sendData = False;
app = Flask(__name__)
socketio = SocketIO(app)
#socketio.on('connect')
def dataSent():
print('they connected**********************************')
for i in range(2,6):
socketio.emit('data update', i)
time.sleep(1)
print(i)
if __name__ == '__main__':
socketio.run(app, debug = True)
When the client requests the websocket connection via
const socket = io(‘ws://localhost:5000’);
it will have to wait until the connection is established first, before it can do anything with the message. The connection is established only when
#socketio.on(‘connect’)
def ...
is finished. So it looks like the client waits until all the emit is done, and then start reacting to the messages.
You probably need to make your for-loop asynchronous so that the server responds to the client about the connection first before it emits the data. For example, you can carve out the for-loop into a separate function and use flask’s background task:
#socketio.on(‘connect’)
def dataSent():
print(‘...’)
socketio.start_background_task(target=emitloop)
def emitloop():
for i in range(2,6):
socketio.emit(‘data update’, i)
time.sleep(1)
(If flask is configured to use gevent for the background task, then you’ll need to install gevent or flask’s gevent plug-in.)
You might also try to use function based setState (i.e. passing a function to setState rather than the state object), because setState is asynchronous and react can combine them together otherwise.

I need to host node js through python

var util = require('util');
var exec = require('child_process').spawn;
var run = exec('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002']);
run.stdout.on('data', function(data){
console.log('stdout: ' + data.toString());
});
run.stderr.on('data', function (data) {
console.log('stderr: ' + data.toString());
});
test.py
from bottle import route, run, template
#route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=9002)
I am new to node js and python just i want do communicate between node js to python with localhost. A simple python script with localhost url to hit node js url after running node js scrpit whih call python script in node and host the same on web browser.
Not entirely sure I see the problem. Your code works.
1) Make sure you access localhost:9002
2) If you meant to run your bottle code, then use
var run = exec('/usr/bin/python', ['/path/to/bottle_server.py']);
As for communicating back and forth between the Python code and the Node.js code, then you need sockets. Some libraries to look at could include socket.io or use a messaging queue like zmq.
If you want one-way communication to your python API, then you need to perform HTTP requests to http://localhost:9002 from the Node code. Alternatively, Node is very much capable of the same functionality you've included in the Python code on its own.
EDIT
Regarding below comments, here is an updated script. You need to inherit the parent's stdout and stderr, otherwise, as you see in the image above, it thinks python is printing to stderr
var util = require('util');
const spawn = require('child_process').spawn;
var run = spawn('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002'],
{ stdio: ['ignore', 'inherit', 'inherit' ] });
run.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

How to handle multiple clients asynchronously , on a web socket using python?

I'm basically building a visual trace route application. The trace route is basically done using a python code and the results are send to the HTML page in real time using web socket. I basically need to do long polling( the server receives one request, process it and sent a maximum of 30 replies to each client at regular or irregular intervals), as well as handle multiple clients. I basically manipulated the below code to work for my application. I found the code from Asynchronous Bottle Framework
from bottle import request, Bottle, abort
app = Bottle()
#app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while True:
try:
message = wsock.receive()
wsock.send("Your message was: %r" % message)
except WebSocketError:
break
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketHandler, WebSocketError
server = WSGIServer(("0.0.0.0", 8080), app,
handler_class=WebSocketHandler)
server.serve_forever()
It does work on a single request. When I issue the second one.. 'wsock.send()' fails... it shows socket dead error. Could someone guide me on, how to handle multiple clients as well. Like, should I spawn a different process for each client ? What if a client requests trace for one domain, and again(before the full result is provided to him) requests for another. Thanks in advice
Client side code :
<script type="text/javascript">
var ws = new WebSocket("ws://example.com:8080/websocket");
ws.onopen = function() {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
alert(evt.data);
};

Categories