gRPC response not getting sent to client inside setTimeout when running in renderer process in electron - node.js

I am using the #grpc/grpc-js module and I have setup a sample gRPC server:
When I run a gRPC server in electron, if I send a response after a "timeout", then the response is not going to the client at all. It's not closing the http2 stream properly. The same server works fine when run in node directly but giving this issue when run through electron.
The issue doesn't happen if I send the response directly outside the timeout function.
Sample Minimal Project which demonstrates the issue:
https://github.com/nateshmbhat/grpc-with-electron-sample-project
Expected Behavior
When the gRPC server sends the response with or without the timeout, the response should reach the client and the associated streams should close properly.
Actual Behavior
Though the server sends the response, the response is not reaching the client. So, the connection and stream don't close.
I have also filed issues for this here:
https://github.com/electron/electron/issues/26838
https://github.com/grpc/grpc-node/issues/1645

Related

.NetCore gRPC client is not able to call Node with NestJs gRPC Server

We have a gRPC server in NodeJs with Nest running on separate port 3001, and when we call this from the Node client it works fine. But one of our microservice is in.NETCore when we try to call it gives us the below error. Currently, we are stuck at the 3,4 point. if someone can guide us it will be very helpful.
1. Status(StatusCode="Unimplemented", Detail="The server does not implement the method", ResponseCode: "404")
2. Status(StatusCode="Internal", Detail="Bad gRPC response. Response protocol downgraded to HTTP/1.1.")
3. An error occurred while sending the request. Http2ConnectionException: The HTTP/2 server sent invalid data on the connection. HTTP/2 error code 'PROTOCOL_ERROR' (0x1).
4. An error occurred while sending the request. IOException: The request was aborted. Http2ConnectionException: The HTTP/2 server sent invalid data on the connection. HTTP/2 error code 'PROTOCOL_ERROR' (0x1).
What we have tried,
AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);
On startup we use the Kestrel with listening to Http1,
options.ListenLocalhost(5000, o => o.Protocols = HttpProtocols.Http1);
Added HttpClientHandler configuration for certificate and SslProtocols

socket.io client doesn't set sid in requests

I'm trying to build a nodejs script to communicate with a socket.io server.
const io = require('socket.io-client');
const socket = io('http://192.168.144.249');
socket.on('connect', () => {
console.log('connected');
})
Using wireshark to follow traffic I can see the following:
So the browser sends me a sid, both in the response body and in the cookie.
Unfortunately, my following requests do not include this sid and I received a 400 Bad Request error:
When I try to build the same client from a browser windows I can see that this cookie is indeed set, both as cookie and as a query parameter:
I don't want to use a browser, I want to use a standalone node script. As far as I understood the parsing of the response and the inclusion of the session id should be done automatically by the socket.io-client. Am I wrong? If so, how can I intercept this event so that I can send the sid with following requests?
Am I supposed to first do a simple http request to the server, get the sid from there and then add it to the socket.io client when creating it using custom cookies or custom query parameters?
I can also see that the node standalone script is using engine.io version 4 (EIO=4 in the GET requests), while the browser is doing it with engine.io version 3, but the respose received seems to be exactly the same so I don't really think this is what is preventing my script from automatically completing the handshake with the server.
Well, I was wrong. It was indeed a protocol mismatch problem.
I was able to make my script working using socket.io-client#1.0.2. Install it with:
npm install socket.io-client#1.0.2

Can you send a message to a websocket client from a non-websocket lambda?

