Letting the Electron server speak to the mirror client

Setting up communication between the web server and client processes of electron, and controlling them using another application.

Advertisements

Important edit.  I’ve implemented another solution for the integration between the server and the client using a mirror module.  I’ll be moving forward with that solution. Check out this article.   For a solution using a change of the core code : please read on…


Allright, now things get a bit more complicated.  In the last article I showed you how I got my debug hub talking to the mirror.  That is, to the web server in the mirror.  There was nothing visible on the screen.   There was not actual visible interaction.

In this article I want to tackle this.

Electron applications are very powerful.  You can combine both server side scripting (such as NodeJS with client side scripting such as Javascript or CSS.  But with great power comes … a bit of complexity.  Complexity in that way that the webserver running in the background is a separate process from the front end client.  This front end client can be considered a browser window in fact.

The electron website explains this very well in its documentation.  In fact, there is a special framework foreseen (and it comes out of the box) to make communication from the client (also called the renderer process) to send to the server (the main process).  A main process (being the web server running in the background) listens to inputs from its renderer proces(ses) (there can be multiple in theory).

See the electron documentation here :

http://electron.atom.io/docs/api/ipc-main/

There is one big catch here.  This framework supports a message being sent from the renderer process to the main process… and that’s not what we want.  We want it the other way around.  Let me remind me of my ultimate goal : to be able to control the mirror with outside interaction.  Whether it be an application (such as the debug hub), an external proces or even Alexa Voice Service, all through a simple HTTP request.  Easy to integrate, easy to maintain, and very easy to deploy.

So here we go.  Let me start by saying there’s an important prerequisite here.  By default there is no support on the client for any server side scripting.  In other words, in the javascript files called by the client process you can’t “require” any nodeJS modules.  By default.  Of course there’s a way around this.  They only thing you have to do is adjust one of the electron settings.  In the screenshot below you can see that activate node integration by setting the setting in the webPreferences to true.

Schermafbeelding 2017-01-21 om 13.10.35.png

That’s it.  That wasn’t all that hard.

Now for the tricky part.  And the confusing part.  There are 2 sides to the IPC integration.  IPC stands for inter process communication in which there is a process that sends a message on a certain channel, and another process that listens for it.  The ipcMain object is responsible for receiving messages.  The ipcRenderer object is responsible for sending them.  It’s also important to know that the ipcRenderer is an object that cannot be used in the webserver process.  It will give you issues such as undefined objects or unknown attributes.  Trust me.  I learned it the hard way.  You should think there’s a problem here because we want the communication to go in the other direction, but it’s time to get creative.

This is where it gets confusing.  The ipcMain object can be used in the web server processes which is situated in the server.js file.  The ipcRenderer can be used in the client process, being the magic mirror module which is located in the main.js file.  That’s right.  Main.js.  What’s in a name… right?  There is no actual relation between the object called ipcMain and the source file called main.js.

Well, now that we’ve got that out of the way, it’s time to start adjusting the server.js file.

First I’ll be defining the ipcMain object on top by doing this :

Schermafbeelding 2017-01-21 om 12.59.09.png

Somewhere in the code of the server process I can now call the “on” function of ipcMain that lets you specify a channel (called asynchronous-message below) and a callback function, which is implemented with a console log and a reply in the screenshot below.

Schermafbeelding 2017-01-21 om 12.59.15.png

You might notice how I just copy pasted the code from the electron website, just to test if this would work.  Note that there are 2 ways to communicate : synchronous and asynchronous.  The first one would be done using the sync method, but it would mean that the client process would wait for a response of the server.  Which is not what we want.  So i’ll be implementing the asynchronous method.

Notice how the code sends a reply.  There’s the key to our solution!  This is a way to send a message back to the client process.

Time to adjust the code of the client process.  This is done in main.js where the MM object is defined.  I started with defining the ipcRenderer object here :

Schermafbeelding 2017-01-21 om 12.58.53.png

In Main.js, you can locate the function called modulesStarted.  It’s a callback function, executed when all mirror modules have stopped loading.  According to me, an ideal place to start testing some stuff.  I added the following lines of code to that function

Schermafbeelding 2017-01-21 om 12.58.44.png

First I send a message to the ipcMain object by using the send method.  The first parameter is the channel (the same one as the ipcRenderer is listening on), and the second parameter is the message i’m sending.

In the second statement I create a listener for a reply.  All it does is print the reply to the console.  Let’s test that out.  And what do you know.  Here you can see the output: On the one hand the console log of the dev tools in the mirror, and on the other hand the console log in the terminal of the web server.  Ping and Pong.

Schermafbeelding 2017-01-21 om 12.58.27.pngSchermafbeelding 2017-01-21 om 12.58.31.png

Now, we can get cracking with our own code.

Let’s start with making a method that will hide all of the mirror modules.  There’s a hideModule method already in the MM object, so I’ll just create one that loops through the modules, and hides them all.  Like so :

Schermafbeelding 2017-01-21 om 13.14.08.png

Next I’ll adjust the code in the modulesStarted callback a bit to kind of a loop.  I will use the standard setInterval function of javascript to continuously call a function every second.  That’s standard functionality.  All it does is call the onPoll function which I defined below it.

Schermafbeelding 2017-01-21 om 13.18.38.png

All it does is send a message, and wait for a reply.

Testing that out, it will give something like this : a lot of pings and a lot of pongs in the consoles.

Schermafbeelding 2017-01-21 om 13.17.54.pngSchermafbeelding 2017-01-21 om 13.18.01.png

Well… actually, the above screenshot is not 100% correct.  That is, it will work, but essentially I’m creating a new listener every time around.  That will create a memory leak, so I adjusted to code and customised it a bit like so :

Schermafbeelding 2017-01-21 om 13.30.25.png

The “mirror” channel is now used for communication.  There’s a listener on the channel “mirror-command”.

In the server.js file, I’ve adjusted the listener as well, to listen for the “mirror” channel.

Schermafbeelding 2017-01-21 om 13.21.35.png

So, summing it all up.  What’s happening?  Every second, the mirror sends the question the server : “what do I have to do?”.  In most cases it will get no response.  But if there is something to do, the server will send a reply with that command, at which time it is executed by the mirror.

The only thing we have to do, is make sure that a HTTP command coming into the webserver, somehow gets into that reply.  That isn’t very difficult.  We only have to create a simple queueing mechanism in which a command is queued up, and every time the question comes “what do I have to do?”, this queue is read and passed on.

Editing the code of server.js, I just define an empty array and call it command queue.

 

Schermafbeelding 2017-01-21 om 13.33.45.png

Next, I adjust the app.get method of the express framework to push a command onto the queue.

The listener for the command requests by the mirror just checks if there is a command in the queue, and removes it by using the shift method.  It then passes it on to the reply.  Easy peasy :

Schermafbeelding 2017-01-21 om 13.34.11.png

See how, in the above code I sent some console logs.  Let’s start this.

Press the button in the debug hub :

Schermafbeelding 2017-01-21 om 13.32.51.png

Here’s the log of the mirror :

Schermafbeelding 2017-01-21 om 13.32.56.png

… and the log of the server.

Schermafbeelding 2017-01-21 om 13.33.02.png

Cool, now just to hook it all up.  In the main.js process I will check for the “hide-all-modules” command, and if it comes, I will call my new function hideAllModules.

Schermafbeelding 2017-01-21 om 13.41.35.png

I added a console log to see if it works well.

Schermafbeelding 2017-01-21 om 13.41.09.png

And here we go : I pressed the button, and the modules disappear in the mirror.  Notice how the “hiding module” console log message appears it the bottom right corner :

Schermafbeelding 2017-01-21 om 13.40.19.png

 

I’ll add another function to show the modules again.  Very similar :

Schermafbeelding 2017-01-21 om 13.45.37.png

And extend the event handler to allow a second command :

Schermafbeelding 2017-01-21 om 13.45.22.png

If we run that I noticed that the server comes with a message that we’re using a deprecated function in the express framework.

Schermafbeelding 2017-01-21 om 13.49.05.png

Looking at the website of express js, that’s indeed true.  It has been replaced with another principal.  Check it out here :

https://expressjs.com/en/guide/routing.html

So i will adjust my code accordingly.  Notice how the parameter is now specified in the URL, and it can be addressed as an attribute of the params object.

Schermafbeelding 2017-01-21 om 14.03.04.png

I have to adjust the debug hub as well to pass along in the correct syntax :

Schermafbeelding 2017-01-21 om 14.03.35.png

And that’s it. We’ve hooked it all up.  I proudly present you the result below :

ezgif.com-video-to-gif.gif

Good luck!

 

 

One thought on “Letting the Electron server speak to the mirror client”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s