Node.js for plugins

LoxBerry 2.0

This information applies to LoxBerry 2.0 and above.

LoxBerry ships with Node.js V12. On LoxBerry 2.0 release, Node.js V12.10.0 was installed. With LoxBerry Update, we will update Node.js to newer minor releases, but stay on Node.js V12 LTS.

We recommend to not install Node.js on your own, as this may possibly lead to a downgrade to Node.js V10.

Node.js servers

If you run Node.js servers on a specific port, try to not collide with already used ports from other plugins: Used ports of LoxBerry and plugins

npm and yarn

Both npm and yarn are available to install libraries and dependencies. yarn is based on npm and has better version dependency management.

# npm
npm install jayson
# yarn
yarn add jayson

Run Node.js scripts via the installed Apache webserver

Admittedly, this is not the concept of Node.js, but it is possible to run Node.js scripts from Apache webrequests.

Therefore, create your script named *.cgi and place it in the webfrontend/html or webfrontend/htmlauth folder.

Start the script with the shebang #!/usr/bin/node

console.log("Content-type: text/html\n");
console.log("<h1>Hello World!</h1>\n");

You need to care to send the correct headers. Output from console.log is sent as response.

The response time is pretty bad (the above example on a Pi2 takes about 0,6 seconds), because every request needs to startup the nodejs engine.

Use LoxBerry's JsonRpc to use LoxBerry's library functions

This example uses the jayson library (yarn add jayson, or npm install jayson) to generate a LoxBerry plugin frontend.

'use strict';
console.log("Content-type: text/html\n");
const jayson = require('jayson/promise');
const client = jayson.client.http('http://localhost:80/admin/system/jsonrpc.php');
// Using Promises in batch mode from jayson to get all JsonRpc requests done before writing the user interface
const batch = [
    client.request('LBWeb::get_lbheader', [ "My Plugin", "", "helptemplate.html" ], undefined, false),
    client.request('LBWeb::get_lbfooter', [], undefined, false),
    client.request('LBWeb::mslist_select_html', [ { LABEL: 'Select your Miniserver', FORMID: 'MSNR', SELECTED: '1' }], undefined, false),
    client.request('getdirs', [ "myplugin" ], undefined, false),
    // Some other example JsonRpc calls
    // client.request('LBSystem::get_localip', [], undefined, false),
    // client.request('LBWeb::loglist_url', [ {'PACKAGE': 'squeezelite' } ], undefined, false),
    // client.request('LBWeb::logfile_button_html', [ { PACKAGE:'squeezelite', NAME:'daemon' } ], undefined, false),
    // client.request('LBSystem::get_miniservers', [], undefined, false),
 client.request(batch).then(function(responses) {
    var lbdirs = responses[3].result;
    console.log("<h1>Demo with Node.js and LoxBerry JsonRpc</h1>");
    console.log("<p>Plugin data directory is ", lbdirs.lbpdatadir, ".</p>");

This example code will give you this output in your plugin page.

With JsonRpc, all LoxBerry functions listed in the PHP SDK documentation can be called. The result is returned depending to the datatype (string, or an object). The Promises approach let you query several data in parallel, and runs the .then block when all requests have finished. The method getdirs (line 16) requests the plugin name and returns all absolute paths of the plugin (web, data, config, log etc.). 

Parameters of the methods have two different approaches:

  • When a list of single parameters are requested, use [ "paramter1", "parameter2", "parameter3" ] 
  • When named parameters are requested, use [ { PARAM1: 'Value1', PARAM2: 'Value2 } ] 
  • Methods without parameters request to use [] 

As returning datatypes are different for different methods, during development you possibly first dump the response.