How to send messages to a AWS websocket custom route in flutter - python

I've set up a websocket in AWS using API gateway and a simple lambda function shown below:
import json
import boto3
def lambda_handler(event, context):
route = event["requestContext"]["routeKey"]
connectionId = event["requestContext"]["connectionId"]
client = boto3.client('apigatewaymanagementapi',
endpoint_url='https://testid.execute-api.ap-southeast-2.amazonaws.com/production')
if route == "$connect":
print('Connection occured')
elif route == "$disconnect":
print("Disconnected")
elif route == "message":
print("Message received")
api = client.post_to_connection(
Data=json.dumps({'result': 'success'}),
ConnectionId = connectionId
)
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
In flutter I connect to the websocket on startup using the web_socket_channel package (skipped some boilerplate code for simplicity)
import 'package:web_socket_channel/io.dart';
#override
void initState() {
super.initState();
WidgetsBinding.instance?.addPostFrameCallback((_) async {
channel = IOWebSocketChannel.connect('wss://testid.execute-api.ap-southeast-2.amazonaws.com/production');
channel.stream.listen((message) {
print(message);
});
}
}
When I check the AWS lambda logs I can see that a connection was definitely established.
I then use a button to trigger a function that sends a message to the message route.
void sendMessage(){
channel.sink.add({'action':'message'});
}
On running the sendMessage function, nothing happens and the connection gets disconnected. I'm actually not sure if that's the way to send a message to a custom route as I couldn't find anything in the docs for the web_socket_channel package. How can I get this working so that the connection stays alive and receives messages from the lambda?

Oh solved it. I just needed to send the json as a string.
void sendMessage(){
channel.sink.add(jsonEncode({'action':'message'}));
}

Related

Not able to bind Flask's Server-Sent Event's data in Angular

I am using Flask for backend and Angular for frontend. I am implementing Server-Sent Events (SSE) for some task. Unfortunately, I am not able to receive any data from the SSE.
Banckend:
#app.route('/stream')
def stream():
def event_stream():
while True:
time.sleep(1)
yield 'data: some data\n\n'
return Response(event_stream(), mimetype='text/event-stream')
Frontend:
ngOnInit(): void {
var eventSource = new EventSource('http://127.0.0.1:5000/stream')
eventSource.onmessage = (e) => {
console.log(e.data); // Not working
this.eventData = e.data; // Not working
}
}
The issue with this code is the if I am commenting time.sleep(1) line in the backend, then I am able to see the response in the Chrome's dev tools, but not able to bind it in the HTML file. So, if I keep it like that, then I am not able to see either of them.
I am facing one more issue, when I am terminating the backend (by killing the command promt), I am able to see that the failed calls are still being continuously made from the browser to the event stream. I believe, SSEs are always sent from the server/backend, but in this case the client/browser is requesting for the event. Is my understanding wrong?
I have attached an image for reference.
Use eventSource's addEventListener method:
eventSource.addEventListener('message', (e) => {
this.eventData = e.data;
});
eventSource.addEventListener('error', (e) => { // This will properly close the stream, when it ends.
eventSource.close();
});

Connection is not getting established from react socket-io client to flask-socket-io server for real time update

Just for learning purpose, I am trying to establish a connection between react and flask with SOCKET.io to get real time updates.
But, sadly I am not able to establish a connection between client socket.io to sever socket.io till now.
I followed several blogs and explored GitHub issues, but none of them had helped me.
Codes
1. React codes
import React, { useState, useEffect } from "react";
import socketIOClient from "socket.io-client";
import io from "socket.io-client/dist/socket.io";
import "./App.css";
const ENDPOINT = "http://127.0.0.1:5000";
function App() {
const [data, setData] = useState("");
const setRecords = (response) => {
console.log("response", response);
setData(response.records);
};
useEffect(() => {
// const socket = socketIOClient(ENDPOINT); // >>>>> Not Working
const socket = io.connect(ENDPOINT, { rejectUnauthorized: false }); //{ transports:["websocket"]}
console.log("connected", socket);
socket.on("success", (data) => console.log(data));
// socket.on("FetchRecords");
// socket.emit("FetchRecords");
// socket.on("SendingRecords", setRecords);
// socket.on("FromAPI", data => {
// setResponse(data);
// });
}, []);
return (
<div className="App">WEBSOCKET with FLASK and REACT...{data.length}</div>
);
}
export default App;
Now if I see the logs in the console, it is being disconnected.
2. Backend Code
from flask import Flask, jsonify
from mongoConnect import todo
from flask_socketio import SocketIO, send, emit
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins='*', engineio_logger=True)
#socketio.on('connect')
def test_connect():
print('CONNECT EVENT happened...')
emit('success', {'data': 'Connected'})
#socketio.on('FetchRecords')
def fetch_all_records():
records = todo.find({})
print('fetch_all_records', len(records))
response = jsonify({'code': 200, 'records': records})
print(response)
emit('sendingRecords', response)
if __name__ == '__main__':
socketio.run(app, port=5000)
Logs of backend (using geevent-websocket)
Can anyone tell me where am I going wrong? Weirdly none of them had the problem like me...
Here are the blogs and issues I checked...
1. React Native: unable to establish the socket connection
2. Simple Chat-App with React & Flask
3. Socket.IO, React and Node.js: Going Real-Time
I had the same problem too.
Try uninstall socket.io-client and install version 2.3.1 npm i socket.io-client#2.3.1
The old version works for me.
Another thing is to make sure there isn't another server running on the same port you're trying to connect to.
Simple mistake but it could happen

Aws Websocket {"message":"Missing Authentication Token"}

