Skip to content

Commit

Permalink
Merge pull request MagicMirrorOrg#924 from QNimbus/client-only-pr
Browse files Browse the repository at this point in the history
Added clientonly script
  • Loading branch information
MichMich authored Jul 12, 2017
2 parents c492ea7 + 2d1e993 commit 86ae704
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [2.1.3] - Unreleased

### Changed

### Added
- Add `clientonly` script to start only the electron client for a remote server.
- Add symbol and color properties of event when `CALENDAR_EVENTS` notification is broadcasted from `default/calendar` module.

### Updated

### Fixed

- Fixed issue with incorrect allignment of analog clock when displayed in the center column of the MM
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ bash -c "$(curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/maste
### Server Only
In some cases, you want to start the application without an actual app window. In this case, you can start MagicMirror² in server only mode by manually running `node serveronly` or using Docker. This will start the server, after which you can open the application in your browser of choice. Detailed description below.

### Client Only
When you have a server running remotely and want to connect a standalone client to this instance, you can manually run `node clientonly --address 192.168.1.5 --port 8080`. (Specify the ip address and port number of the server)

**Important:** Make sure that you whitelist the interface/ip in the server config where you want the client to connect to, otherwise it will not be allowed to connect to the server

#### Docker

MagicMirror² in server only mode can be deployed using [Docker](https://docker.com). After a successful [Docker installation](https://docs.docker.com/engine/installation/) you just need to execute the following command in the shell:
Expand Down
97 changes: 97 additions & 0 deletions clientonly/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* jshint esversion: 6 */

"use strict";

// Use seperate scope to prevent global scope pollution
(function () {
var config = {};

// Helper function to get server address/hostname from either the commandline or env
function getServerAddress() {
// Helper function to get command line parameters
// Assumes that a cmdline parameter is defined with `--key [value]`
function getCommandLineParameter(key, defaultValue = undefined) {
var index = process.argv.indexOf(`--${key}`);
var value = index > -1 ? process.argv[index + 1] : undefined;
return value !== undefined ? String(value) : defaultValue;
}

// Prefer command line arguments over environment variables
["address", "port"].forEach((key) => {
config[key] = getCommandLineParameter(key, process.env[key.toUpperCase()]);
})
}

function getServerConfig(url) {
// Return new pending promise
return new Promise((resolve, reject) => {
// Select http or https module, depending on reqested url
const lib = url.startsWith("https") ? require("https") : require("http");
const request = lib.get(url, (response) => {
var configData = "";

// Gather incomming data
response.on("data", function(chunk) {
configData += chunk;
});
// Resolve promise at the end of the HTTP/HTTPS stream
response.on("end", function() {
resolve(JSON.parse(configData));
});
});

request.on("error", function(error) {
reject(new Error(`Unable to read config from server (${url} (${error.message}`));
});
})
};

function fail(message, code = 1) {
if (message !== undefined && typeof message === "string") {
console.log(message);
} else {
console.log("Usage: 'node clientonly --address 192.168.1.10 --port 8080'");
}
process.exit(code);
}

getServerAddress();

(config.address && config.port) || fail();

// Only start the client if a non-local server was provided
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) === -1) {
getServerConfig(`http://${config.address}:${config.port}/config/`)
.then(function (config) {
// Pass along the server config via an environment variable
var env = Object.create(process.env);
var options = { env: env };
config.address = config.address;
config.port = config.port;
env.config = JSON.stringify(config);

// Spawn electron application
const electron = require("electron");
const child = require("child_process").spawn(electron, ["js/electron.js"], options);

// Pipe all child process output to current stdout
child.stdout.on("data", function (buf) {
process.stdout.write(`Client: ${buf}`);
});

// Pipe all child process errors to current stderr
child.stderr.on("data", function (buf) {
process.stderr.write(`Client: ${buf}`);
});

child.on("error", function (err) {
process.stdout.write(`Client: ${err}`);
});
})
.catch(function (reason) {
fail(`Unable to connect to server: (${reason})`);
});
} else {
fail();
}
}());
1 change: 1 addition & 0 deletions config/config.js.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

var config = {
address: "localhost",
port: 8080,
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
// or add a specific IPv4 of 192.168.1.5 :
Expand Down
2 changes: 2 additions & 0 deletions js/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
*/

var port = 8080;
var address = "localhost";
if (typeof(mmPort) !== "undefined") {
port = mmPort;
}
var defaults = {
address: address,
port: port,
kioskmode: false,
electronOptions: {},
Expand Down
14 changes: 8 additions & 6 deletions js/electron.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const electron = require("electron");
const core = require(__dirname + "/app.js");

// Config
var config = {};
var config = process.env.config ? JSON.parse(process.env.config) : {};
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
Expand Down Expand Up @@ -47,7 +47,7 @@ function createWindow() {

// and load the index.html of the app.
//mainWindow.loadURL('file://' + __dirname + '../../index.html');
mainWindow.loadURL("http://localhost:" + config.port);
mainWindow.loadURL(`http://${config.address}:${config.port}`);

// Open the DevTools if run with "npm start dev"
if (process.argv.includes("dev")) {
Expand Down Expand Up @@ -96,8 +96,10 @@ app.on("activate", function() {
}
});

// Start the core application.
// Start the core application if server is run on localhost
// This starts all node helpers and starts the webserver.
core.start(function(c) {
config = c;
});
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) > -1) {
core.start(function (c) {
config = c;
});
}
4 changes: 4 additions & 0 deletions js/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ var Server = function(config, callback) {
res.send(global.version);
});

app.get("/config", function(req,res) {
res.send(config);
});

app.get("/", function(req, res) {
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), {encoding: "utf8"});
html = html.replace("#VERSION#", global.version);
Expand Down

0 comments on commit 86ae704

Please sign in to comment.