I've started learning Golang after writing in Node.js for a long time and I'm a bit curious as to how am I to implement a handler - I've opted to use Gorilla Websocket since I understood it's the most reliable package out there.
In socket.io for example you have the simple socket.on function that allows me to call a function based on the "name" parameter passed in JSON.
Gorilla websocket doesn't implement such a thing, so my question is am I to sort of implement the logic behind socket.io in order to achieve what I want ?
As in do a certain procedure based on the value transferred in the websocket ?
If so - I need to implement it both client (I'm using AngularJS on the front-end) and server side separately by my own - make a switch case statement based on a value I get in JSON both in AngularJS for the front-end and in Go for the back-end, and also - is that the most efficient way ?
Thanks !
If you've been using Javascript for a while it is really easy to implement your own version of socket.on and socket.emit here is one I made for my own projects but you can have it if you need,
// e.g.
// let socket = new Socket("ws://w/e");
// socket.on('connected', () => { console.log('Connected'); });
// socket.emit('lobby join', { data: { username: 'Boo' } });
// Using ES2015 with Babel
import {EventEmitter} from 'events';
class Socket {
constructor(wsurl, ee = new EventEmitter()) {
let ws = new WebSocket(wsurl);
this.ee = ee;
this.ws = ws;
ws.onmessage = this.message.bind(this);
ws.onopen = this.open.bind(this);
ws.onclose = this.close.bind(this);
}
on(name, fn) {
this.ee.on(name, fn);
}
off(name, fn) {
this.ee.removeListener(name, fn);
}
emit(name, data) {
const message = JSON.stringify({name, data});
this.ws.send(message);
}
message(e) {
try {
const msgData = JSON.parse(e.data);
this.ee.emit(msgData.name, msgData.data);
}
catch(err) {
let error = {
message: err
}
console.log(err)
this.ee.emit(error.message)
}
}
open() {
this.ee.emit('connected');
}
close() {
this.ee.emit('disconnected');
}
}
export default Socket
This will let you use your common socket.on('event', fn); and what not
As for handling it on the servers end:
For receiving messages, I personally just make a switch statement that will match an incoming string to a function, e.g.:
// readPump pumps messages from the websocket connection to the hub.
func (c *connection) readPump() {
defer c.ws.Close()
for {
_, message, err := c.ws.ReadMessage()
if err != nil {
break
}
var incMessage interface{}
err = json.Unmarshal(message, &incMessage)
if err != nil {
log.Println(err)
}
incMessageMap := incMessage.(map[string]interface{})
switch incMessageMap["name"] {
case "lobby join":
// Do something to handle joining
case "lobby leave":
// Do something to handle leaving
}
}
}
For sending them I have a send channel on my connections that is stored in a map and when I need to emit I have a simple struct that takes a message name, and data, e.g.:
type wsMsg struct {
Name string `json:"name"`
Data map[string]interface{} `json:"data"`
}
c.send <- wsMsg{
"user joined",
map[string]interface{}{
"username": "Booh",
},
}
Then on the client side it would come as
socket.on('user joined', (msg) => {
console.log(msg) // { username: "Booh" }
});
I suggest looking at the examples on gorillas git: https://github.com/gorilla/websocket/tree/master/examples/chat
Here is an working example of golang websocket to stream video
https://github.com/interviewparrot/OpenAVStream
Let me know if it is good enough
Related
I'm working with WebSocket and having an issue with a function showing incorrect data, All my code used to work with a Class-based component, I'm only trying to convert a class component that actually calls the connect method of Websocket to a functional-based component. The Websocket is class-based for instance.
So I have a WebSocket which on socket New Message sets callbacks.
socketNewMessage(data) {
console.log(data);
const parsedData = JSON.parse(data);
const command = parsedData.command;
if (command === "userChatGroups") {
this.callback[command](parsedData.chatGRoups);
}
if (command === "new_userChatGroups") {
this.callback[command](parsedData.chatGRoup);
}
}
and here are the callbacks defined -
addCallbacks(userChatGroups, newUserChatGroup) {
this.callback["userChatGroups"] = userChatGroups;
this.callback["new_userChatGroups"] = newUserChat;
}
and then websocket finally return -
const WebSocketInstance = Websocketservice.getInstance();
export default WebSocketInstance;
Now the class-based component which I'm trying to convert to functional based -
let's call this component Chats-
this calls the connect method and a Websocket instance is returned.
useEffect(() => {
if (loggedInUserDetail) {
WebSocketInstance.connect(loggedInUserDetail[0].id);
}
}, [loggedInUserDetail]);
I have a helper function which checks the status of websocket -
function waitForSocketConnection(callback) {
setTimeout(() => {
if (WebSocketInstance.state() === 1) {
console.log("connection is secure");
callback();
return;
} else {
console.log("waiting for connection");
waitForSocketConnection(callback);
}
}, 10);
}
and I check the status and map my callbacks - here is the problem-
useEffect(() => {
waitForSocketConnection(() => {
WebSocketInstance.addCallbacks(
setChatGroups,
addNewChatGroup
);
});
}, [loggedInUserDetail]);
I have a state to manage CHatGroups -
const [groups, setGroups] = useState([]);
the setChatGroups (which initially loads all the groups the users are associated with works fine and sets the state of chatsGroups) as -
const setChatGroups = useCallback((userChatGroups) => {
setGroups(userChatGroups); //whatever data it recieved from the websocket.
}, []);
but the function addNewChatGroup always shows groups value as an empty array [] (it was updated earlier with setChatGroups). If I manually check the value of groups it is an array of n length, but in addNewChatGroup function, it always shows an empty array with the initial value [].
const addNewChatGroup = useCallback(
(newCHatGroup) => {
console.log(groups); **error -> this is always empty array**
// here I have to update. add the received value with the previous
},
[groups] // callbacks used hoping this will bind
);
In the class-based component I used to set callbacks on the constructor and used to bind with this, but I'm not able to do it here, can anyone help what I'm missing?
I'm sure it is a binding issue. maybe. May I know the reason for this binding failure?
Well if I understood correctly your problem, it could be link to multiple things.
The problem actually is I don't have a clear view on all your components, maybe you can try to paste a sandbox link or something like that with a "simple structure".
I tried to reproduced a typescript version, I don't know if it could help:
class MyWebSocket {
private static _instance: MyWebSocket;
public callbacks: any = {};
public connected: boolean = false;
public socketNewMessage(data: any): void {
const parsedData = JSON.parse(data);
console.log('new message received:', parsedData);
const command = parsedData.command;
if (command === "new_userChatGroups") {
this.callbacks[command](parsedData.newGroupAdded);
}
}
public addCallbacks(elements: {command: string, func: Function}[]) {
console.log('adding callbacks...', elements);
elements.forEach(element => {
this.callbacks[element.command] = element.func;
});
}
public connect(): void {
setTimeout(() => this.connected = true, 1100);
}
public static getInstance(): MyWebSocket {
return this._instance || (this._instance = new MyWebSocket());
}
}
class SocketUtils {
static waitForSocketConnection(callback: any): void {
const waitingInterval = setInterval(() => {
if (MyWebSocket.getInstance().connected) {
console.log('socket is connected! processing callback...');
clearInterval(waitingInterval);
callback();
return;
} else {
console.log('socket is not connected after 1sec, waiting...');
}
}, 1000);
}
}
class Chat {
groups: string[] = ['group of JStw'];
new_userChatGroups(group: string) {
this.groups.push(group);
}
}
class Main {
constructor() {
const myChat = new Chat();
MyWebSocket.getInstance().connect();
// waiting connections.
SocketUtils.waitForSocketConnection(() => {
console.log('waitForSocketConnection is triggered, adding callbacks...');
// adding callbacks
MyWebSocket.getInstance().addCallbacks([{command: 'new_userChatGroups', func: myChat.new_userChatGroups.bind(myChat)}]);
});
// Waiting 5min to dispatch an message
setTimeout(() => {
// testing eventing after getting connection
MyWebSocket.getInstance().socketNewMessage(JSON.stringify({command: 'new_userChatGroups', newGroupAdded: 'group of Ranu Vijay'}));
}, 5000);
setTimeout(() => {
console.log('program finished, results of chat groups:', myChat.groups);
}, 10000);
}
}
new Main();
Output:
I'm more specialized on functional component by using react so without a link to investigate all your code, it will be complex to help.
I don't know if you are using a library, but there is this one: https://www.npmjs.com/package/react-use-websocket which seems to be really ultra simple to use without managing socket connection/disconnection.
For me if I had to implement it, I would say:
Component ChatGroup which is using websocket hook const { sendMessage, lastMessage, readyState } = useWebSocket(socketUrl); and contains the state groups, setGroups.
Component Chat which can use the sendMessage from props of ChatGroup component and call it from this component if a join a group.
Then your "parent" component is managing the state and is controlling the data.
I have created an CRUD API using typescript NodeJS, Express and MongoDB. What I am trying to achieve is that when using the POST method when I send the correct parameter. API works fine. However whenever I send incorrect parameters to the API the whole NodeJS app crashes, I get an error message in console that the parameters passed to the API are wrong and I will have restart the application again.
When as user sends the incorrect parameters to the API. I don't want the NodeJS app to crash. I want to display the useful error message. Keep the app running. I Don't want to restart the application.
This is the code i use to create New providers.
public addProviders(req: Request, res: Response, next: NextFunction) {
var type = req.body.type,
name = req.body.name;
let newProvider = new Provider({
type,
name
})
newProvider.save()
.then((provider: Object) => {
if (provider) {
let statusCode = res.statusCode;
res.json({
statusCode,
provider
})
}
})
}
Below is the code that i have tried so far.
try {
newProvider.save()
.then((provider: Object) => {
if (provider) {
let statusCode = res.statusCode;
res.json({
statusCode,
provider
})
}
})
}
catch (e) {
res.json("enter valid parameters")
}
I am new to NodeJS. Thanks in advance.
You need to add input validation middleware to check inputs before adding to Database.
#1 You can check it manually, like:
var { type, name } = req.body;
if (typeof type !== 'string') {
res.status(400).send("type input is not valid");
} else if (typeof name !== 'string') {
res.status(400).send("name input is not valid");
} else {
let newProvider = new Provider({
type,
name
})
// ...rest of the code
}
#2 Or you can use a package like express-validator.
I am getting the event emitter leak after using my code 10 times essentially. I understand the default of event emitter auto sending out a warning in the console. My question is what in this code is directly creating the event listeners? Is it poor coding on my part or is it just how the websockets are stacked onto each other?
I'll explain the code a bit. I have one websocket within another and I figured it would serve the data to a web page essentially flowing from Twitch to a localhost site. However, if I use the keywords more than 10 times, I get the error. I do not understand enough about WebSockets to really understand why my code creates a new listener with each msg.text received so anyone with a bit more understanding please help!
I believe me issue to be similar to this though I am having a hard time conceptualizing my own code here
const { paintballShot } = require('./JavaScript/paintballGunFire');
const { readPin } = require('./JavaScript/readPin');
const ws = require('ws');
const express = require('express');
const app = express();
//CONNECT TO TWITCH
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
//create headless websocket
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
//call other websocket connected to Twitch from inside the new websocket
client.on("PRIVMSG", (msg, error) => {
if (msg.messageText === "right") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "left") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "fire") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
paintballShot();
}
if (msg.messageText === "pin") {
readPin();
}
process.on('uncaughtException', function (err) {
console.log(err);
});
});
client.connect();
client.join("channel");
socket.on('message', message => console.log(message));
});
// `server` is a vanilla Node.js HTTP server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
});
});
process.on('uncaughtException', function (err) {
console.log(err);
});
To wrap this up, the library I am using (Dank TwitchIRC) does have a connection rate limiter that seems to work if you add it to your chat client in the beginning. If I set it low enough, depending on the messages received from Twitch, it will end connections just as fast, meaning no memory leak.
So I've been searching for a long time on mqtt.js examples for structuring and best practices and haven't found anything worthwhile. thus [main] how do you structure your mqtt.js code in your node/express application?
[1] So the libraries mqttjs/async-MQTT provides some example on connecting and on-message but on a real app with lots of subscription and publishes how to structure code so that it initiliazes on the app.js and uses the same client (return from the mqtt.connect) for all the sub/pub in different files.
[2] and from the question[1] should my app only use 1 client for all the works or can use multiple clients as needed on multiple files (let's say I have 3 files mqttInit, subscriber, publisher. so if I use the init on subscriber and get a client should I export it or just make a new instance of a client on the publisher file)
[3] so the mqttjs API provides only an onMessage function so all subscribed topics message gets here thus I put a switch or a if else to manage this so if we have a lot of topics how do you manage this
[4] so my current setup is kind of messed up
this is the initializer file lets say'
mqttService.js
const mqtt = require("mqtt");
const { readFileSync } = require("fs");
module.exports = class mqttService {
constructor() {
this.client = mqtt.connect("mqtt://xxxxxxxxxxx", {
cert: readFileSync(process.cwd() + "/certificates/client.crt"),
key: readFileSync(process.cwd() + "/certificates/client.key"),
rejectUnauthorized: false,
});
this.client.on("error", (err) => {
console.log(err);
});
this.client.once("connect", () => {
console.log("connected to MQTT server");
});
}
};
subscriber.js
this is the function(subscribe()) that I call in app.js to init the mqtt thing
const { sendDeviceStatus, sendSensorStatus } = require("../socketApi");
const { client } = new (require("./mqttService"))();
function subscribe() {
let state = {
timer: false,
};
...
let topics = {
....
},
client.subscribe([...]);
client.on("message", async (topic, buffer) => {
if (topic) {
...
}
});
}
module.exports = {
subscribe,
client,
};
publish.js
const { AsyncClient } = require("async-mqtt");
const _client = require("./subscribe").client;
const client = new AsyncClient(_client);
async function sendSensorList(daqId) {
let returnVal = await client.publish(
`${daqId}-GSL-DFC`,
JSON.stringify(publishObject),
{ qos: 1 }
);
console.log(returnVal);
return publishObject;
}
.....
module.exports = {
sendSensorList,
.......
};
so as you can see from the above code everything is kind of linked with one another and messed up thus I need some expo on how you structure code
thanks for reading, please feel free to provide any info and any info is much appreciated
I'm trying to inflate messages from a third party websocket using javascript, but receiving a pako.js
"invalid stored block lengths" error.
The sample code I'm using to implement the web socket can be found here:
https://github.com/okcoin-okex/API-docs-OKEx.com/tree/master/demo
A full working version of the code can be found implemented here:
https://github.com/Tucsky/SignificantTrades/blob/master/src/exchanges/okex.js
(https://aggr.trade)
I've tried using zlib.js instead of Pako.js, but running into more difficult problems with that library.
I've tried other alternate solutions found on stackoverflow but they don't seem to do what I need.
This is the code I'm running which shows the error.
https://jsfiddle.net/fwkgmvjr/
let myAPI = new WebSocket('wss://real.okex.com:10442/ws/v3');
//When the connection is first opened
myAPI.onopen = event => {
console.log('Socket opened')
myAPI.send('{"op": "subscribe", "args":["futures/ticker:ETH-USD-190927"]}')
}
myAPI.onmessage = event => {
if (event.data instanceof String) {
console.log(event.data)
} else {
try {
console.log(JSON.parse(pako.inflateRaw(event.data, {
to: 'string'
})))
} catch (err) {
console.log(err)
}
}
}
myAPI.onclose = event => {
console.log('Socket closed')
}
myAPI.onerror = event => {
console.log(`[error] ${error.message}`)
}
I expect the message from the websocket to be easily inflatable somehow.
The solution was to add
this.api.binaryType = 'arraybuffer'
when declaring the websocket.