How to update a redux state from a node js function - node.js

I'm creating a program that graphs in real time the data send by a serial port.
I'm using Electron, so in the main.js file (Where you create the window for the app) I have declared the event when receives data.
const { SerialPort, ReadlineParser } = require('serialport');
const port = new SerialPort({
path: 'COM5',
baudRate: 9600,
});
const parser = new ReadlineParser({ delimiter: '\r\n' });
port.pipe(parser);
let anterior = '';
let cont = 0;
// on data print the complete data from the serial port
parser.on('data', (line) => {
let value = line.substring(5, 15);
value = parseFloat(value.trim());
if (value > 0.0 && !line.includes('?') && line != anterior) {
console.log(`> ${line}`);
anterior = line;
updateStateFromNode(value, cont);
cont += 1;
}
});
The function I call is this:
import { store } from '../store/store'; // my actual store
import { addValue, addLabel } from '../store/data';
function updateStateFromNode(newValue, newLabel) {
store.dispatch(addValue(newValue));
store.dispatch(addLabel(newLabel));
}
I console log inside the function addValue to check if it reaches the function, and it does...
I also have tried with a customHook, but it didn't work also.
Anyone knows how could I achieve this?

The main and renderer processes are isolated from each other, which means that dispatching from main will not update the store on your renderer. To communicate between the two processes, you can use IPC. Assuming you use a preload file, you can do something looking like this:
Main
function updateStateFromNode(newValue, newLabel) {
// We will use a channel named "updateState"
mainWindow.webContents.send("updateState", newValue, newLabel);
}
Preload
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld("electronAPI", {
onUpdateState: (callback) => {
const channel = "updateState";
const subscription = (_event, ...args) => callback(...args);
// Sets the listener on the channel "updateState"
ipcRenderer.on(channel, subscription);
// Returns a function to remove the listener
return () => {
ipcRenderer.removeListener(channel, subscription);
};
}
})
Renderer
import { addValue, addLabel } from "../store/data";
const { electronAPI } = window; // `electronAPI` is exposed with the preload
const MyComponent = () => {
const dispatch = useDispatch();
useEffect(() => {
// Calls the function from preload to set the listener on the channel "updateState"
const removeUpdateStateListener = electronAPI.onUpdateState((newValue, newLabel) => {
dispatch(addValue(newValue));
dispatch(addLabel(newLabel));
});
return removeUpdateStateListener; // Removes the listener on unmount
}, [dispatch]);
return (...);
}

Related

how to allow multiple async routes in express.js

I'm fairly new to Node and Express and am struggling with creating a route that takes a user uploaded file and processes it into another file. The problem is that the second time the user sends a request, I am having to wait for the first process to complete to allow the user to upload a new file.
The basic structure of route that I have is below
THE PROBLEM is that the function convertFile below is a time taking process and it keeps the server busy from accepting new requests. How do I make it so that once the project is saved in mongo db at newProject.save() - the process to convertFile runs in the background while the server accepts new requests from the same route?
I'm sending a response back the user after newProject.save() and was hoping that would allow the user to send another request. And although this sends another request, the server doesn't accept it since its busy with the previous process to convertFile
router.post('/', upload.fields([{ name: 'zip' }]), async (req, res, next) => {
let data = {
title: req.body.title,
description: req.body.description,
}
if (req.files && req.files.zip) {
const newProject = new MongoProject(data);
newProject.save()
.then(async (project) => {
res.send(project);
console.log("Project created");
const uploadedFilePath = path.normalize(req.files.zip[0].path);
// below method - "convertFile" is a time taking method
const extractZipinfo = await convertFile(uploadedFilePath , data.masterFile).then((zipInfo) => {
console.log({ zipInfo })
data.zipInfo = {
sizes: zipInfo.sizes
}
})
})
.catch(err => {
console.log("Error creating project");
return res.send(err);
})
}
})
Below is the simplified version of code in convertFile function (code modified for brevity):
I know that this can be improvised a lot, but i'm struggling with getting it to function as expected first (allowing multiple routes)
async function convertFile(inputFilePath, outputInfo) {
const outputFilePath = "output.abc";
const jsonFilePath = "output.json";
const doc = new Document(); // this is a class to store all data of the output file that we will write at the end
const _FileAPI = new fileAPI();
const outputFinalData = await _FileAPI.Init() // this is an async method
.then(() => {
const dataClass = initiateClass(); // this is a class to store data in JSON format
const paragraphs = _FileAPI.GetallParagraphs(inputFilePath);
for (let i = 0, len = paragraphs.size(); i < len; i++) {
for (let j = 0, lenj = paragraphs.size(); j < lenj; j++) {
const para = paragraphs.get(j);
// read each para and Capitalize each word
dataClass.paragraphs.push(para);
}
}
fs.writeFileSync(jsonFilePath, JSON.stringify(dataClass, null, 2), 'utf-8');
console.log("then")
}).then(() => {
const io = new NodeIO(); // this class helps in writing the file in the desired output format
const outData = io.write(outputFilePath, doc).then(() => {
outputInfo.sizes.push(fs.statSync(outputFilePath).size);
return outputInfo;
});
return outData;
});
return outputFinalData;
}

