Error in Electron | Node.js - javascript

I'm trying to download a torrent with Electron and Node.js using WebTorrent. Well, this is my code in main.js
const electron = require('electron')
const { app, BrowserWindow } = electron
const path = require('path')
const url = require('url')
const server = require('./server')
let win
function createWindow() {
win = new BrowserWindow ({ vibrancy: 'dark', width: 400, height: 600, frame: false, resizable: false, transparent: true })
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file',
slashes: true
}))
}
app.on('ready', createWindow)
And my code in server.js is:
require('http').createServer(function (req, res) {
var WebTorrent = require('webtorrent-hybrid')
var client = new WebTorrent()
var magnetURI = 'magnet:?xt=urn:btih:EF3B95AEF1C94FC8E98825386C3B12560FE21CFF&tr=udp://glotorrents.pw:6969/announce&tr=udp://tracker.opentrackr.org:1337/announce&tr=udp://torrent.gresille.org:80/announce&tr=udp://tracker.openbittorrent.com:80&tr=udp://tracker.coppersurfer.tk:6969&tr=udp://tracker.leechers-paradise.org:6969&tr=udp://p4p.arenabg.ch:1337&tr=udp://tracker.internetwarriors.net:1337'
client.add(magnetURI, { path: 'movies' }, function (torrent) {
torrent.on('done', function () {
console.log('torrent download finished')
})
})
res.end('Hello from server started by Electron app!');
}).listen(9000)
The problem starts when I run the app and appears this message on the console:
(node:9032) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 ready listeners added. Use emitter.setMaxListeners() to increase limit

Its just a warning!!!
As per the Nodejs.org documentation
https://nodejs.org/api/events.html#events_emitter_setmaxlisteners_n
By default EventEmitters will print a warning if more than 10 listeners are added for a particular event. This is a useful default that helps finding memory leaks. Obviously, not all events should be limited to just 10 listeners. The emitter.setMaxListeners() method allows the limit to be modified for this specific EventEmitter instance. The value can be set to Infinity (or 0) to indicate an unlimited number of listeners.
So you need to add a below line in your code
"emitter.setMaxListeners(n)"

Related

require module inside preload script in electron

I'm building an app with electron react and MySQL, I'm stuck in preload script where i want to make my db instance available in render-er process, i got the following error
Error: module not found: ./config/db in console.
this happening when i try to require a module inside preload script.
const { app, BrowserWindow } = require("electron");
const path = require("path");
const isDev = require("electron-is-dev");
const dotenv = require("dotenv");
//load .env
dotenv.config();
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
title: "Electron",
minWidth: 800,
minHeight: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
devTools: isDev,
},
});
//get url dependig on envirement (dev/prod)
const url = isDev
? `http://localhost:${process.env.PORT}/`
: `file://${path.join(__dirname, "../../dist/react/index.html")}`;
// load the url
mainWindow.loadURL(url);
// Open the DevTools.
isDev && mainWindow.webContents.openDevTools();
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
createWindow();
app.on("activate", function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", function () {
if (process.platform !== "darwin") app.quit();
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
require("./handlers");
preload
const { contextBridge, ipcRenderer } = require("electron");
const { db } = require("./config/db");
contextBridge.exposeInMainWorld("mainApi", {
db,
});
Since Electron v20.0.0, the sandbox parameter defaults to true (according to the list of Breaking Changes)
One of the side effects of the sandbox attribute is that it can only require a few things:
A require function similar to Node's require module is exposed, but can only import a subset of Electron and Node's built-in modules:
electron (only renderer process modules)
events
timers
url
To disable sandboxing, just add sandbox: false to your webPreferences on window creation:
// ...
// Create the browser window.
const mainWindow = new BrowserWindow({
title: "Electron",
minWidth: 800,
minHeight: 600,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
devTools: isDev,
sandbox: false, // fixes require() in preloader
},
});
// ...

Getting TypeError: "path" is not defined: undefined while executing serial port program for windows using JavaScript