I have a nodejs websocket AWS lambda endpoint (Api Gateway) set up and it connects and can echo messages back. During initial connection, I save the endpoint and connection_id to a database. That gets saved just fine. If I open a browser client, and connect to the websocket endpoint, I can connect successfully, and send a message from the browser successfully - I have code to echo the message back, and it works.
Now, in another nodejs lambda, one that provides a REST endpoint, I have code that loads the connection_id from the database and does this:
// 'connection' is loaded successfully from DB (I log it and see the right values)
let api = new AWSSDK.ApiGatewayManagementApi({apiVersion: '2018-11-29', endpoint: connection.endpoint});
await api.postToConnection({
ConnectionId: connection.connection_id,
Data: JSON.stringify({ message: 'Hello World' })
}).promise();
However, the code in the REST endpoint (code above) always gets a 410 error in the postToConnection. I know the connection is still active, since I can connect to it and ping it in a browser client just prior to testing the REST API above.
Is it not possible to post to a websocket connection from a non-websocket lambda?
I think you should use this to send messages from the backend to your clients.
To send a callback message to the client, use:
POST
https://{api-id}.execute-api.us-east-1.amazonaws.com/{stage}/#connections/{connection_id}
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-how-to-call-websocket-api-connections.html

Using Socket.io with Sequelize

I am trying to use Socket.io and Sequelize to create a chat app. Socket.io will handle the socket to allow for instant messaging. Sequelize will handle storing the messages so when you refresh the screen you still have your messages.
What is happening is that on localhost my socket works, but it does not send the messages to the database. When I put it onto Heroku, my database worked, but it does not use the sockets.
My socket is located in app.js and my database route is located in routes/messages.js.
I have been working on this bug for a while now and I have been trying to get help with it. I think the best way to share this is with my markdown I created detailing my efforts to fix my bug that can be found at here. My repo for this can be found here.
There are a few different parts that you need to distinguish:
the HTTP server, in your code represented by the variable http
the Express app, represented by app
the Socket.IO server, represented by io
a Socket.IO (client) connection (see below)
The HTTP server directs "normal" HTTP requests to the Express app, which will handle them according to the middleware and routes that are set up. A router handler gets called with (at least) two arguments, generally called req and res, to represent the (incoming) HTTP request and the (outgoing) HTTP response.
The Socket.IO server gets to handle specific Socket.IO requests, which get sent to the server by the Socket.IO client (running in the browser). When such a client sets up a connection with the server, the connection event gets triggered on the server. Any handlers for this event will get passed an argument, generally called socket, that represents the (bidirectional) connection with that client.
That Socket.IO connection can receive messages (sent from the client running in the browser), which trigger events on the socket. You can install a handler to listen for particular messages (like "chat message"), which will receive, as argument, the data that was sent to it by the client.
The issue in your code seems to be with setting up everything to handle those chat messages. The correct setup order would be:
listen on the Socket.IO server for connection events
when such an event is received, add a listener for the chat message event on the connection
when such an event is received, write the data to the database.
In code:
// Listen for new client connections.
io.on('connection', function(socket) {
// Listen for the client to send a _"chat message"_ message.
socket.on('chat message', function(data) {
// Store the data in the database.
models.Messages.create({
message : data.message,
username : data.username
});
});
});
As you can see, req and res aren't available inside of those Socket.IO event handlers, because those are only used for normal HTTP requests.
Also, as opposed to HTTP, you don't necessarily have to send anything back to the client when you have received a message, so I left that part out. The handler above only writes the message data to the database (it also doesn't check for, or handle, errors, which eventually you should add).

Upgrading from XHR-Polling to Websockets in Socket.io 1.0.X results in packets dropping

I have been working with a problem in Socket.io 1.0.6, where a client randomly does not receive a packet on a given protocol, and randomly does.
I have been running my node application with prefix DEBUG=* and in the browser set the variable localStorage.debug='*'.
It goes as follows:
1. Client emits on 'event'.
2. Server receives on 'event' and emits on 'event'.
3. Client does receive on 'event'/client does not receive on 'event' (randomly).
Debug messages approves this.
I do not get any error messages, just don't receive packets.
My server now runs with this configuration, which works every time:
var io = require('socket.io')(port, { allowUpgrades : false });
Have anyone else experienced problems with upgrading transport protocols in engine.io?

Resources