Use local variable inside included code in NodeJS - javascript

I am trying to use local variable inside the included code but getting an error.
app.js:
import RequireDir from "require-dir";
import { Server, Socket } from "socket.io";
...
client.on("connection", (socket) => {
const id = socket.id;
RequireDir("./data", { recurse: true, noCache: true });
}
data/main.js:
console.log(id);
It will show this error on Runtime:
ReferenceError: id is not defined
There is any solution?

You cannot access variables that are initialized inside a function outside of that function.
The question is what you are trying to do with that socket ID. This socket ID is unique for each session, and you should not expose that to global variables.
The best approach would be to write a function that takes that ID and handles it.
data/main.js:
export const handleSocket = (socket) => {
console.log(socket.id);
// ... rest of your code
};
app.js:
import RequireDir from "require-dir";
import { Server, Socket } from "socket.io";
import { handleSocket } from "data/main.js"; // import the function
...
client.on("connection", (socket) => {
// pass socket to your handler
handleSocket(socket);
RequireDir("./data", { recurse: true, noCache: true });
}
You might want to read about javascript closures to understand scoping of variables.

Related

How to use STOMP for connecting with ActiveMQ in React js

Can anyone provide successful implementation of Stomp using the latest version of ActiveMQ 5.x using the React N? How to connect and publish to the queue?
I have below questions:
I have to retrieve the data from consumer and do some add some boolean value and send it to publish.
How can I keep the connection alive because continuously I will get message in queues.
How can I implement this in React.js in simple manner (any plugins)
I tried with JavaScript, and it works as expected.
consumer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("consumer connected");
stompClient.subscribe("/queue/<name>",function(body){
console.log(body);
});
});
producer.js
const Stomp = require("stomp-client");
const stompClient = new Stomp("127.0.0.1",61613);
stompClient.connect( function(sessionId){
console.log("producer connected");
stompClient.publish("/queue/<name>",function(body){
console.log(body);
console.log(typeof(body));
//JSON.stringify(body);
});
stompClient.disconnect();
});
This is what I tried in React.JS (which failed): here i can able to connect and after that if i call subscribe with que name it is not giving any response
import './App.css';
import React,{useEffect} from 'react';
import { Client, Message } from '#stomp/stompjs';
function App() {
const clientdata = new Client();
useEffect(() => {
clientdata.configure({
brokerURL: 'ws://localhost:61614/stomp',
onConnect: (frame) => {
console.log('onConnect');
console.log(frame);
clientdata.subscribe('/queue/<quename>',info => {
console.log(info);
})
console.log(subscription);
},
// Helps during debugging, remove in production
debug: (str) => {
// console.log(new Date(), str);
}
});
client.activate();
}, []);
return (
<div >
</div>
);
}
export default App;
When i tried the above code I am getting only connected log and I'm not able to subscribe any thing and not seeing anything.

socket.io in Svelte via store

I'd like to have socket.io available across the whole Svelte app. I don't know what I am doing wrong...
store.js
export const socket = writable();
This works
App.svelte
import { io } from "socket.io-client";
import { socket } from "./stores.js";
$socket = io();
$socket.on("orders", (orders) => {
console.log(orders);
});
This doesn't
App.svelte
import { io } from "socket.io-client";
import { socket } from "./stores.js";
$socket = io();
Component.svelte
import { socket } from "./stores.js";
$socket.on("orders", (orders) => {
console.log(orders);
});
The code shown works as long as the execution order is guaranteed to be correct, i.e. the code in App running before the code in Component.
If it is not, you need to add additional logic to handle the store not being set. (You also probably should clean up these on event handlers via onDestroy as well.)
E.g. you can use a reactive statement to check whether the store was set, if it is initialized with null:
$: if ($socket != null) {
$socket.on("orders", (orders) => {
console.log(orders);
});
}

Nodejs pass log instance between modules

I’ve logger which I initiate using a constractor in the index.js file. Now I need
To pass the logger instance to other files, and I do it like this
index.js
const books = require(“./books”);
books(app, logger);
logger = initLogger({
level: levels.error,
label: “app”,
version: "0.0.1",
});
app.listen(port, () => logger.info(`listening on port ${port}`));
And inside the books.js file I use it like following, get the logger from the index.js file and use it
inside the books.js file, also pass it to another file with the function isbn.get(books, logger);,
Is it recommended to do it like this? Is there a cleaner way in nodes ?
books.js
const isbn = require(“./isbn”);
module.exports = async function (app, logger) {
…
try {
Let books = await getBooks();
logger.info(“get “books process has started”);
} catch (err) {
logger.error("Failed to fetch books", err);
return;
}
…
// this function is from the file “isbn” and I should pass the logger to it also
try {
let url = await isbn.get(books, logger);
} catch (e) {
res.send(e.message);
}
}
Try creating a module specifically for your logger configuration, then you can import that into your modules instead of using a side-effect of your business module to create a logger.
This will help if you ever need/want to change your logger configuration - instead of following a chain of business methods, you can just update the log configuration.
Example
logger.js
'use strict';
// Any setup you need can be done here.
// e.g. load log libraries, templates etc.
const log = function(level, message) {
return console.log(level + ": " + message);
};
module.exports = log;
business-logic.js
'use strict';
var log = require('./logger');
var stuff = require('./stuff');
const do_stuff = function (thing) {
// do stuff here
log("INFO", "Did stuff");
}
This is a pretty clean way of doing it, however it could be awkward when trying to share more variables or adding more requires. So, you could put all the variables in an object and destructure only the variables you need in books.js:
index.js:
const state = {app, logger, some, other, variables};
require("./books")(state);
require("./another_file")(state);
books.js:
module.exports = async function ({app, logger}) {
};