I am trying to execute a Serial Port program for windows based application using JavaScript and Arduino Uno. This is the link i referred https://channel9.msdn.com/Blogs/raw-tech/Arduino-talks-back-to-Nodejs-Drama-on-the-Serial-Port. While i try to execute the program by issuing npm start COMxx. Iam getting the following error.
App threw an error during load
TypeError: "path" is not defined: undefined
at new SerialPort (C:\serial test js\serial-app\node_modules\#serialport\stream\lib\index.js:116:11)
at Object.<anonymous> (C:\serial test js\serial-app\src\index.js:7:16)
at Module._compile (internal/modules/cjs/loader.js:1078:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1108:10)
at Module.load (internal/modules/cjs/loader.js:935:32)
at Module._load (internal/modules/cjs/loader.js:776:14)
at Function.f._load (electron/js2c/asar_bundle.js:5:12684)
at loadApplicationPackage (C:\serial test js\serial-app\node_modules\electron\dist\resources\default_app.asar\main.js:110:16)
at Object.<anonymous> (C:\serial test js\serial-app\node_modules\electron\dist\resources\default_app.asar\main.js:222:9)
at Module._compile (internal/modules/cjs/loader.js:1078:30)
And this is my code
const { app, BrowserWindow } = require('electron');
const path = require('path');
const SerialPort = require('serialport');
const Readline = SerialPort.parsers.Readline;
const portname = process.argv[2];
const myPort = new SerialPort(portname, {
baudRate:9600,
parser: new Readline("\n")
});
myPort.on('open',onOpen);
myPort.on('data',onData);
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
app.quit();
}
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
});
// and load the index.html of the app.
mainWindow.loadFile(path.join(__dirname, 'index.html'));
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
function onOpen(){
console.log("Open Connection");
}
function onData(data){
console.log("on Data "+data);
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.
Help me to resolve the issue
Instead :
const myPort = new SerialPort(portname, {
baudRate:9600,
parser: new Readline("\n")
});
Try this :
const myPort = new SerialPort({
path:portname,
baudRate:9600,
parser: new Readline("\n")
});
As path is a part of nodejs core module, it doesn't need to be listed explicitly
const path = require('path');
Just try to stop your solution and re-run application it should be working.

Dynamic pathRewrite with createProxyMiddleware and create react app

I have the following in my Create React App as per https://create-react-app.dev/docs/proxying-api-requests-in-development/
src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:5000',
changeOrigin: true,
})
);
};
This works fine and sends all requests to my nodejs app running on port 5000. However I wish to intercept the request somehow and rewrite the path into a url query string format.
I have json-server running on the nodejs server which needs the requests to be formatted differtently, using this type of format /api/cheeses?cheeseno=12
For example
'/api/cheese/12' => `/api/cheeses?cheeseno=12`
I have come across pathRewrite and router on this page https://www.npmjs.com/package/http-proxy-middleware but I have no idea how to map them over.
Later on as I get mor advanced, I will need to map nested path routes to url queries.
So
/location/{locationId}/aisle/{aisleid}/cheeses => /api/cheeses?locationId=12&aisleid=123`
Thanks
const { createProxyMiddleware } = require('http-proxy-middleware');
const rewriteFn = function (path, req) {
return path.replace('/api/foo', '/api/bar');
};
const options = {
target: 'http://localhost:3000',
pathRewrite: rewriteFn,
};
const apiProxy = createProxyMiddleware('/api', options);
rewriteFn is the key
https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/pathRewrite.md#custom-rewrite-function

Communicating to the serial port of the Kenwood TH-D72A is seems nearly impossible. Why can't I read data using javascript?

This is (hopefully) the end of a god-awful journey. I have a long history of communicating with serial ports via tty terminal programs and it usually takes 5 mins to set them all up.
What am I trying do?
1. Write commands to the TH-D72A via javascript
2. Read data from the TH-D72A via javascript
Successes:
A: Can read and write in python. However the TH-D72A get into a weird mode where it doesn't respond.
B: Contacted Kenwood Customer support and have a very lengthy discussion with them. Yet, I have put in 3 weeks of something that should take 5 mins. and they don't seem to understand what's wrong either.
C: This operational mode will be on Raspberry Pis but my dev OS is Mac OS. I'm able to do the python scripts in either platform.
Code
I'm not sure if I must use a parser or simply read from the port. port.read() does not display any data. This code compiles but there are no data sent to the func:
'use strict';
var express = require('express');
var router = express.Router();
var util = require("util");
const SerialPort = require('serialport');
const Readline = SerialPort.parsers.Readline;
var devicePath = '/dev/ttyUSB0';
var osvar = process.platform;
console.log(osvar);
if (osvar == 'darwin') {
console.log("Using Mac OS");
devicePath = '/dev/tty.SLAB_USBtoUART';
}else{
devicePath = '/dev/ttyUSB0';
}
const port = new SerialPort(devicePath, {
baudRate: 9600,
parity: 'none',
stopBits: 1,
dataBits: 8,
flowControl: false
}, function(err) {
if (err){
console.log('error: ', err.message);
port.close();
}});
const parser = new Readline({delimiter: '\n'});
port.pipe(parser);
console.log('parser setup');
parser.on('data', function(data) {
console.log('data received: ', data);
});
port.on('data', function(data) { console.log('Date:' +data);
});
port.on('open', function() { console.log('Port Opened');
});
port.on('close', function() { console.log('Port Closed');
});
port.write('DISP\r\n');
router.get('/', function (req,res) {
res.render('terminal', { title: 'Terminal Page' });
});
module.exports = router;
Other
The projects are open at github: https://github.com/kcw-grunt/nodetest
And, I forked a module (npm) to add more methods: https://www.npmjs.com/package/th-d72-ax25
I hope there is some javascript guru that can see the problem (which must be really simple)
Background
I have become a forensics specialist trying to figure why this simple task has taken literally 6 weeks...and I have found a solution. I consider it a workaround but I can move forward with it to continue code my bigger solution
Each of my supporters have suggested that javascript was sound and I tend to agree with them. But, the system was not responding at all. This includes the serialport 2.0.6, 2.1.2 and even v 6.2.0.
This code actually works (as well as #psiphi75 said it should):
'use strict';
var express = require('express');
var router = express.Router();
var serialport = require('serialport');
var SerialPort = serialport.SerialPort;
var devicePath = '/dev/ttyUSB2';
var port = new SerialPort( devicePath, { // change path
baudrate: 9600
, function ( err ) {
if ( err ) {
console.error('error opening serial port:' , err);
}
}
});
port.on('data', function(data) {
console.log('Data:'+data)
});
port.write('KISS ON\r\n', function(err) {
console.log('KISS ON Turned on');
});
port.write('RESTART\r\n', function(err) {
console.log('Restarted');
});
port.on('open', function() {
console.log('Port Opened');
});
port.on('closed', function() {
console.log('Port Closed');
});
var start = Date.now();
setInterval(function() {
var delta = Date.now() - start; // milliseconds elapsed since start
// alternatively just show wall clock time:
console.log(new Date().toUTCString());
port.write('I\r\n');
}, 5000); // update
router.get('/', function (req,res) {
res.render('terminal', { title: 'Terminal Page' });
});
module.exports = router;
The problem has actually been the Kenwood TH-D72A serial (USB) port. In fact when using it in a dev enviroment, it remains in a state where it does not emit data after the second serialport 'connection'. This is a serious bug Kenwood should fix especially that the HT is considered one of the most expensive on the market.
The workaround has been to simply power cycle the TH-D72A each time a build + run is started.
I may spend some time finding out if there is some persistent state causing this. But, the code restarts the HT in each build.. This will be a serious problem for a non-tech user in the field let alone someone without 2 Raspberry Pis, a Linux, windows and Mac
I've used SerialPort many times without issues (gprs-signal-strength, super-duper-serial-gps-system. Here is some example code.
Note: These use SerialPort v2.0.x. Which looks like it used the new SerialPort.SerialPort(...) syntax as opposed to the udpated new SerialPort(...) syntax.
const port = new SerialPort.SerialPort('/dev/ttyS2', {
baudrate: 115200,
parser: SerialPort.parsers.readline( '\r\n' ) // you may just want \r or \n
}, function ( err ) {
if ( err ) {
console.error( 'Error opening GPRS serial port: ', err );
}
} );
port.on('data', function(data) {
console.log(data)
});
If anyone is still trying to do this, I got it working with the following code and serialport#7.1.5:
const SerialPort = require("serialport");
const port = new SerialPort("/dev/tty.SLAB_USBtoUART", {
baudRate: 9600,
dataBits: 8,
parity: "none",
stopBits: 1,
rtscts: true
});
I think the trick is to turn on hardware flow control with rtscts: true.

Serving static files in Electron (React app)

I am working on a project where I need to build a desktop app in Electron. The majority of functionality will be built in React, but there will be a part where we need to integrate a 3rd party static HTML magazine. I need some advice on how to do this. I am building a proof of concept app currently and I have based it on this https://github.com/chentsulin/electron-react-boilerplate
how would I add that on /static/ I server static HTML files. I know I could do it in express, but I really don't want to include the entire express framework just for serving static files.
I was looking at this https://www.npmjs.com/package/serve-static but have no Idea how to integrate it in my react app and bundle it into electron app.
I found another solution without using express or serve-static, we only
need to cusomize Electron built-in interceptFileProtocol() to serve static contents.
Code:(main.js)
(I use the electron-quick-start as Electron template)
function createWindow () {
window = new BrowserWindow({ width: 800, height: 600 })
window.loadURL(url.format({
pathname: 'index.html', /* Attention here: origin is path.join(__dirname, 'index.html') */
protocol: 'file',
slashes: true
}))
window.on('closed', () => {
window = null
})
}
app.on('ready', () => {
protocol.interceptFileProtocol('file', (request, callback) => {
const url = request.url.substr(7) /* all urls start with 'file://' */
callback({ path: path.normalize(`${__dirname}/${url}`)})
}, (err) => {
if (err) console.error('Failed to register protocol')
})
createWindow()
})
Reference:
protocol.interceptFileProtocol()
Explaination:
Normally, if you run React app as a normal website, all static contents should be served by HTTP [GET] method. Though they use relative paths, your HTTP server will handle the path parsing work.
However, when running under Electron, things change.
Your static contents usually use relative path like ./picture.jpg, Electron will use file protocol instead of HTTP protocol and find the file under root path like C://.//. So static contents like ./picture.jpg won't be loaded correctly.
By customizing interceptFileProtocol(), all static contents' requests will be pointed to your working directory instead of Windows(or other OS) root.
Finally, I'm not sure whether it's a good solution for all Electron projects, but if you already have a React project (or some other SPA) and want to wrap it with Electron, this solution would be fine to use.
As an addition to the great answer from #yeze322 above, here a working sample for all not so familiar with node and electron (like me). It took me some time to find out the correct require statements.
main.js (code from #yeze322 plus required imports)
const { app, BrowserWindow, protocol } = require('electron')
const path = require('path')
const url = require('url')
let mainWindow
function createWindow() {
mainWindow = new BrowserWindow({ width: 800, height: 600 })
mainWindow.loadURL(url.format({
pathname: 'index.html', /* Attention here: origin is path.join(__dirname, 'index.html') */
protocol: 'file',
slashes: true
}))
mainWindow.on('closed', function () {
mainWindow = null
})
}
app.on('ready', () => {
protocol.interceptFileProtocol('file', (request, callback) => {
const url = request.url.substr(7) /* all urls start with 'file://' */
callback({ path: path.normalize(`${__dirname}/${url}`) })
}, (err) => {
if (err) console.error('Failed to register protocol')
})
createWindow()
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
if (mainWindow === null) {
createWindow()
}
})
In your main file you have
const app = require("app")
app.on("ready", () => {
...
Here you can start the server like you would do in node.js
const serveStatic = require('serve-static')
// or
const express = require('express')
...
}
Putting 3rd patry resources in the resources directory can solve the problem

Categories

Resources