@iotflows/iotflows-remote-access
Version:
IoTFlows Remote Access and health monitoring tool.
188 lines (154 loc) • 5.64 kB
JavaScript
/**
* Copyright 2019-2022 IoTFlows Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable laconsole.w or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/
var http = require('http');
var express = require("express");
var fs = require("fs");
var fetch = require('node-fetch');
var runtime = require("@node-red/runtime");
const { exec, spawn } = require("child_process");
class iotflows_managed_nodered {
constructor(username, password)
{
var self = this;
self.username = username;
self.password = password;
self.authHeader = {'Authorization': 'Basic ' + Buffer.from(username + ":" + password).toString("base64")}
self.homeDir = require('os').homedir();
self.RED = require("node-red");
// Create the base settings
self.iotflowsSettings =
{
uiPort: process.env.PORT || 2020,
uiHost: "::",
mqttReconnectTime: 15000,
serialReconnectTime: 15000,
debugMaxLength: 1000,
userDir: __dirname + "/.node-red/",
functionGlobalContext: {
os:require('os')
},
logging: {
console: {
level: "info",
metrics: false,
audit: false
}
},
editorTheme: {
projects: {
enabled: false
}
}
}
// Grab current settings of Node-RED if exists
if(!fs.existsSync(self.homeDir + "/.node-red"))
{
fs.mkdirSync(self.homeDir + "/.node-red");
}
try
{
self.currentSettings = require(self.homeDir + "/.node-red/settings.js")
try {delete self.currentSettings.adminAuth} catch(e){}
try {delete self.currentSettings.httpNodeAuth} catch(e){}
try {delete self.currentSettings.httpStaticAuth} catch(e){}
}
catch(e){}
}
async start()
{
try{
var self = this;
// Read cloud settings
let cloudSettings = {}
await fetch(`https://api.iotflows.com/v1/devices/${self.username}/nodered/settings`, {
headers: self.authHeader
})
.then(res => res.json())
.then(json => {
if(json && json.data){
cloudSettings = json.data.nodered_settings || {}
}else{
cloudSettings = {}
}
});
// Merge settings
self.mergedSettings = {
...self.iotflowsSettings,
...self.currentSettings,
...cloudSettings
};
// IMPORTANT! COPY this object with no reference
self.mergedSettings = JSON.parse(JSON.stringify(self.mergedSettings));
// Make sure Node-RED is not running
self.bash('sudo systemctl stop nodered.service');
self.bash('sudo systemctl disable nodered.service');
self.startServer();
}
catch(e)
{
console.error(e)
}
}
startServer()
{
var self = this;
// Create an Express app
this.app = express();
// Add a simple route for static content served from 'public'
this.app.use("/", express.static("public"));
// Create a server
this.server = http.createServer(self.app);
// Initialise the runtime with a server and settings
this.RED.init(self.server, self.mergedSettings);
// Serve the editor UI from /red
this.app.use(self.mergedSettings.httpAdminRoot, this.RED.httpAdmin);
// Serve the http nodes UI from /api
this.app.use(self.mergedSettings.httpNodeRoot, this.RED.httpNode);
self.server.listen(self.mergedSettings.uiPort);
// self.server.listen(2020);
// Start the runtime
this.RED.start();
}
async restart()
{
try{
var self = this;
await self.server.close();
await self.RED.stop();
self.start();
}
catch(e){
console.error(e)
}
}
// Execute a bash command
bash(command)
{
exec(command, (error, stdout, stderr) => {
if (error) {
// console.log(`error: ${error.message}`);
return;
}
if (stderr) {
// console.log(`stderr: ${stderr}`);
return;
}
// console.log(`stdout: ${stdout}`);
});
}
}
module.exports = iotflows_managed_nodered