anyone knows what's wrong with this code.
The address from the api gateway returns {"message": "Missing Authentication Token"}.
All code deploy by serverless framework on AWS.
JS custom.js
var socket;
// Connect to the WebSocket and setup listeners
function setupWebSocket(username, token) {
socket = new ReconnectingWebSocket(" {api endpoint}?token=" + token);
socket.onopen = function(event) {
data = {"action": "getRecentMessages"};
socket.send(JSON.stringify(data));
};
socket.onmessage = function(message) {
var data = JSON.parse(message.data);
data["messages"].forEach(function(message) {
if ($("#message-container").children(0).attr("id") == "empty-message") {
$("#message-container").empty();
}
if (message["username"] === username) {
$("#message-container").append("<div class='message self-message'><b>(You)</b> " + message["content"]);
} else {
$("#message-container").append("<div class='message'><b>(" + message["username"] + ")</b> " + message["content"]);
}
$("#message-container").children().last()[0].scrollIntoView();
});
};
}
// Sends a message to the websocket using the text in the post bar
function postMessage(token){
var content = $("#post-bar").val();
if (content !== "") {
data = {"action": "sendMessage", "token": token, "content": content};
socket.send(JSON.stringify(data));
$("#post-bar").val("");
}
}
handler.py
def _send_to_connection(connection_id, data, event):
gatewayapi = boto3.client("apigatewaymanagementapi",
endpoint_url="https://" + event["requestContext"]["domainName"] +
"/" + event["requestContext"]["stage"])
return gatewayapi.post_to_connection(ConnectionId=connection_id,
Data=json.dumps(data).encode('utf-8'))
Contrary to the message, the issue is not actually a missing authentication token. API Gateway returns the same message when the endpoint you are accessing is not exactly correct; i.e. does not exist, probably due to some typo or slight misconfiguration. I would suggest confirming that your endpoint is valid and re-check that.
The reason you get this message is because if they returned a 404 it meant that you now know that the (invalid) endpoint you called does not exist. But that also means that you could do a brute force process of checking all possible endpoints and any not returning 404 do exist but behind some kind of firewall, authentication system or API Key. By returning 403 for all endpoints, even if they don't exist, AWS are improving their security posture. Its the same reason that on a login form you don't return a message such as "Username does not exist", because otherwise someone could find a way to find valid usernames based on your error message.
Hope that helps

How to receive data from server using Kotlin?

I have a server written in python and an Android client written in Kotlin (in Android Studio IDE). I use sockets for maintaining this connection. After the client sends a message to the server, the server will need to send an answer to the client. I didn't find a way to receive data at the client by using sockets. I tried to do that:
var server = Socket(serverIP, serverPort)
server.outputStream.write(message.toByteArray())
var answer = server.inputStream.bufferedReader().use(BufferedReader::readText)
server.close()
but it seems not to work. If it matters, the sending at server side looks like that:
client.send(message.encode())
I suppose, you are using OkHttp for this. In my app I have the following code
private fun getClient(): OkHttpClient {
return try {
val builder = OkHttpClient.Builder()
builder.pingInterval(30, TimeUnit.SECONDS)
builder.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
class WebSocketController(
val callback: SomeCallback
) {
private val url = "wss://your.url.com/"
private val socketClient = getClient()
private var serverSocket: WebSocket? = null
private val listener = object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
super.onOpen(webSocket, response)
val json = "" // your payload to send on connect
serverSocket = webSocket
serverSocket!!.send(json)
}
override fun onMessage(webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
val data = Json.decodeFromString<YourModel>(text)
// here you can use your data from server
callback.makeSomething(data)
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
super.onFailure(webSocket, t, response)
callback.onFailure(t)
}
}
fun establishConnection() {
socketClient.newWebSocket(requestBuilder().build(), listener)
}
fun disconnect() {
val json = "" // your payload on disconnect
serverSocket?.send(json)
}
private fun requestBuilder(): Request.Builder = Request.Builder().url(url)
}

MeteorJS HTTP POST Request Connection Lost XMLHttpRequest

I am writing an application that integrates into a website that is already written in Meteor (I can't change that but I can add on to it). I am trying to send information from the Meteor application to my Flask server.
To do this I am using MeteorJs's HTTP module.
The code for this:
HTTP.post('http://127.0.0.1:5000/path', {
"content" : {"headers" : {"Content-Type": "application/json"}, "data": {time: getTime, data: getData()}}
},
(error, result) => {
if(error){
console.log(error);
console.log({time: getTime(), data: getData()})
}
else {
console.log(result);
}
}
)
getTime() and getData() both work independently outside this function, so they shouldn't be the source of error.
When I look at the JS console for when the event is being fired I receive the following message:
Error: Connection lost at XMLHttpRequest.xhr.onreadystateexchange and what was supposed to be sent to the Flask server.
When I look at the Flask server I see that it is receiving the post request with status code 200, but it seems like there is no data actually being received.
The code on the python end:
#app.route(r'path', methods=["POST"])
def get_data():
print(request.data)
print(request.args)
return "Hello World"
The print statements come out empty with this being shown on the console b'[object Object]' or ImmutableMultiDict([])
The Meteor app and the Flask app are both on different ports.
The problem I believe is on the MeteorJS side, since I used the curl linux function it works properly when I ping the flask server from there.
Is there a way to fix this error? If so how?
Hi "parameters" should be "data".
You can find all valid options in the docs.
Let me know if it works for you.
HTTP.post('http://127.0.0.1:5000/path', {
data : {time: getTime(), data: getData()}
}, (error, result) => {
if(error){
console.log(error);
console.log({time: getTime(), data: getData()})
} else {
console.log(result);
}
}
)

Categories

Resources