WebSocket with angular 6 gets destroyed - python

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)

Related

Post request from react to flask

I am trying to send a post request from react to flask using the following code:
function App() {
const [currentTime, setCurrentTime] = useState(0);
const [accessToken, setAccessToken] = useState(null);
const clicked = 'clicked';
useEffect(() => {
fetch('/time').then(res => res.json()).then(data => {
setCurrentTime(data.time);
});
}, []);
useEffect(() => {
// POST request using fetch inside useEffect React hook
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title: 'React Hooks POST Request Example',action: 'clicked' })
};
var myParams = {
data: requestOptions
}
fetch('http://127.0.0.1:5000/login', myParams)
.then(response => response.json())
.then(data => setAccessToken(data.access_token));
// empty dependency array means this effect will only run once (like componentDidMount in classes)
}, []);
return (
<div className="App">
<div className="leftPane">
<div className="joyStick" >
<Joystick size={300} baseColor="gray" stickColor="black" ></Joystick>
</div>
<p>The current time is {currentTime}.</p>
<p>The access token is {accessToken}.</p>
</div>
And the flask code is
from __future__ import print_function
from flask import Flask, jsonify, request
from flask_cors import CORS
import time
from flask import Flask
import sys
robotIP="10.7.4.109"
PORT=9559
app = Flask(__name__)
access_token='a'
action="d"
#app.route('/time')
def get_current_time():
return {'time': time.time()}
#app.route('/login', methods=['POST'])
def nao():
nao_json = request.get_json()
if not nao_json:
return jsonify({'msg': 'Missing JSON'}), 400
action = nao_json.get('action')
access_token= action+'s'
print(access_token, file=sys.stderr)
return jsonify({'access_token': access_token}), 200
But every time I run both them both, I get the 'msg': 'Missing JSON' message I have defined and the data from react is never available in flask,even though the get request works.I am not sure what I am doing wrong here.
The problem actually is that this is a cross origin request which must be allowed by the server.
Place this function on your Python code:
#app.after_request
def set_headers(response):
response.headers["Access-Control-Allow-Origin"] = "*"
response.headers["Access-Control-Allow-Headers"] = "*"
response.headers["Access-Control-Allow-Methods"] = "*"
return response
Note:
If react is served from the same server this won't be necessary.
You should set the value of these headers to be as strict as possible on production. The above example is too permissive.
You could serve your React aplication from Flask, thus not requiring these headers to be set. You could use something like this to serve the main react file:
#app.route('/', defaults={'path': ''})
#app.route('/<string:path>')
#app.route('/<path:path>')
def index(path: str):
current_app.logger.debug(path)
return bp_main.send_static_file('path/to/dist/index.html')
Where path/to/dist/index.html would be on the static folder.
See more at:
MDN Web docs
Stackoverflow: How to enable CORS in flask
Stackoverflow: Catch all routes for Flask

Unable to send flutter GET request to python local server

I've made a simple flutter web app with TextField() and a Text() widget. When I press the button I expect it to send a query to the simple flask app made using python where it will returns the inverted text and I display that on the Text widget.
NOTE: Inverting text is not the actual task. Its just to check if I'm
able to get the data.
Python Code:
This code works when I run on the chrome.
#performing flask imports
from flask import Flask,jsonify
from flask.globals import request
app = Flask(__name__) #intance of our flask application
#Route '/' to facilitate get request from our flutter app
#app.route("/api",methods=["GET"])
def function():
d = {}
text = str(request.args["Query"])
text = text[::-1]
d["query"] = text
return jsonify(d)
if __name__ == "__main__":
app.run()
Flutter Code:
main.dart
import 'package:flutter/material.dart';
import 'api.dart';
import 'dart:convert';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String url;
var data;
String queryText = "Query";
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("PYTHON AND FLUTTER"),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
onChanged: (value) {
url = "http://10.0.2.2:5000/api?Query=" + value.toString();
},
decoration: InputDecoration(
hintText: "Search Anything Here",
suffixIcon: GestureDetector(
onTap: () async {
data = await getData(url);
var decodedData = jsonDecode(data);
setState(() {
queryText = decodedData["Query"];
});
},
child: Icon(Icons.search))),
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
queryText,
style: TextStyle(fontSize: 30.0, fontWeight: FontWeight.bold),
),
),
],
),
),
);
}
}
api.dart
import 'package:http/http.dart' as http;
Future getData(url) async {
http.Response response = await http.get(url);
return response.body;
}
I followed the tutorial from : This Youtube Video
I'm running the python code via Command Prompt and flutter app through VScode.
I'm getting the following errors:
Error: Expected a value of type 'Uri', but got one of type 'String'
at Object.throw_ [as throw] (http://localhost:50523/dart_sdk.js:5348:11)
at Object.castError (http://localhost:50523/dart_sdk.js:5319:15)
at Object.cast [as as] (http://localhost:50523/dart_sdk.js:5635:17)
at Function.as_C [as as] (http://localhost:50523/dart_sdk.js:5263:19)
at getData (http://localhost:50523/packages/word_prediction/api.dart.lib.js:29:47)
at getData.next (<anonymous>)
at runBody (http://localhost:50523/dart_sdk.js:39211:34)
at Object._async [as async] (http://localhost:50523/dart_sdk.js:39242:7)
at Object.getData (http://localhost:50523/packages/word_prediction/api.dart.lib.js:28:18)
at main._MyAppState.new.<anonymous> (http://localhost:50523/packages/word_prediction/main.dart.lib.js:422:48)
at Generator.next (<anonymous>)
at runBody (http://localhost:50523/dart_sdk.js:39211:34)
at Object._async [as async] (http://localhost:50523/dart_sdk.js:39242:7)
at http://localhost:50523/packages/word_prediction/main.dart.lib.js:421:210
at tap.TapGestureRecognizer.new.invokeCallback (http://localhost:50523/packages/flutter/src/gestures/recognizer.dart.lib.js:203:18)
at tap.TapGestureRecognizer.new.handleTapUp (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:417:40)
at tap.TapGestureRecognizer.new.[_checkUp] (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:223:12)
at tap.TapGestureRecognizer.new.acceptGesture (http://localhost:50523/packages/flutter/src/gestures/tap.dart.lib.js:199:23)
at arena.GestureArenaManager.new.sweep (http://localhost:50523/packages/flutter/src/gestures/arena.dart.lib.js:222:31)
at binding$5.WidgetsFlutterBinding.new.handleEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:402:27)
at binding$5.WidgetsFlutterBinding.new.dispatchEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:381:24)
at binding$5.WidgetsFlutterBinding.new.dispatchEvent (http://localhost:50523/packages/flutter/src/rendering/layer.dart.lib.js:6107:13)
at binding$5.WidgetsFlutterBinding.new.[_handlePointerEventImmediately] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:352:14)
at binding$5.WidgetsFlutterBinding.new.handlePointerEvent (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:325:43)
at binding$5.WidgetsFlutterBinding.new.[_flushPointerEventQueue] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:314:14)
at binding$5.WidgetsFlutterBinding.new.[_handlePointerDataPacket] (http://localhost:50523/packages/flutter/src/gestures/binding.dart.lib.js:304:65)
at Object.invoke1 (http://localhost:50523/dart_sdk.js:185426:7)
at _engine.EnginePlatformDispatcher.__.invokeOnPointerDataPacket (http://localhost:50523/dart_sdk.js:165747:15)
at _engine.PointerBinding.__.[_onPointerData] (http://localhost:50523/dart_sdk.js:166405:49)
at http://localhost:50523/dart_sdk.js:166863:28
at http://localhost:50523/dart_sdk.js:166816:16
at http://localhost:50523/dart_sdk.js:166509:11
I don't know what I'm doing wrong here.
Try this:
Future getData(String url) async {
var response = await http.get(Uri.parse(url));
return response.body;
}
Along this change https://stackoverflow.com/a/66517561/13592012 mentioned by Ουιλιαμ Αρκευα.
There was another problem:
When I use Break point it shows file call by blinding.dart
This was because of CORS.
Cross Origin Request(CORS) error which was because I did not set this up in my server.
This is especially if your flutter web application is not running in the same domain as the server where you api is running. Even if its on the same machine, you will have to allow the request from certain domain and ports.
This can be done by adding the following lines to flask code:
response.headers.add("Access-Control-Allow-Origin", "*")
and
response.headers.add("Access-Control-Allow-Credentials", "true")
So the updated code will be:
#performing flask imports
from flask import Flask,jsonify
from flask.globals import request
app = Flask(__name__) #intance of our flask application
#Route '/' to facilitate get request from our flutter app
#app.route("/api",methods=["GET"])
def word_predictor():
d = {}
text = str(request.args["Query"])
text = text[::-1]
d["Query"] = text
response = jsonify(d)
response.headers.add("Access-Control-Allow-Origin", "*")
response.headers.add("Access-Control-Allow-Credentials", "true")
return response
if __name__ == "__main__":
app.run()
And, with these two changes, code works fine.

CORS header 'Access-Control-Allow-Origin' missing despite header begin there

I'm making an api in flask-restful, and I'm trying to make a request, but when I try I get the error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://127.0.0.1:5000/events/. (Reason: CORS header 'Access-Control-Allow-Origin' missing)
My code is:
class Event(Resource):
def get(self, id=0):
if id == 0:
return random.choice(events), 200
for event in events:
if(event["id"] == id):
return event, 200, {'Access-Control-Allow-Origin': '*'}
return "Event not found", 404
I have added the header, but I stil get the error. Does anyone know what the problem is?
Also, if anyone needs it, the full code is here:
from flask import Flask
from flask_restful import Api, Resource, reqparse
import random
app = Flask(__name__)
api = Api(app)
events = [
{
"id": 0,
"starter": "a",
"dungeon": "test a",
"info": "A test event for the web app and api"
},
{
"id": 1,
"starter": "b",
"dungeon": "test b",
"info": "A test event for the web app and api 2"
}
]
class Event(Resource):
def get(self, id=0):
if id == 0:
return random.choice(events), 200
for event in events:
if(event["id"] == id):
return event, 200, {'Access-Control-Allow-Origin': 'file:///C:/Python/website%20test/index.html'}
return "Event not found", 404
api.add_resource(Event, "/events", "/events/", "/events/<int:id>")
if __name__ == '__main__':
app.run(debug=True)
Edit:
Here is how I am making the request:
let request = new XMLHttpRequest();
request.open("GET", "http://127.0.0.1:5000/events/");
request.send();
request.onload = () => {
if (request.status == 200) {
console.log(JSON.parse(request.response));
} else {
console.log('API offline');
}
}
install flask-CORS package.
pip install -U flask-cors
and apply the following changes. On your current code.
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
#app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"

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

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)

Python socket server with selection

How do I make socket server(made in node js) with node selection like the one shown below in node.js in python3 ?
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', function(socket){
socket.on('pose', function(pose){
io.emit('pose', pose);
console.log(pose);
});
});
http.listen(3000, function () {
console.log('Socket.io Running');
});
Found what I needed to do, here's the sample code with reference:
from flask import Flask, render_template
from flask_socketio import SocketIO, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)
#socketio.on('my event')
def test_message(message):
emit('my response', {'data': 'got it!'})
if __name__ == '__main__':
socketio.run(app, port = 3000)

Categories