BotFramework TypeError: Cannot perform 'get' on a proxy that has been revoked

I am trying to develop a MS Teams bot that sends content to students module(unit) wise. I have created 3 classes:
methods.js = Contains all the methods for sending texts, attachments etc.
teamBot.js = Captures a specific keyword from the users and based on that executes a function.
test.js = Connects the bot with Airtable and sends the content accordingly
I am facing Cannot perform 'get' on a proxy that has been revoked error. I figured it might be because of the context. I am passing context as a parameter, which I feel might not be the correct way, how can I achieve the result, and retain the context between files.
teamsBot.js
const test = require("./test");
class TeamsBot extends TeamsActivityHandler {
constructor() {
super();
// record the likeCount
this.likeCountObj = { likeCount: 0 };
this.onMessage(async (context, next) => {
console.log("Running with Message Activity.");
let txt = context.activity.text;
// const removedMentionText = TurnContext.removeRecipientMention(context.activity);
// if (removedMentionText) {
// // Remove the line break
// txt = removedMentionText.toLowerCase().replace(/\n|\r/g, "").trim();
// }
// Trigger command by IM text
switch (txt) {
case "Begin": {
await test.sendModuleContent(context)
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
// Listen to MembersAdded event, view https://learn.microsoft.com/en-us/microsoftteams/platform/resources/bot-v3/bots-notifications for more events
this.onMembersAdded(async (context, next) => {
const membersAdded = context.activity.membersAdded;
for (let cnt = 0; cnt < membersAdded.length; cnt++) {
if (membersAdded[cnt].id) {
const card = cardTools.AdaptiveCards.declareWithoutData(rawWelcomeCard).render();
await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
break;
}
}
await next();
});
}
test.js
const ms = require('./methods')
async function sendModuleContent(context) {
data = module_text //fetched from Airtable
await ms.sendText(context, data)
}
methods.js
const {TeamsActivityHandler, ActivityHandler, MessageFactory } = require('botbuilder');
async function sendText(context, text){
console.log("Sending text")
await context.sendActivity(text);
}
Refer this: TypeError: Cannot perform 'get' on a proxy that has been revoked
make the following changes to test.js
const {
TurnContext
} = require("botbuilder");
var conversationReferences = {};
var adapter;
async function sendModuleContent(context) {
data = module_text //fetched from Airtable
const currentUser = context.activity.from.id;
conversationReferences[currentUser] = TurnContext.getConversationReference(context.activity);
adapter = context.adapter;
await adapter.continueConversation(conversationReferences[currentUser], async turnContext => {
await turnContext.sendActivity(data);
});
}

Socket connection congests whole nodejs application

I have a socket connection using zmq.js client:
// routerSocket.ts
const zmqRouter = zmq.socket("router");
zmqRouter.bind(`tcp://*:${PORT}`);
zmqRouter.on("message", async (...frames) => {
try {
const { measurementData, measurementHeader } =
await decodeL2Measurement(frames[frames.length - 1]);
addHeaderInfo(measurementHeader);
// Add cell id to the list
process.send(
{ measurementData, measurementHeader, headerInfoArrays },
(e: any) => {
return;
},
);
} catch (e: any) {
return;
}
});
I run this socket connection within a forked process in index.ts:
// index.ts
const zmqProcess = fork("./src/routerSocket");
zmqProcess.on("message", async (data: ZmqMessage) => {
if (data !== undefined) {
const { measurementData, measurementHeader, headerInfoArrays } = data;
headerInfo = headerInfoArrays;
emitHeaderInfo(headerInfoArrays);
// Emit the message to subscribers of the rnti
const a = performance.now();
io.emit(
measurementHeader.nrCellId,
JSON.stringify({ measurementData, measurementHeader }),
);
// Emit the message to the all channel
io.emit("all", JSON.stringify({ measurementData, measurementHeader }));
const b = performance.now();
console.log("time to emit: ", a - b);
}
});
There is data coming in rapidly, about one message per ms, to the zmqRouter object, which it then processes and sends onto the main process where I use socket.io to distribute the data to clients. But as soon as the stream begins, node can't do anything else. Even a setInterval log stops working when the stream begins.
Thank you for your help!

Error to emit socket: internal / bootstrap / pre_execution.js: 308

internal/bootstrap/pre_execution.js:308
get() {
^
RangeError: Maximum call stack size exceeded
at get (internal/bootstrap/pre_execution.js:308:8)
at hasBinary (/home/spirit/Documents/ProjectsJS/ProjectBack/node_modules/has-binary2/index.js:44:3)
Hello I am trying to issue my socket but I have this error, and I can not receive my socket in the back end below all the code I used
io.on('connection', function (socket) {
setInterval(() => Queue.searching() , 1000);
sessionMap.set(socket.id,socket);
//ADD PLAYER TO QUEUE
socket.on('addPlayer-Queue', (result) => {
const player = {
id:result.id,
socketid: socket.id,
name: result.name,
mmr: result.mmr,
socket: socket
}
const nPlayer = new Player(player);
Queue.addPlayer(nPlayer);
/*
console.log(queue);
console.log(sessionMap.all());*/
//socket.emit('match', matches)
});
});
//
searching = () => {
const firstPlayer = this.getRandomPlayer();
const secondPlayer = this.players.find(
playerTwo =>
playerTwo.mmr < this.calculateLessThanPercentage(firstPlayer) &&
playerTwo.mmr > this.calculateGreaterThanPercentage(firstPlayer) &&
playerTwo.id != firstPlayer.id
);
if(secondPlayer){
const matchedPlayers = [firstPlayer, secondPlayer];
this.removePlayers(matchedPlayers);
Matches.configurePlayersForNewMatch(matchedPlayers);
}
}
//
getMatchConfigurationFor = players => {
console.log(sessionMap.all())
if(players){
const match = new Match(players);
const result = {
idMatch: match.id,
playerOne: match.players[0],
playerTwo:match.players[1]
}
return result;
}
}
configurePlayersForNewMatch = (matchedPlayers) => {
matchedPlayers.forEach(player =>
sessionMap.get(player.socketId)
.broadcast.to(player.socketId)
.emit('match',
this.getMatchConfigurationFor(matchedPlayers)));
}
so what I admit the problem is in this code snippet:
matchedPlayers.forEach(player =>
sessionMap.get(player.socketId)
.broadcast.to(player.socketId)
.emit('match',
this.getMatchConfigurationFor(matchedPlayers)));
The session map is a mapping I made of my sockets saving key (socket id) and socket to send by emit later. on console log about my session.map this is console . log on my socket player https://pastebin.com/XHDXH9ih

How to stub an object method with sinon?

I need to stub the sendMandrill method of the mh object.
See my file under test (mail.js):
let MailHandler = require('../../modules/mail.handler.module');
...
let api = (router, parser) => {
let send = async (req, res, next) => {
let mh = new MailHandler();
mh.sendMandrill();
...
}
...
return router.post('/mail/send', parser.json(), send);
}
module.exports = api;
...
My test (mail.spec.js):
let stRequest = require('supertest');
let MailHandler = require('../../modules/mail.handler.module');
describe('my test', () => {
beforeEach(() => {
sinon.stub(MailHandler.prototype, 'sendMandrill', () => true);
})
it('stubs sendMandrill!', done => {
stRequest(app)
.post('/mail/send')
.end((err, resp) => {
done();
});
})
})
Currently I'me getting the error below:
TypeError: Cannot stub non-existent own property sendMandrill
Adding mail.handler.module - See below the mailHandler / sendMandrill code:
module.exports = mailHandler;
function mailHandler() {
...
var mandrill = require('../modules/mandrill');
var handler = {
sendMandrill: sendMandrill,
...
};
return handler;
function sendMandrill() {
mandrill.messages.sendTemplate({
message: {...}
});
}
...
}
You current approach creates a new sendMandrill for each and every instance created by mailHandler factory. You should actually call it w/o new let mh = mailHandler() or even better rename it to createMailHandler to avoid misuse.
If you want to effectively use prototype inheritance you'll need to rewrite mailHandler to use actually use this instead of a newly created object.
var mandrill = require('../modules/mandrill');
module.exports = MailHandler;
function MailHandler() {
// use this instead of newly created object
this.foo = 'bar'
// avoid explicit return
// return handler;
}
// set methods to prototype
MailHandler.prototype.sendMandrill = function sendMandrill() {
// use this instead of handler here
mandrill.messages.sendTemplate({
message: {...}
});
}
Using the above approach you would be able to stub prototype properties via sinon and justify calling the constructor with new keyword.
UPD
If you have no control over mail.handler.module you could either use rewire module that allows to mock entire dependencies or expose MailHandler as a part of your api module to make it injectable.
api.MailHandler = require('../../modules/mail.handler.module')
let mh = api.MailHandler();
And then in tests
let oldMailHandler;
beforeAll(() => { oldMailHandler = api.MailHandler})
afterAll(() => { api.MailHandler = oldMailHandler})
beforeEach(() => { api.MailHandler = function MockMailHandler() {} })

Resources