Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

nodeJS - Communicate with an electron app running in the background through a CLI

as an example of what I'm trying to achieve, consider launching VS Code from the terminal. The code <file-name> command opens an instance of vs code if not only running, or tells it to open a file otherwise. Also, once opened, the user can use the terminal session for other tasks again (as if the process was disowned).

My script needs to interact with my electron app in the same way, with the only difference being that my app will be in the tray and not visible in the dock. . The solution only needs to work on linux

like image 979
Wali Waqar Avatar asked Jun 05 '21 15:06

Wali Waqar


People also ask

How do I run a node js app as a background service?

Run command systemctl start node-app-service-name to start the service, the node-app-service-name is the service file name as above. If you want to run node in background every time when the Linux OS startup, you can run the command systemctl enable node-app-service-name in a terminal to achieve this.

Can I use node with Electron?

To use Electron, you need to install Node. js. We recommend that you use the latest LTS version available. Please install Node.


2 Answers

Use a unix socket server for inter-process-communication.

In electron

const handleIpc = (conn) => {
  conn.setEncoding('utf8');
  conn.on('data',(line) => {
    let args = line.split(' ');
    switch(args[0]) {
      case 'hey': 
        conn.write('whatsup\n');
        break;
      default: conn.write('new phone who this?\n');
    }
    conn.end();
  })
}
const server = net.createServer(handleIpc);
server.listen('/tmp/my-app.sock');

Then your CLI is:

#!/usr/bin/node
const net = require('net');
let args = process.argv;
args.shift(); // Drop /usr/bin/node 
args.shift(); // Drop script path

let line = args.join(' ');
net.connect('/tmp/my-app.sock',(conn)=>{
  conn.setEncoding('utf8');
  conn.on('data',(response)=>{
    console.log(response);
    process.exit(0);
  });
  conn.write(line+'\n');
}).on('error',(err)=>{
  console.error(err);
  process.exit(1);
});
like image 53
leitning Avatar answered Oct 28 '22 13:10

leitning


If I understand correctly, you want to keep only one instance of your app and to handle attempts to launch another instance. In old versions of Electron, app.makeSingleInstance(callback) was used to achieve this. As for Electron ...v13 - v15, app.requestSingleInstanceLock() with second-instance event is used. Here is an example how to use it:

const { app } = require('electron');
let myWindow = null;

const gotTheLock = app.requestSingleInstanceLock();

if (!gotTheLock) {
    app.quit();
} else {
    app.on('second-instance', (event, commandLine, workingDirectory) => {
        // Someone tried to run a second instance
        // Do the stuff, for example, focus the window
        if (myWindow) {
            if (myWindow.isMinimized()) myWindow.restore()
            myWindow.focus()
        }
    })

    // Create myWindow, load the rest of the app, etc...
    app.whenReady().then(() => {
        myWindow = createWindow();
    })
}

So when someone will launch ./app arg1 arg2 at the second time, the callback will be called. By the way, this solution is cross-platform.

like image 36
Vlad Havriuk Avatar answered Oct 28 '22 13:10

Vlad Havriuk