socket io event fires multiple times

I have searched similar questions here but none of them work for me.
I know some people recommend not to use socket inside another event but I had no clue how to trigger socket whenever there is an event.
So I have initialized socket inside another event which is updated every time something happens. But socket connection repeats the previous result with every new update.
I tried initializing socket within componentDidMount lifecyle and it simply does not work.
class UploadComponent extends Component {
constructor (props) {
super(props);
this.state = {
endpoint: "http://localhost:3000",
}
this.uploadModal = this.uploadModal.bind(this);
}
uploadModal () {
update.on('success', file => {
let {endpoint} = this.state;
let socket = socketIOClient(endpoint, {transports: ['websocket', 'polling', 'flashsocket']});
socket.on('data', (mydata) => {
console.log(mydata) // <-- This gets fired multiple times.
})
})
}
// some more code //
}
I want to trigger socket whenever "update" event is fired without message duplication.
As sockets are emitting multiple times on Angular with nodejs happened the same with me for sockets, i tried by removing the socket listeners by this.socket.removeListener( "Your On Event" );,
This helped me solved the issue of multiple socket calls, try it, it may help !
Unless you can guarantee success is called only once, then you'll need to initialize the socket connection / event handler outside this function
class UploadComponent extends Component {
constructor (props) {
super(props);
const endpoint = "http://localhost:3000";
this.state = { endpoint };
this.uploadModal = this.uploadModal.bind(this);
this.socket = socketIOClient(endpoint, {transports: ['websocket', 'polling', 'flashsocket']});
this.socket.on('data', (mydata) => {
console.log(mydata)
})
}
uploadModal() {
update.on('success', file => {
// this.socket.emit perhaps?
})
}
}
As James have suggested I have put my socket logic in the constructor. But it was only being fired after my component remounts.
After looking at my nodejs server code I tried to replace
// some code //
io.on('connection', (client) => {
client.emit('data', {
image: true,
buffer: imageBuffer.toString('base64'),
fileName: meta.name
})
})
with this
// some code //
io.emit('data', {
image: true,
buffer: imageBuffer.toString('base64'),
fileName: meta.name
})
and it works!
Also I had to close socket in componentWillUnmount to avoid multiple repeated data.

Different behaviour when calling emit from class methods

I am building an app with socket.io and typescript. As always I have created server and client but now I'm facing weird issue with my server code. My server is listening on 'connection' event and as callback creates new class instance and invokes his onConnect method. In this function it invokes another method - 'bindHandlers'. In this function socket listens to his events.
And this is my problem: if i pass callback to 'draw' event as an anonymous function it works as expected, but if i use my class method it sends events back to to the client instead of broadcasting it. I want to make my code more modular and this issue is blocking me for now.
main file:
io.on("connection", SocketService.createInstance(db).onConnect);
simplified socket file:
export class SocketService {
private socket: Socket | null = null;
constructor(private db: DB) {}
static createInstance = (db: DB) => {
return new SocketService(db);
};
onConnect = (socket: Socket) => {
this.socket = socket;
const username = socket.handshake.query.user;
console.log(`${username} connected ${socket.id}`);
this.bindHandlers(socket);
};
private bindHandlers = (socket: Socket) => {
if (!this.socket) return console.log("socket is undefined");
socket.on("draw", this.onDraw);
// if I swap with code below it works properly
// socket.on("draw", data => {
// socket.broadcast.emit("draw", data);
// });
};
private onDraw = (data: DrawingPoint) => {
const username = this.socket!.handshake.query.user;
const { group } = data;
this.socket!.broadcast.emit("draw", data);
};
The reason why it is working with:
socket.on("draw", data => {
socket.broadcast.emit("draw", data);
});
is because you are using arrow function which for context (this) will have surrounding context, but when defining an event handler such as: socket.on("draw", this.onDraw); context will not be anymore instance of SocketService. Play with it a little bit and debug it to see what will be the context in a case when you are calling it with that.
One solution would be to set the context explicitly such as:
socket.on("draw", this.onDraw.bind(this));
Keep in mind that context of the method/function in JS depends on how method was called.

Categories

Resources