Flask-Socketio emitting from an external process - python

I've been working on a project using flask, flask-socketio and redis
I have a server, and some modules I would like to be able to emit from outside of the server file.
server.py
from flask import Flask, Response, request, json
from flask_socketio import SocketIO, join_room, leave_room, emit
app = Flask(__name__)
socketio = SocketIO()
socketio.init_app(
app,
cors_allowed_origins="*",
message_que="redis://127.0.0.1:6379/0"
)
#socketio.on('ready')
def ready(data):
socketio.emit('rollCall', { 'message': 'Ive got work for you' }, room='Ready')
...
jobque.py
from modules.server.server import socketio
...
socketio.emit('rollCall', { 'message': 'Ive got work for you' }, room='Ready')
As it's currently configured, emits from the server file all work, the clients respond and they can talk back and forth. But when jobque goes to emit the same message, nothing happens. There's no error, and the client doesn't hear it.
I'm also using redis for things other than the websockets, I can get and set from it with no problem, in both files.
What do I need to do to get this external process to emit? I've looked through the flask-socketio documentation and this is exactly how they have it setup.
I've also tries creating a new SocketIO object inside jobque.py instead of importing the one form the server, but the results are the same
socket = SocketIO(message_queue="redis://127.0.0.1:6379/0")
socketio.emit('rollCall', { 'message': 'Ive got work for you' }, room='Ready')
I also went and checked if I could see the websocket traffic in redis with the message que setup using redis-cli > MONITOR, but I don't see any. I only see the operations I'm using redis for directly with the redis module. This makes me think the message que isn't actually being used, but I can't know for sure.

Unfortunately spelled message_queue as message_que was the issue.
Creating a new SocketIO instance without the app works now.

Related

Is there a way to easily communicate data from a python/flask app to a node.js app?

So here is the issue...I have had to use two separate SDK's for telnyx due to each offering a functioning service the other did not. One is in Python, one is in Node. Essentially I am sending a message from my phone to a telnyx API endpoint in python, and what I am hoping to do is communicate the number, and the message received in python over to my node.js app, which I will not have a problem formatting. I am just confused about how to communicate data between the two. Open to the smoothest suggestions. It is all server side, no client, just sending messages to a server and responding to them with another server based on the content of the messages.
Python/flask below:
import os
from flask import Flask, request
app = Flask(__name__)
#app.route('/webhooks', methods=['POST'])
def webhooks():
body = request.json
messageSenderNumber = body['data']['payload']['from']['phone_number']
messageSenderMessage = body['data']['payload']['text']
newMessageSenderMessage = messageSenderMessage.lower()
print(f"You have a new message from {messageSenderNumber}: {newMessageSenderMessage}")
return '', 200
if __name__ == "__main__":
app.run(port=5000)
Here is the Node:
var telnyx = require('telnyx').
('KEY0178B7161E6B3873C151BDC3597EE42B_SHXIHH1anGGOgfhcIb3kjQ');
telnyx.messages.create(
{
'from': '+12182101811', // Your Telnyx number
'to': '+18646662611',
'text': 'Hello, World!'
},
function(err, response) {
console.log(response);
}
);
My goal is to take the newMessageSenderMessage and messageSenderNumber variable's data and export it into my node app, that is all I need. Nothing crazy, just a phone number and a string from the python server side code, and same in node.
Thanks in advance.
Replace your return statement in the flask with this.
This should send back a JSON to your Node.js app
return {"newMessageSenderMessage": newMessageSenderMessage, "messageSenderNumber": messageSenderNumber}

JavaScript EventSource triggers onerror after every received message

