I'm trying to figure out how to implement a two separate websockets together. Not sure if this possible or not, but I have a websocket that works on it's own in from node.js file to angular another node.js file that uses Kraken (crypto exchange) websocket that also works in it's own file. I'm trying to consolidate them both together so that whenever a event onChange comes from Kraken websocket, I can relay that data to angular with angular socket.io websocket. Trying to do something like this
const webSocketClient = new WebSocket(connectionURL);
webSocketClient.on("open", function open() {
webSocketClient.send(webSocketSubscription);
});
webSocketClient.on("message", function incoming(wsMsg) {
const data = JSON.parse(wsMsg);
let io = require("socket.io")(server, {
cors: {
origin: "http://localhost:4200",
methods: ["GET", "POST"],
allowedHeaders: ["*"],
credentials: true,
},
});
io.on("connection", (socket) => {
const changes = parseTrades(data);
socketIo.sockets.emit(connection.change, changes);
Log whenever a user connects
console.log("user connected");
socket.emit("test event", JSON.stringify(changes));
});
console.log("DATA HERE", data[0]);
});
webSocketClient.on("close", function close() {
console.log("kraken websocket closed");
});
Although doing this doesnt relay the data to frontend and gives me a memory leak. Is there some way I can accomplish this?
I would probably split up the task a little bit. So have a service for the kraken websocket and maybe a service for your own socket, then have them communicate via observables, that you can also tap into from the front end to display data you want.
#Injectable()
export class KrakenService{
private webSocketClient : WebSocket | null;
private messages$ = new BehaviorSubject<any>(null); // give it a type
openConnection(){
// is connectionUrl from environment ??
this.webSocketClient = new WebSocket(connectionURL);
webSocketClient.on("open", function open() {
/// is webSocketSubscription from environment ??
webSocketClient.send(webSocketSubscription);
});
webSocketClient.on("message", function incoming(wsMsg) {
const data = JSON.parse(wsMsg);
this.messages$.next(data);
console.log("DATA HERE", data[0]);
});
webSocketClient.on("close", function close() {
console.log("kraken websocket closed");
this.webSocketClient = null;
});
}
getKrakenMessages(){
if(webSocketClient == null) this.openConnection();
return messages$.asObserbable();
}
}
So now when you want to either read the web socket messages or use them with the other socket you just subscribe to the krakenService.getKrakenMessages();
Then you can do something similar with you local service as well. Have something that opens connections, and one that emits messages. The example you showed it would open up a connection every time you got a message, so keep those logics separated. And reuse existing connection.
In Laravel 8, I generate a broadcast event that writes data to Redis.
The broadcastOn method of the "NewEvent implements ShouldBroadcast" class specifies the name of the event that writes data to Redis.
public function broadcastOn()
{
return ['news-action'];
}
With the help of the redis-cli monitor, I can see the format of the data that goes to the Redis server.
1616158237.374187 [0 127.0.0.1:60746] "SELECT" "0"
1616158237.374770 [0 127.0.0.1:60746] "EVAL" "for i = 2, #ARGV do\n redis.call('publish', ARGV[i], ARGV[1])\nend" "0" "{\"event\":\"App\\\\Events\\\\NewEvent\",\"data\":{\"result\":{\"labels\":[\"\\u043c\\u0430\\u0440\\u0442\",\"\\u0430\\u043f\\u0440\\u0435\\u043b\\u044c\",\"\\u043c\\u0430\\u0439\",\"\\u0438\\u044e\\u043d\\u044c\",\"33333\"],\"datasets\":[{\"label\":\"\\u041f\\u0440\\u043e\\u0434\\u0430\\u0436\\u0438\",\"backgroundColor\":[\"#D01919\",\"#F26202\",\"#EAAE00\",\"#B5CC18\"],\"data\":[15000,50000,10000,8000,500]}]},\"socket\":null},\"socket\":null}" "laravel_database_news-action"
1616158237.374850 [0 lua] "publish" "laravel_database_news-action" "{\"event\":\"App\\\\Events\\\\NewEvent\",\"data\":{\"result\":{\"labels\":[\"\\u043c\\u0430\\u0440\\u0442\",\"\\u0430\\u043f\\u0440\\u0435\\u043b\\u044c\",\"\\u043c\\u0430\\u0439\",\"\\u0438\\u044e\\u043d\\u044c\",\"33333\"],\"datasets\":[{\"label\":\"\\u041f\\u0440\\u043e\\u0434\\u0430\\u0436\\u0438\",\"backgroundColor\":[\"#D01919\",\"#F26202\",\"#EAAE00\",\"#B5CC18\"],\"data\":[15000,50000,10000,8000,500]}]},\"socket\":null},\"socket\":null}"
Since this data is incomprehensible to a person in this form, I tried to parse it manually, and that's what I got.
1616158237.374187 [0 127.0.0.1:60746] "SELECT" "0"
1616158237.374770 [0 127.0.0.1:60746] "EVAL" "for i = 2, #ARGV do\n redis.call('publish', ARGV[i], ARGV[1])\nend" "0"
"{
\"event\":\"App\\\\Events\\\\NewEvent\",
\"data\":{
\"result\":{
\"labels\":[
\"\\u043c\\u0430\\u0440\\u0442\",
\"\\u0430\\u043f\\u0440\\u0435\\u043b\\u044c\",
\"\\u043c\\u0430\\u0439\",
\"\\u0438\\u044e\\u043d\\u044c\",
\"33333\"
],
\"datasets\":[
{
\"label\":\"\\u041f\\u0440\\u043e\\u0434\\u0430\\u0436\\u0438\",
\"backgroundColor\":[
\"#D01919\",
\"#F26202\",
\"#EAAE00\",
\"#B5CC18\"
],
\"data\":[
15000,50000,10000,8000,500
]
}
]
},
\"socket\":null
},
\"socket\":null
}"
"laravel_database_news-action"
1616158237.374850 [
0 lua
]
"publish"
"laravel_database_news-action"
"{
\"event\":\"App\\\\Events\\\\NewEvent\",
\"data\":{
\"result\":{
\"labels\":[
\"\\u043c\\u0430\\u0440\\u0442\",
\"\\u0430\\u043f\\u0440\\u0435\\u043b\\u044c\",
\"\\u043c\\u0430\\u0439\",
\"\\u0438\\u044e\\u043d\\u044c\",
\"33333\"
],
\"datasets\":[
{
\"label\": \"\\u041f\\u0440\\u043e\\u0434\\u0430\\u0436\\u0438\",
\"backgroundColor\":[\"#D01919\",\"#F26202\",\"#EAAE00\",\"#B5CC18\"],
\"data\":[15000,50000,10000,8000,500]
}
]
},
\"socket\":null
},
\"socket\":null
}"
My Node server correctly subscribes to the Redis channel "*"
redis.psubscribe("*", (err, count) => {
if (err) {
console.error("Failed to subscribe: %s", err.message);
} else {
console.log(
`Subscribed successfully! This client is currently subscribed to ${count} channels.`
);
}
});
and issues a message about it to the console.
$ node node-server.js
Listening on Port: 3000
Subscribed successfully! This client is currently subscribed to 1 channels.
The Node server then connects to the socket.
redis.on("pmessage", (channel, message) => {
console.log(channel);
console.log(message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
But for some reason, not the message itself gets into the variable "message", but this text "laravel_database_news-action" which I see in the console
$ node node-server.js
Listening on Port: 3000
Subscribed successfully! This client is currently subscribed to 1 channels.
*
laravel_database_news-action
Because of this, during an attempt to pass this string in the JSON.parse (message) function, the Node-server immediately crashes.
From this I conclude that at the time of subscribing to the channel, I must indicate the specific name of the channel, but not "*"
But if I change "*" to "news-action" then the server stops responding and does not output any messages to the console.
Therefore, I want to know how to specify the channel name correctly so that the subscription is performed correctly and that the correct data, which is written in Redis server, gets into the variable "message"
Okay, everybody, I figured it out.
First, I added another method in the "Broadcast" class of the event.
public function broadcastAs(){
return 'new-event';
}
Secondly, fixed some functions in my Node server.
If suddenly someone needs it, then I represent him completely.
const http = require('http').Server();
const io = require('socket.io')(http, {
cors: {
// origin: "http://127.0.0.1:8000",
// methods: ["GET", "POST"],
// withCredentials: false
}
});
const Redis = require('ioredis');
const redis = new Redis(6379, "127.0.0.1");
redis.psubscribe("*", (err, count) => {
//
});
redis.on("pmessage", (pattern, channel, message) => {
message = JSON.parse(message);
// console.log(pattern);
// console.log(channel);
// console.log(message);
io.emit("news-action:"+message.event, message.data);
});
http.listen(3000, function (){
console.log('Listening on Port: 3000')
});
And thirdly, the client must subscribe to the channel as follows
socket.on("news-action:new-event", function (data){
// console.log(data);
this.data = data.result;
}.bind(this));
First, we are quite new in the area Hyperledger Fabric and MQTT. We are building a prototype with a Blockchain platform (Hyperledger Fabric) written in nodeJS and a raspberry pi for transmitting the IoT data (working with mqtt). In our nodeJS file we create a MQTT client that subscribes to a topic and gets as a message a JSON object. The parameters of that object have to be passed on to the smart contract (submitContract). We realized that the gateway for Hyperledger Fabric disconnects before it runs the MQTT event functions (client.on) and therefore we thought we let the gateway disconnect on the condition of a submitted contract (see below code). In order to do so we want to get the success variable out of the client.on("message") function so that we can use it for the if statement at the end. However, the success variable doesn't seem to get updated to success=true by simply using return within client.on() so that eventually the program never exits (aka gateway is not disconnected). Below, you see parts of the code (the relevant parts). Does anyone know how to pass on properly an updated variable out of the MQTT event function?
'use strict';
const { FileSystemWallet, Gateway } = require('fabric-network');
const mqtt = require("mqtt");
async function main() {
try {
// Create a new gateway for connecting to our peer node.
const gateway = new Gateway();
await gateway.connect(ccpPath, { wallet, identity: 'user1', discovery: { enabled: true, asLocalhost: true } });
// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');
// Get the contract from the network.
const contract = network.getContract('fabcar');
//MQTT client connection & contract submission
console.log("connecting to broker");
const client = mqtt.connect("mqtt://192.168.43.217");
var success = false;
client.on("connect", () =>{
console.log("Subscribing");
client.subscribe("rfidData");
console.log("Please hold your tag on the RFID reader. Wait...");
});
client.on("message", (topic, message) =>{
var rfidPayload = JSON.parse(message.toString());
var carKeyIn = rfidPayload.carKey;
var renterIDIn = rfidPayload.renterID;
var timestampIn = rfidPayload.timestamp;
console.log(rfidPayload);
contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);
success = true;
console.log("Success? " + success);
return success;
});
client.stream.on('error', (err) => {
console.log('errorMessage', err);
client.end()
});
client.on("offline",() =>{
console.log("offline");
});
client.on("reconnect", ()=>{
console.log("reconnect");
});
// Disconnect from the gateway.
if (success === true){
client.end();
gateway.disconnect();
};
} catch (error) {
console.error(`Failed to submit transaction: ${error}`);
process.exit(1);
}
}
main();
You need to take on the concept of asynchronous execution and event driven systems. The application you have written does not execute in the order it is written.
The on('message',....) call back will only be executed when a message is delivered to client. This function also does not return any values (it is not actually called by any of your code, it is called by the underlying MQTT client code) so it will not "return" the value of success.
If you want the application to disconnect after it has received the first message then the easiest thing to do is to move the code that disconnects the MQTT client and the Fabric gateway to inside the callback. e.g.
client.on("message", (topic, message) =>{
var rfidPayload = JSON.parse(message.toString());
var carKeyIn = rfidPayload.carKey;
var renterIDIn = rfidPayload.renterID;
var timestampIn = rfidPayload.timestamp;
console.log(rfidPayload);
contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);
gateway.disconnect();
client.end();
});
EDIT:
Looking at the doc it appears that submitTransaction() is flagged as being an async function, so you should be able to use await to block until it completes
...
console.log(rfidPayload);
await contract.submitTransaction('openCar', carKeyIn, renterIDIn, timestampIn);
gateway.disconnect();
client.end();
});
I am trying to send a typing indicator on conversationUpdate but seems for me session.sendTyping() is only working within a dialog. At least I tried in Webchat and BotEmulator channels with no success. Any ideas about how to accomplish this?
Here my try:
bot.on('conversationUpdate', async (message) => {
if (message.membersAdded) {
for (let identity of message.membersAdded) {
if (identity.id === message.address.bot.id) {
const replies = getGreetingReplies(message);
cosmosDB.writeOnConvUpdate({ userMessage: message, botMessage: replies[0] }, message.address.conversation.id);
bot.loadSession(message.address, async (err, session) => {
for (let reply of replies) {
//var msg = new builder.Message().address(message.address).text('');
//msg.type = 'Typing';
//bot.send(msg);
await utilities.SendTyping(session, 3000);
bot.send(reply);
}
});
}
}
}});
For directline/webchat make sure to set up your bot connection on the frontend like so:
botConnection = new BotChat.DirectLine({
secret: "<secret>",
webSocket:true,
sendTyping: true
});
Then to actually send a sendTyping event you just have to call session.sendTyping() when a new message is received, or if you want to be more specific, you can call the method before something you know is going to take a while, like an API call.
The sendTyping event only works with an open webSocket, and is not supported in all channels. However it will work in webchat when using the above configuration.
Currently I have facing issue that I got response to all users.
I want to just notify for Selected user in single chat module.
like below i want to sent notification to this "userid" only
Client side file code has below
var forwardString =
{
"userid": actual_receiverID,
"id": msgId
};
socket.emit('insertReceiverIdInMessageForwardReq',forwardString);
socket.on('insertReceiverIdInMessageForwardRes', function (messages) {
var updatedMsg = messages.Messages;
});
------------------Server Side code------------------
io.on('connection', function (socket) {
socket.on('insertReceiverIdInMessageForwardReq', function (status) {
io.emit('insertReceiverIdInMessageForwardRes', res);
});
});
// sending to individual socketid (private message)
socket.to(<socketid>).emit('hey', 'I just met you');
// or you can do this as well
io.sockets.connected[<socketid>].emit('hey', 'I just met you');
Please refer the documentation for more details: https://socket.io/docs/emit-cheatsheet/