I have a web app utilizing Python Flask where I am trying to use Server Sent Events (SSEs) to push messages to web pages without having to poll from the client side or request that data. I'm using Redis to listen for new data which will then be sent to the web page. To start and make sure that I can use SSEs correctly, I've used a template similar to an example like this (How to implement server push in Flask framework?).
The problem I'm running into is that every time the client receives a message, the EventSource onmessage() method is called and delivers the message properly, but then the .onerror() method immediately gets triggered, causing the client to try to reconnect. This results in the '/listen' endpoint being called over and over and over, leading to the creation of many redis pubsub objects that are redundant and subscribe to the same channels.
The python code that runs the flask app is as follows
import flask
from flask_bootstrap import Bootstrap
from redis import Redis
from flask_wtf import FlaskForm
app = flask.Flask(__name__)
bootstrap = Bootstrap(app)
red = Redis(host='localhost', port=6379, db=0)
#app.route('/listen')
def listen():
pubsub = red.pubsub()
pubsub.subscribe('chat')
def stream():
for message in pubsub.listen():
if message['type'] == 'message':
msg = f"data: {message['data'].decode('utf-8')}\n\n"
yield msg
for msg in stream():
return Response(msg, mimetype='text/event-stream')
#app.route('/sse_page', methods=['GET', 'POST'])
def sse_page():
form = FlaskForm()
return render_template('sse_page.html', title='Server Push Testing', form=form)
if __name__ == "__main__":
app.run(port=8000, threaded=True, debug=True)
The corresponding section of sse_page.html where I try to open the EventSource and listen for the events stream is
<body>
<div id="target_div">Watch this space...</div>
</body>
<script>
var source = new EventSource("/listen");
source.onmessage = function (event) {
console.log('data: ', event)
$("#target_div").text(event.data)
};
source.onerror = function (event) {
console.log('error ', event)
};
source.onopen = function (event) {
console.log('open', event)
};
</script>
Using the redis-cli to send messages like those seen
here (and transcribed below)
127.0.0.1:6379> publish chat a
(integer) 1
127.0.0.1:6379> publish chat b
(integer) 2
Result in the console logging messages from Eventsource.onopen(), Eventsource.onmessage(), and Eventsource.onerror() for every single message, as seen
here.
I cannot figure out why the eventsource has an error after every single message that is received or how to prevent that from happening.
The answer to this question is NOT a problem in the code itself.
What this ended up being was an issue with the anti-virus security that was being used on the machine. Using Sophos AV Endpoint was causing each SSE to be treated as a download, and so any of the text data was unable to be streamed until the 'download was complete'.
This is (apparently) a known issue (see link https://community.sophos.com/on-premise-endpoint/f/sophos-endpoint-software/74878/server-sent-events-blocked-by-download-scanner) and there are a couple of ways to deal with it. You can either disable web scanning by Sophos (which does not work if you do not have administrator permissions) or run the flask app securely over HTTPS (https://blog.miguelgrinberg.com/post/running-your-flask-application-over-https has a great tutorial).
Credit too should go to this post (JavaScript EventSource SSE not firing in browser), which is how I was able to find that the AV software was what ended up causing my issues.

Woocomerce webhook not being recieved

I am playing around with the webhooks of WooCommerce and i have setup a hook that triggers when an item is being added to a cart.
I have a little Flask app that listens to requests and prints them out.
from flask import Flask, request, Response
app = Flask(__name__)
#app.route('/webhook', methods=['POST'])
def respond():
print(request.json);
return Response(status=200)
This script is being run on the same machine as the Wordpress server.
But when i add an item to my cart no calls are being made.
Does anyone know what i am doing wrong?
I still am unable to trigger any webhook to an url that points to an service on the same machine. I tried running my endpoint in a docker container and addressing the ip address of the container. I also tried making custom dns entries in my host file. Still didnt work. Eventually fixed my problem by using ngrok.

Difficulty accessing Google Text-to-Speech API from within Flask app

I am having difficulties accessing Google's texttospeech Python API from within a Flask app. The app is running in a container with Debian 10, Nginx/Gunicorn, and Python 3.7 installed. In the code below, the client connects successfully, but the synthesize_speech request hangs indefinitely (without any error message). When I run the same code from a Python script in the same container without Flask, the speech synthesis request is successful. However, I can call other external APIs, such as those at AWS, from my Flask app without any problems.
What could be causing this or how I could go about diagnosing the problem? I have tried switching to version 1.0.1 of the texttospeech library, but without success. Presumably the problem isn't my credentials, which I believe I have set up correctly, as otherwise the connection request wouldn't be successful.
from google.cloud import texttospeech
# Connect (this is successful)
client = texttospeech.TextToSpeechClient()
input_text = texttospeech.SynthesisInput(text="God dag")
voice_parameters = texttospeech.VoiceSelectionParams(
language_code="sv-SE",
name="sv-SE-Wavenet-A"
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
# Synthesize speech (this never completes)
response = client.synthesize_speech(
request={
"input": input_text,
"voice": voice_parameters,
"audio_config": audio_config
}
)
pip freeze
google-api-core==1.22.1
google-auth==1.20.1
google-cloud-texttospeech==2.2.0
googleapis-common-protos==1.52.0
grpcio==1.31.0
...
It turns out the issue was caused by monkey_patching in gunicorn's gevent worker class. I have managed to resolve the issue by changing the worker_class in gunicorn to "sync", as suggested on this page for a similar issue:
https://github.com/googleapis/google-cloud-python/issues/5848

How to contact flask-restful api from react native app?

i am new to backend dev. I try to developp a flask restful api. I followed the documentation and made the suggested minimal api, that is just returning a jsonified dict. With postman, curl and in the browser, no problem, the api is running and responds to my requests.
From my react native app however, i always get a Netwrok Error.
I tried lots of things:
- multiple IP addresses for the flask serveur
- differents ways to use axios
- different os : win10, ubuntu
- different endpoints : /, /api, /test
- different ways of writing the api (flask-restful class, flask app functions ...)
- manips from web documentations : dev mode of my device, chrome dev tools (port forwarding)
- i asked a react native developper to check my client-side code, nothing wrong according to him,
precisions :
- python code runs under a conda virtual env
- appli runs under node js and expo
- container folders of my app and my api are at the same level
- the flask server does not respond 404 or whatever, it does not respond at all, the error returned in react native is a network error
- depending on url, the network errors occurs immediately or after a 2 minutes delay
- flask shows requests and status when called by postman, curl, chrome, but does not react when i press my buttons from the react native app
Here is (one of) my python code:
from flask import (Flask, jsonify)
# from flask_restful import Resource, Api
from flask_cors import CORS, cross_origin
app = Flask(__name__)
CORS(app)
#app.route("/api", methods=["GET"])
def get():
return jsonify(hello='bouh !')
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
and here is the clientside code:
import React, {Component} from 'react';
import { View, Button } from 'react-native';
import axios from 'axios';
import { sharedStyles } from '../../SHARED/_shared';
var url = "http://192.168.1.16:5000/api";
export default class PrevCommune extends Component {
constructor(props){
super(props);
this.navigation=this.props.navigation;
};
getAxios=()=>{
axios.get(`${url}`).then((response)=>{
console.log("succes axios :",response);
}).catch((error)=>{
console.log("fail axios :", error);
});
};
getFetch=()=>{
fetch(url).then((response)=>{
console.log("succes fetch :",response)
}).catch((error)=>{
console.log("fail fetch :",error)
})
}
render(){
return (
<View style={sharedStyles.mainContainer}>
<Button onPress={()=>this.getAxios()} title={"get axios"}></Button>
<Button onPress={()=>this.getFetch()} title={"get fetch"}></Button>
</View>
);
};
};
And the lines returned by requests:
fail axios : [Error: Network Error]
fail fetch : [TypeError: Network request failed]
I saw lots of tutos, videos, articles on flask api but i didn't find where i am wrong. Please tell me if you have any ideas ! I think both client and server codes are ok, the problem seems to be that my requests are blocked by something.
Solved : the probleme was my firewall ... thank you ricardo for the CORS doc =)
What worked for me was to change the IP address of localhost to my network IP in the api call in react native and then starting the flask application using the below command.
flask run --host=0.0.0.0

Categories

Resources