Build script
A build process that generates a package with single executable for each component.
This commit is contained in:
1 parent
819e8a52a3
commit
0b59811924
23 files changed
+722
-676
No files matched your search
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"es6": true
|
"es6": true,
|
||||||
|
"node": true
|
||||||
},
|
},
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 8
|
"ecmaVersion": 8
|
||||||
|
|||||||
+112
-6
@@ -1,9 +1,115 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
var path = require('path');
|
"use strict";
|
||||||
var fs = require('fs');
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
var dir = path.resolve(path.dirname(fs.realpathSync(__filename)), '..');
|
process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), ".."));
|
||||||
process.chdir(dir);
|
|
||||||
|
|
||||||
var cluster = require(path.resolve(dir, 'lib/cluster'));
|
const config = require("../lib/config");
|
||||||
cluster.start('cwmp');
|
const logger = require("../lib/logger");
|
||||||
|
const cluster = require("../lib/cluster");
|
||||||
|
const server = require("../lib/server");
|
||||||
|
const cwmp = require("../lib/cwmp");
|
||||||
|
const db = require("../lib/db");
|
||||||
|
const extensions = require("../lib/extensions");
|
||||||
|
const cache = require("../lib/cache");
|
||||||
|
|
||||||
|
const VERSION = require("../package.json").version;
|
||||||
|
|
||||||
|
logger.init("cwmp", VERSION);
|
||||||
|
|
||||||
|
const SERVICE_ADDRESS = config.get("CWMP_INTERFACE");
|
||||||
|
const SERVICE_PORT = config.get("CWMP_PORT");
|
||||||
|
|
||||||
|
function exitWorkerGracefully() {
|
||||||
|
db.disconnect();
|
||||||
|
cache.disconnect();
|
||||||
|
extensions.killAll();
|
||||||
|
cluster.worker.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitWorkerUngracefully() {
|
||||||
|
extensions.killAll(() => {
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cluster.worker) {
|
||||||
|
const WORKER_COUNT = config.get("CWMP_WORKER_PROCESSES");
|
||||||
|
|
||||||
|
logger.info({
|
||||||
|
message: `genieacs-cwmp starting`,
|
||||||
|
pid: process.pid,
|
||||||
|
version: VERSION
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.start(WORKER_COUNT, SERVICE_PORT, SERVICE_ADDRESS);
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGINT, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGTERM, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let ssl;
|
||||||
|
if (config.get("CWMP_SSL")) {
|
||||||
|
ssl = {
|
||||||
|
key: path.resolve(config.get("CONFIG_DIR"), "cwmp.key"),
|
||||||
|
cert: path.resolve(config.get("CONFIG_DIR"), "cwmp.crt"),
|
||||||
|
ca: path.resolve(config.get("CONFIG_DIR"), "cwmp.ca-bundle")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on("uncaughtException", err => {
|
||||||
|
if (err.code === "ERR_IPC_DISCONNECTED") return;
|
||||||
|
logger.error({
|
||||||
|
message: "Uncaught exception",
|
||||||
|
exception: err,
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
cache.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
server.start(
|
||||||
|
SERVICE_PORT,
|
||||||
|
SERVICE_ADDRESS,
|
||||||
|
ssl,
|
||||||
|
cwmp.listener,
|
||||||
|
cwmp.onConnection
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
+108
-6
@@ -1,9 +1,111 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
var path = require('path');
|
"use strict";
|
||||||
var fs = require('fs');
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
var dir = path.resolve(path.dirname(fs.realpathSync(__filename)), '..');
|
process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), ".."));
|
||||||
process.chdir(dir);
|
|
||||||
|
|
||||||
var cluster = require(path.resolve(dir, 'lib/cluster'));
|
const config = require("../lib/config");
|
||||||
cluster.start('fs');
|
const logger = require("../lib/logger");
|
||||||
|
const cluster = require("../lib/cluster");
|
||||||
|
const server = require("../lib/server");
|
||||||
|
const _fs = require("../lib/fs");
|
||||||
|
const db = require("../lib/db");
|
||||||
|
const cache = require("../lib/cache");
|
||||||
|
|
||||||
|
const VERSION = require("../package.json").version;
|
||||||
|
|
||||||
|
logger.init("fs", VERSION);
|
||||||
|
|
||||||
|
const SERVICE_ADDRESS = config.get("FS_INTERFACE");
|
||||||
|
const SERVICE_PORT = config.get("FS_PORT");
|
||||||
|
|
||||||
|
function exitWorkerGracefully() {
|
||||||
|
db.disconnect();
|
||||||
|
cache.disconnect();
|
||||||
|
cluster.worker.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitWorkerUngracefully() {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cluster.worker) {
|
||||||
|
const WORKER_COUNT = config.get("FS_WORKER_PROCESSES");
|
||||||
|
|
||||||
|
logger.info({
|
||||||
|
message: `genieacs-fs starting`,
|
||||||
|
pid: process.pid,
|
||||||
|
version: VERSION
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.start(WORKER_COUNT, SERVICE_PORT, SERVICE_ADDRESS);
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGINT, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGTERM, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let ssl;
|
||||||
|
if (config.get("FS_SSL")) {
|
||||||
|
ssl = {
|
||||||
|
key: path.resolve(config.get("CONFIG_DIR"), "fs.key"),
|
||||||
|
cert: path.resolve(config.get("CONFIG_DIR"), "fs.crt"),
|
||||||
|
ca: path.resolve(config.get("CONFIG_DIR"), "fs.ca-bundle")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on("uncaughtException", err => {
|
||||||
|
if (err.code === "ERR_IPC_DISCONNECTED") return;
|
||||||
|
logger.error({
|
||||||
|
message: "Uncaught exception",
|
||||||
|
exception: err,
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
cache.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
server.start(
|
||||||
|
SERVICE_PORT,
|
||||||
|
SERVICE_ADDRESS,
|
||||||
|
ssl,
|
||||||
|
_fs.listener,
|
||||||
|
_fs.onConnection
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
+112
-6
@@ -1,9 +1,115 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
var path = require('path');
|
"use strict";
|
||||||
var fs = require('fs');
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
var dir = path.resolve(path.dirname(fs.realpathSync(__filename)), '..');
|
process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), ".."));
|
||||||
process.chdir(dir);
|
|
||||||
|
|
||||||
var cluster = require(path.resolve(dir, 'lib/cluster'));
|
const config = require("../lib/config");
|
||||||
cluster.start('nbi');
|
const logger = require("../lib/logger");
|
||||||
|
const cluster = require("../lib/cluster");
|
||||||
|
const server = require("../lib/server");
|
||||||
|
const nbi = require("../lib/nbi");
|
||||||
|
const db = require("../lib/db");
|
||||||
|
const extensions = require("../lib/extensions");
|
||||||
|
const cache = require("../lib/cache");
|
||||||
|
|
||||||
|
const VERSION = require("../package.json").version;
|
||||||
|
|
||||||
|
logger.init("nbi", VERSION);
|
||||||
|
|
||||||
|
const SERVICE_ADDRESS = config.get("NBI_INTERFACE");
|
||||||
|
const SERVICE_PORT = config.get("NBI_PORT");
|
||||||
|
|
||||||
|
function exitWorkerGracefully() {
|
||||||
|
db.disconnect();
|
||||||
|
cache.disconnect();
|
||||||
|
extensions.killAll();
|
||||||
|
cluster.worker.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitWorkerUngracefully() {
|
||||||
|
extensions.killAll(() => {
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cluster.worker) {
|
||||||
|
const WORKER_COUNT = config.get("NBI_WORKER_PROCESSES");
|
||||||
|
|
||||||
|
logger.info({
|
||||||
|
message: `genieacs-nbi starting`,
|
||||||
|
pid: process.pid,
|
||||||
|
version: VERSION
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.start(WORKER_COUNT, SERVICE_PORT, SERVICE_ADDRESS);
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGINT, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGTERM, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let ssl;
|
||||||
|
if (config.get("NBI_SSL")) {
|
||||||
|
ssl = {
|
||||||
|
key: path.resolve(config.get("CONFIG_DIR"), "nbi.key"),
|
||||||
|
cert: path.resolve(config.get("CONFIG_DIR"), "nbi.crt"),
|
||||||
|
ca: path.resolve(config.get("CONFIG_DIR"), "nbi.ca-bundle")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on("uncaughtException", err => {
|
||||||
|
if (err.code === "ERR_IPC_DISCONNECTED") return;
|
||||||
|
logger.error({
|
||||||
|
message: "Uncaught exception",
|
||||||
|
exception: err,
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
db.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
cache.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
server.start(
|
||||||
|
SERVICE_PORT,
|
||||||
|
SERVICE_ADDRESS,
|
||||||
|
ssl,
|
||||||
|
nbi.listener,
|
||||||
|
nbi.onConnection
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
Executable
+112
@@ -0,0 +1,112 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
"use strict";
|
||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), ".."));
|
||||||
|
|
||||||
|
const config = require("../lib/config");
|
||||||
|
const logger = require("../lib/logger");
|
||||||
|
const cluster = require("../lib/cluster");
|
||||||
|
const server = require("../lib/server");
|
||||||
|
const ui = require("../lib/ui");
|
||||||
|
const db = require("../lib/ui/db");
|
||||||
|
const cache = require("../lib/cache");
|
||||||
|
|
||||||
|
const VERSION = require("../package.json").version;
|
||||||
|
|
||||||
|
logger.init("ui", VERSION);
|
||||||
|
|
||||||
|
const SERVICE_ADDRESS = config.get("UI_INTERFACE");
|
||||||
|
const SERVICE_PORT = config.get("UI_PORT");
|
||||||
|
|
||||||
|
function exitWorkerGracefully() {
|
||||||
|
db.disconnect();
|
||||||
|
cache.disconnect();
|
||||||
|
cluster.worker.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
function exitWorkerUngracefully() {
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cluster.worker) {
|
||||||
|
const WORKER_COUNT = config.get("UI_WORKER_PROCESSES");
|
||||||
|
|
||||||
|
logger.info({
|
||||||
|
message: `genieacs-ui starting`,
|
||||||
|
pid: process.pid,
|
||||||
|
version: VERSION
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.start(WORKER_COUNT, SERVICE_PORT, SERVICE_ADDRESS);
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGINT, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
logger.info({
|
||||||
|
message: "Received signal SIGTERM, exiting",
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
|
||||||
|
cluster.stop();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let ssl;
|
||||||
|
if (config.get("UI_SSL")) {
|
||||||
|
ssl = {
|
||||||
|
key: path.resolve(config.get("CONFIG_DIR"), "ui.key"),
|
||||||
|
cert: path.resolve(config.get("CONFIG_DIR"), "ui.crt"),
|
||||||
|
ca: path.resolve(config.get("CONFIG_DIR"), "ui.ca-bundle")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let stopping = false;
|
||||||
|
|
||||||
|
process.on("uncaughtException", err => {
|
||||||
|
if (err.code === "ERR_IPC_DISCONNECTED") return;
|
||||||
|
logger.error({
|
||||||
|
message: "Uncaught exception",
|
||||||
|
exception: err,
|
||||||
|
pid: process.pid
|
||||||
|
});
|
||||||
|
stopping = true;
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGINT", () => {
|
||||||
|
stopping = true;
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on("SIGTERM", () => {
|
||||||
|
stopping = true;
|
||||||
|
server
|
||||||
|
.stop()
|
||||||
|
.then(exitWorkerGracefully)
|
||||||
|
.catch(exitWorkerUngracefully);
|
||||||
|
});
|
||||||
|
|
||||||
|
const listener = (req, res) => {
|
||||||
|
if (stopping) res.setHeader("Connection", "close");
|
||||||
|
ui.listener(req, res);
|
||||||
|
};
|
||||||
|
|
||||||
|
cache.connect(err => {
|
||||||
|
if (err) throw err;
|
||||||
|
server.start(SERVICE_PORT, SERVICE_ADDRESS, ssl, listener, ui.onConnection);
|
||||||
|
});
|
||||||
|
}
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
const util = require("util");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
const nodeExternals = require("webpack-node-externals");
|
||||||
|
const postcss = require("postcss");
|
||||||
|
const postcssImport = require("postcss-import");
|
||||||
|
const postcssCssNext = require("postcss-cssnext");
|
||||||
|
const cssnano = require("cssnano");
|
||||||
|
|
||||||
|
const MODE = "production";
|
||||||
|
|
||||||
|
const BUILD_METADATA = new Date()
|
||||||
|
.toISOString()
|
||||||
|
.split(".")[0]
|
||||||
|
.replace(/[^0-9]/g, "");
|
||||||
|
|
||||||
|
const INPUT_DIR = path.resolve(__dirname, "..");
|
||||||
|
const OUTPUT_DIR = path.resolve(__dirname, "../dist");
|
||||||
|
|
||||||
|
function rmDirSync(dirPath) {
|
||||||
|
if (!fs.existsSync(dirPath)) return;
|
||||||
|
const files = fs.readdirSync(dirPath);
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const filePath = `${dirPath}/${file}`;
|
||||||
|
if (fs.statSync(filePath).isFile()) fs.unlinkSync(filePath);
|
||||||
|
else rmDirSync(filePath);
|
||||||
|
}
|
||||||
|
fs.rmdirSync(dirPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cpDirSync(src, dst) {
|
||||||
|
fs.mkdirSync(dst);
|
||||||
|
const files = fs.readdirSync(src);
|
||||||
|
for (const file of files) {
|
||||||
|
const current = fs.lstatSync(path.join(src, file));
|
||||||
|
if (current.isDirectory()) {
|
||||||
|
cpDirSync(path.join(src, file), path.join(dst, file));
|
||||||
|
} else if (current.isSymbolicLink()) {
|
||||||
|
const symlink = fs.readlinkSync(path.join(src, file));
|
||||||
|
fs.symlinkSync(symlink, path.join(dst, file));
|
||||||
|
} else {
|
||||||
|
fs.copyFileSync(path.join(src, file), path.join(dst, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
// Delete any old output directory
|
||||||
|
rmDirSync(OUTPUT_DIR);
|
||||||
|
|
||||||
|
// Create output directory layout
|
||||||
|
fs.mkdirSync(OUTPUT_DIR);
|
||||||
|
fs.mkdirSync(OUTPUT_DIR + "/bin");
|
||||||
|
fs.mkdirSync(OUTPUT_DIR + "/config");
|
||||||
|
fs.mkdirSync(OUTPUT_DIR + "/debug");
|
||||||
|
fs.mkdirSync(OUTPUT_DIR + "/public");
|
||||||
|
|
||||||
|
// Create package.json
|
||||||
|
const packageJson = require("../package.json");
|
||||||
|
delete packageJson["devDependencies"];
|
||||||
|
packageJson["scripts"] = {
|
||||||
|
install: packageJson["scripts"].install,
|
||||||
|
configure: packageJson["scripts"].configure
|
||||||
|
};
|
||||||
|
packageJson["version"] = `${packageJson["version"]}+${BUILD_METADATA}`;
|
||||||
|
fs.writeFileSync(
|
||||||
|
path.resolve(OUTPUT_DIR, "package.json"),
|
||||||
|
JSON.stringify(packageJson, null, 4)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function copyStatic() {
|
||||||
|
const files = [
|
||||||
|
"LICENSE",
|
||||||
|
"README.md",
|
||||||
|
"CHANGELOG.md",
|
||||||
|
"npm-shrinkwrap.json",
|
||||||
|
"config/config-sample.json",
|
||||||
|
"config/config-ui-sample.json",
|
||||||
|
"config/auth-sample.js",
|
||||||
|
"config/ext-sample.js",
|
||||||
|
"public/logo.svg",
|
||||||
|
"public/favicon.png"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
fs.copyFileSync(
|
||||||
|
path.resolve(INPUT_DIR, file),
|
||||||
|
path.resolve(OUTPUT_DIR, file)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpDirSync(
|
||||||
|
path.resolve(INPUT_DIR, "tools"),
|
||||||
|
path.resolve(OUTPUT_DIR, "tools")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateCss() {
|
||||||
|
const cssInPath = path.resolve(INPUT_DIR, "ui/css/app.css");
|
||||||
|
const cssOutPath = path.resolve(OUTPUT_DIR, "public/app.css");
|
||||||
|
const cssIn = fs.readFileSync(cssInPath);
|
||||||
|
const cssOut = await postcss([
|
||||||
|
postcssImport,
|
||||||
|
postcssCssNext({ warnForDuplicates: false }),
|
||||||
|
cssnano
|
||||||
|
]).process(cssIn, { from: cssInPath, to: cssOutPath });
|
||||||
|
fs.writeFileSync(cssOutPath, cssOut.css);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateJs() {
|
||||||
|
const backendConf = {
|
||||||
|
mode: MODE,
|
||||||
|
target: "node",
|
||||||
|
node: false,
|
||||||
|
entry: {
|
||||||
|
"genieacs-cwmp": path.resolve(INPUT_DIR, "bin/genieacs-cwmp"),
|
||||||
|
"genieacs-nbi": path.resolve(INPUT_DIR, "bin/genieacs-nbi"),
|
||||||
|
"genieacs-fs": path.resolve(INPUT_DIR, "bin/genieacs-fs"),
|
||||||
|
"genieacs-ui": path.resolve(INPUT_DIR, "bin/genieacs-ui")
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
[path.resolve(INPUT_DIR, "package.json")]: path.resolve(
|
||||||
|
OUTPUT_DIR,
|
||||||
|
"package.json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
externals: [nodeExternals()],
|
||||||
|
output: {
|
||||||
|
path: path.resolve(OUTPUT_DIR, "bin")
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
include: path.resolve(INPUT_DIR, "bin"),
|
||||||
|
use: path.join(__dirname, "./shebang-loader")
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true })
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const frontendConf = {
|
||||||
|
mode: MODE,
|
||||||
|
entry: path.resolve(INPUT_DIR, "ui/app.js"),
|
||||||
|
output: {
|
||||||
|
path: path.resolve(OUTPUT_DIR, "public"),
|
||||||
|
filename: "app.js"
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
[path.resolve(INPUT_DIR, "package.json")]: path.resolve(
|
||||||
|
OUTPUT_DIR,
|
||||||
|
"package.json"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const stats = await util.promisify(webpack)([backendConf, frontendConf]);
|
||||||
|
|
||||||
|
// Remove js ext and mark as executable
|
||||||
|
for (const file of [
|
||||||
|
"genieacs-cwmp",
|
||||||
|
"genieacs-nbi",
|
||||||
|
"genieacs-fs",
|
||||||
|
"genieacs-ui"
|
||||||
|
]) {
|
||||||
|
fs.renameSync(
|
||||||
|
path.resolve(OUTPUT_DIR, `bin/${file}.js`),
|
||||||
|
path.resolve(OUTPUT_DIR, `bin/${file}`)
|
||||||
|
);
|
||||||
|
const mode = fs.statSync(path.resolve(OUTPUT_DIR, `bin/${file}`)).mode;
|
||||||
|
fs.chmodSync(path.resolve(OUTPUT_DIR, `bin/${file}`), mode | 73);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write(stats.toString({ colors: true }) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
||||||
|
.then(() => {
|
||||||
|
Promise.all([copyStatic(), generateCss(), generateJs()])
|
||||||
|
.then(() => {})
|
||||||
|
.catch(err => {
|
||||||
|
process.stderr.write(err.stack + "\n");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
process.stderr.write(err.stack + "\n");
|
||||||
|
});
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
module.exports = function(source) {
|
||||||
|
return source.replace(/^#![^\n\r]*[\r\n]/, "");
|
||||||
|
};
|
||||||
@@ -8,5 +8,7 @@
|
|||||||
"FS_INTERFACE" : "0.0.0.0",
|
"FS_INTERFACE" : "0.0.0.0",
|
||||||
"FS_PORT" : 7567,
|
"FS_PORT" : 7567,
|
||||||
"FS_HOSTNAME" : "acs.example.com",
|
"FS_HOSTNAME" : "acs.example.com",
|
||||||
|
"UI_INTERFACE" : "0.0.0.0",
|
||||||
|
"UI_PORT" : 3000,
|
||||||
"DEBUG" : false
|
"DEBUG" : false
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
{
|
{
|
||||||
"server": {
|
"server": {
|
||||||
"workers": 4,
|
|
||||||
"interface": "0.0.0.0",
|
|
||||||
"port": 3000,
|
|
||||||
"nbi": "http://127.0.0.1:7557/",
|
"nbi": "http://127.0.0.1:7557/",
|
||||||
"mongodbConnectionUrl": "mongodb://127.0.0.1:27017",
|
"mongodbConnectionUrl": "mongodb://127.0.0.1:27017",
|
||||||
"jwtSecret": "jwtSecret"
|
"jwtSecret": "jwtSecret"
|
||||||
@@ -312,11 +309,5 @@
|
|||||||
"type": "device-actions"
|
"type": "device-actions"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"logger": {
|
|
||||||
"logFile": "",
|
|
||||||
"accessLogFile": "",
|
|
||||||
"logFormat": "simple",
|
|
||||||
"accessLogFormat": "simple"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"node": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-83
@@ -20,44 +20,10 @@
|
|||||||
|
|
||||||
const cluster = require("cluster");
|
const cluster = require("cluster");
|
||||||
const logger = require("./logger");
|
const logger = require("./logger");
|
||||||
const config = require("./config");
|
|
||||||
|
|
||||||
const VERSION = require("../package.json").version;
|
|
||||||
|
|
||||||
let respawnTimestamp = 0;
|
let respawnTimestamp = 0;
|
||||||
let tooManyCrashesTimestamp = 0;
|
let tooManyCrashesTimestamp = 0;
|
||||||
|
|
||||||
function getDependencyVersions() {
|
|
||||||
const dependencies = [`node@${process.versions.node}`];
|
|
||||||
try {
|
|
||||||
const npmls = JSON.parse(
|
|
||||||
require("child_process").execSync("npm ls --prod --json --depth 0")
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const k in npmls.dependencies)
|
|
||||||
dependencies.push(`${k}@${npmls.dependencies[k].version}`);
|
|
||||||
} catch (err) {
|
|
||||||
// Continue regardless of error
|
|
||||||
}
|
|
||||||
|
|
||||||
return dependencies.join(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
function getConfig() {
|
|
||||||
const conf = [];
|
|
||||||
const keys = Object.keys(process.env);
|
|
||||||
for (const k of keys) {
|
|
||||||
if (k.startsWith("GENIEACS_")) {
|
|
||||||
const name = k.slice(9);
|
|
||||||
const value = process.env[k];
|
|
||||||
const def = config.getDefault(name);
|
|
||||||
if (def == null || value !== `${def}`) conf.push(`${name}=${value}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return conf.join(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
function restartWorker(worker, code, signal) {
|
function restartWorker(worker, code, signal) {
|
||||||
const msg = {
|
const msg = {
|
||||||
message: "Worker died",
|
message: "Worker died",
|
||||||
@@ -96,24 +62,12 @@ function restartWorker(worker, code, signal) {
|
|||||||
}, respawnTimestamp - now);
|
}, respawnTimestamp - now);
|
||||||
}
|
}
|
||||||
|
|
||||||
function start(service) {
|
function start(workerCount, servicePort, serviceAddress) {
|
||||||
logger.init(service, VERSION);
|
|
||||||
const SERVICE_ADDRESS = config.get(`${service.toUpperCase()}_INTERFACE`);
|
|
||||||
const SERVICE_PORT = config.get(`${service.toUpperCase()}_PORT`);
|
|
||||||
|
|
||||||
logger.info({
|
|
||||||
message: `GenieACS (genieacs-${service}) starting`,
|
|
||||||
pid: process.pid,
|
|
||||||
version: VERSION,
|
|
||||||
dependencies: getDependencyVersions(),
|
|
||||||
config: getConfig()
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.on("listening", (worker, address) => {
|
cluster.on("listening", (worker, address) => {
|
||||||
if (
|
if (
|
||||||
(address.addressType === 4 || address.addressType === 6) &&
|
(address.addressType === 4 || address.addressType === 6) &&
|
||||||
address.address === SERVICE_ADDRESS &&
|
address.address === serviceAddress &&
|
||||||
address.port === SERVICE_PORT
|
address.port === servicePort
|
||||||
) {
|
) {
|
||||||
logger.info({
|
logger.info({
|
||||||
message: "Worker listening",
|
message: "Worker listening",
|
||||||
@@ -126,46 +80,16 @@ function start(service) {
|
|||||||
|
|
||||||
cluster.on("exit", restartWorker);
|
cluster.on("exit", restartWorker);
|
||||||
|
|
||||||
process.on("SIGINT", () => {
|
|
||||||
logger.info({
|
|
||||||
message: "Received signal SIGINT, exiting",
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
|
||||||
logger.info({
|
|
||||||
message: "Received signal SIGTERM, exiting",
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.setupMaster({
|
|
||||||
exec: "lib/server",
|
|
||||||
args: [service]
|
|
||||||
});
|
|
||||||
|
|
||||||
let workerCount = config.get(`${service.toUpperCase()}_WORKER_PROCESSES`);
|
|
||||||
|
|
||||||
if (!workerCount) workerCount = Math.max(2, require("os").cpus().length);
|
if (!workerCount) workerCount = Math.max(2, require("os").cpus().length);
|
||||||
|
|
||||||
for (let i = 0; i < workerCount; ++i) cluster.fork();
|
for (let i = 0; i < workerCount; ++i) cluster.fork();
|
||||||
}
|
}
|
||||||
|
|
||||||
process.on("uncaughtException", err => {
|
function stop() {
|
||||||
logger.error({
|
|
||||||
message: "Uncaught exception in master process, exiting",
|
|
||||||
exception: err,
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
process.exitCode = 1;
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
cluster.removeListener("exit", restartWorker);
|
||||||
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
||||||
});
|
}
|
||||||
|
|
||||||
exports.start = start;
|
exports.start = start;
|
||||||
|
exports.stop = stop;
|
||||||
|
exports.worker = cluster.worker;
|
||||||
+18
-2
@@ -19,6 +19,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
CONFIG_DIR: { type: "path", default: "config" },
|
CONFIG_DIR: { type: "path", default: "config" },
|
||||||
@@ -52,6 +53,13 @@ const options = {
|
|||||||
FS_LOG_FILE: { type: "path", default: "" },
|
FS_LOG_FILE: { type: "path", default: "" },
|
||||||
FS_ACCESS_LOG_FILE: { type: "path", default: "" },
|
FS_ACCESS_LOG_FILE: { type: "path", default: "" },
|
||||||
|
|
||||||
|
UI_WORKER_PROCESSES: { type: "int", default: 0 },
|
||||||
|
UI_PORT: { type: "int", default: 3000 },
|
||||||
|
UI_INTERFACE: { type: "string", default: "0.0.0.0" },
|
||||||
|
UI_SSL: { type: "bool", default: false },
|
||||||
|
UI_LOG_FILE: { type: "path", default: "" },
|
||||||
|
UI_ACCESS_LOG_FILE: { type: "path", default: "" },
|
||||||
|
|
||||||
UDP_CONNECTION_REQUEST_PORT: { type: "int", default: 0 },
|
UDP_CONNECTION_REQUEST_PORT: { type: "int", default: 0 },
|
||||||
|
|
||||||
DOWNLOAD_TIMEOUT: { type: "int", default: 3600 },
|
DOWNLOAD_TIMEOUT: { type: "int", default: 3600 },
|
||||||
@@ -175,7 +183,9 @@ for (const [k, v] of Object.entries(process.env))
|
|||||||
setConfig("CONFIG_DIR", options["CONFIG_DIR"]["default"]);
|
setConfig("CONFIG_DIR", options["CONFIG_DIR"]["default"]);
|
||||||
|
|
||||||
// Configuration file
|
// Configuration file
|
||||||
const configFile = require(path.resolve(allConfig.CONFIG_DIR, "config"));
|
const configFile = JSON.parse(
|
||||||
|
fs.readFileSync(path.resolve(allConfig.CONFIG_DIR, "config.json"))
|
||||||
|
);
|
||||||
for (const [k, v] of Object.entries(configFile)) {
|
for (const [k, v] of Object.entries(configFile)) {
|
||||||
if (!setConfig(k, v))
|
if (!setConfig(k, v))
|
||||||
// Pass as environment variable to be accessable by extensions
|
// Pass as environment variable to be accessable by extensions
|
||||||
@@ -226,7 +236,13 @@ function getDefault(optionName) {
|
|||||||
|
|
||||||
// Load authentication scripts
|
// Load authentication scripts
|
||||||
try {
|
try {
|
||||||
exports.auth = require(path.resolve(allConfig.CONFIG_DIR, "auth"));
|
const authScript = fs.readFileSync(
|
||||||
|
path.resolve(allConfig.CONFIG_DIR, "auth.js")
|
||||||
|
);
|
||||||
|
exports.auth = (function(exports) {
|
||||||
|
eval(authScript.toString());
|
||||||
|
return exports;
|
||||||
|
})({});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// No auth.js exists
|
// No auth.js exists
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,17 @@ function flatten(details) {
|
|||||||
delete details.fault;
|
delete details.fault;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For genieacs-ui
|
||||||
|
if (details.context) {
|
||||||
|
details.remoteAddress = details.context.request.ip;
|
||||||
|
if (details.context.state.user)
|
||||||
|
details.user = details.context.state.user.username;
|
||||||
|
delete details.context;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const [k, v] of Object.entries(details))
|
||||||
|
if (v == null) delete details[k];
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,12 +218,15 @@ function formatSimple(details, systemd) {
|
|||||||
if (details.remoteAddress) {
|
if (details.remoteAddress) {
|
||||||
if (details.deviceId)
|
if (details.deviceId)
|
||||||
remote = `${details.remoteAddress} ${details.deviceId}: `;
|
remote = `${details.remoteAddress} ${details.deviceId}: `;
|
||||||
|
else if (details.user)
|
||||||
|
remote = `${details.user}@${details.remoteAddress}: `;
|
||||||
else remote = `${details.remoteAddress}: `;
|
else remote = `${details.remoteAddress}: `;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keys = Object.keys(details);
|
const keys = Object.keys(details);
|
||||||
const skip = {
|
const skip = {
|
||||||
deviceId: 1,
|
deviceId: 1,
|
||||||
|
user: 1,
|
||||||
remoteAddress: 1,
|
remoteAddress: 1,
|
||||||
severity: 1,
|
severity: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
|||||||
+21
-64
@@ -18,29 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const service = process.argv[2];
|
|
||||||
|
|
||||||
if (service == null) throw new Error("Missing argument cwmp, fs, or nbi");
|
|
||||||
|
|
||||||
const cluster = require("cluster");
|
|
||||||
const path = require("path");
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const http = require("http");
|
const http = require("http");
|
||||||
const https = require("https");
|
const https = require("https");
|
||||||
const logger = require("./logger");
|
|
||||||
logger.init(service, require("../package.json").version);
|
|
||||||
const config = require("./config");
|
|
||||||
const db = require("./db");
|
|
||||||
const cache = require("./cache");
|
|
||||||
const extensions = require("./extensions");
|
|
||||||
|
|
||||||
const networkInterface = config.get(`${service.toUpperCase()}_INTERFACE`);
|
let server, listener;
|
||||||
const port = config.get(`${service.toUpperCase()}_PORT`);
|
|
||||||
const useHttps = config.get(`${service.toUpperCase()}_SSL`);
|
|
||||||
|
|
||||||
const { listener, onConnection } = require(`./${service}`);
|
|
||||||
|
|
||||||
let server;
|
|
||||||
|
|
||||||
function closeServer(timeout, callback) {
|
function closeServer(timeout, callback) {
|
||||||
if (!server) return void callback();
|
if (!server) return void callback();
|
||||||
@@ -66,46 +48,19 @@ function closeServer(timeout, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function exit() {
|
function start(port, networkInterface, ssl, _listener, onConnection) {
|
||||||
setTimeout(() => {
|
listener = _listener;
|
||||||
extensions.killAll(() => {
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
}, 30000).unref();
|
|
||||||
|
|
||||||
closeServer(20000, () => {
|
if (ssl) {
|
||||||
db.disconnect();
|
|
||||||
cache.disconnect();
|
|
||||||
extensions.killAll();
|
|
||||||
if (cluster.worker) cluster.worker.disconnect();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on("uncaughtException", err => {
|
|
||||||
logger.error({
|
|
||||||
message: "Uncaught exception",
|
|
||||||
exception: err,
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (useHttps) {
|
|
||||||
const httpsKey = path.resolve(config.get("CONFIG_DIR"), `${service}.key`);
|
|
||||||
const httpsCert = path.resolve(config.get("CONFIG_DIR"), `${service}.crt`);
|
|
||||||
const httpsCa = path.resolve(
|
|
||||||
config.get("CONFIG_DIR"),
|
|
||||||
`${service}.ca-bundle`
|
|
||||||
);
|
|
||||||
const options = {
|
const options = {
|
||||||
key: fs.readFileSync(httpsKey),
|
key: fs.readFileSync(ssl.key),
|
||||||
cert: fs.readFileSync(httpsCert)
|
cert: fs.readFileSync(ssl.cert)
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use intermediate certificates if available
|
// Use intermediate certificates if available
|
||||||
options.ca = fs
|
options.ca = fs
|
||||||
.readFileSync(httpsCa)
|
.readFileSync(ssl.ca)
|
||||||
.toString()
|
.toString()
|
||||||
.match(/-+BEGIN CERTIFICATE-+[0-9a-zA-Z+\-/=\s]+?-+END CERTIFICATE-+/g);
|
.match(/-+BEGIN CERTIFICATE-+[0-9a-zA-Z+\-/=\s]+?-+END CERTIFICATE-+/g);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -113,20 +68,22 @@ if (useHttps) {
|
|||||||
}
|
}
|
||||||
server = https.createServer(options, listener);
|
server = https.createServer(options, listener);
|
||||||
if (onConnection != null) server.on("secureConnection", onConnection);
|
if (onConnection != null) server.on("secureConnection", onConnection);
|
||||||
} else {
|
} else {
|
||||||
server = http.createServer(listener);
|
server = http.createServer(listener);
|
||||||
if (onConnection != null) server.on("connection", onConnection);
|
if (onConnection != null) server.on("connection", onConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
db.connect(err => {
|
|
||||||
if (err) throw err;
|
|
||||||
|
|
||||||
cache.connect(err => {
|
|
||||||
if (err) throw err;
|
|
||||||
|
|
||||||
server.listen(port, networkInterface);
|
server.listen(port, networkInterface);
|
||||||
});
|
}
|
||||||
});
|
|
||||||
|
|
||||||
process.on("SIGINT", exit);
|
function stop() {
|
||||||
process.on("SIGTERM", exit);
|
return new Promise((resolve, reject) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
reject(new Error("Could not close server in a timely manner"));
|
||||||
|
}, 30000).unref();
|
||||||
|
closeServer(20000, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.start = start;
|
||||||
|
exports.stop = stop;
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const http = require("http");
|
|
||||||
const cluster = require("cluster");
|
|
||||||
const Koa = require("koa");
|
const Koa = require("koa");
|
||||||
const Router = require("koa-router");
|
const Router = require("koa-router");
|
||||||
const koaStatic = require("koa-static");
|
const koaStatic = require("koa-static");
|
||||||
@@ -10,15 +8,11 @@ const koaBodyParser = require("koa-bodyparser");
|
|||||||
const koaJwt = require("koa-jwt");
|
const koaJwt = require("koa-jwt");
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
const config = require("./config");
|
const config = require("./ui/config");
|
||||||
const api = require("./api");
|
const api = require("./ui/api");
|
||||||
const Authorizer = require("../common/authorizer");
|
const Authorizer = require("./common/authorizer");
|
||||||
const expression = require("../common/expression");
|
const expression = require("./common/expression");
|
||||||
const logger = require("./logger");
|
const logger = require("./logger");
|
||||||
const db = require("./db");
|
|
||||||
|
|
||||||
const VERSION = require("../../package.json")["version"];
|
|
||||||
logger.init("server", VERSION);
|
|
||||||
|
|
||||||
const koa = new Koa();
|
const koa = new Koa();
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
@@ -170,51 +164,7 @@ koa.use(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const server = http
|
|
||||||
.createServer(koa.callback())
|
|
||||||
.listen(config.server.port, config.server.interface);
|
|
||||||
|
|
||||||
koa.use(async (ctx, next) => {
|
|
||||||
await next();
|
|
||||||
if (!server.listening) ctx.set("Connection", "close");
|
|
||||||
});
|
|
||||||
|
|
||||||
koa.use(router.routes());
|
koa.use(router.routes());
|
||||||
koa.use(koaStatic("./public"));
|
koa.use(koaStatic("./public"));
|
||||||
|
|
||||||
function closeServer(timeout) {
|
exports.listener = koa.callback();
|
||||||
return new Promise(resolve => {
|
|
||||||
// prevent new sockets to connect and close server eventually.
|
|
||||||
server.close(resolve);
|
|
||||||
setTimeout(resolve, timeout).unref();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function exit() {
|
|
||||||
setTimeout(() => {
|
|
||||||
process.exit(1);
|
|
||||||
}, 30000).unref();
|
|
||||||
|
|
||||||
closeServer(20000).then(() => {
|
|
||||||
db.disconnect();
|
|
||||||
if (cluster.worker) cluster.worker.disconnect();
|
|
||||||
logger.close();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on("unhandledRejection", err => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on("uncaughtException", err => {
|
|
||||||
logger.error({
|
|
||||||
message: "Uncaught exception",
|
|
||||||
exception: err,
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
process.exitCode = 1;
|
|
||||||
exit();
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on("SIGINT", exit);
|
|
||||||
process.on("SIGTERM", exit);
|
|
||||||
+1
-1
@@ -5,7 +5,7 @@ const Router = require("koa-router");
|
|||||||
const db = require("./db");
|
const db = require("./db");
|
||||||
const apiFunctions = require("./api-functions");
|
const apiFunctions = require("./api-functions");
|
||||||
const expression = require("../common/expression");
|
const expression = require("../common/expression");
|
||||||
const logger = require("./logger");
|
const logger = require("../logger");
|
||||||
|
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const cluster = require("cluster");
|
|
||||||
const config = require("./config");
|
|
||||||
const logger = require("./logger");
|
|
||||||
|
|
||||||
const VERSION = require("../../package.json")["version"];
|
|
||||||
|
|
||||||
let respawnTimestamp = 0;
|
|
||||||
let tooManyCrashesTimestamp = 0;
|
|
||||||
|
|
||||||
function restartWorker(worker, code, signal) {
|
|
||||||
const msg = {
|
|
||||||
message: "Worker died",
|
|
||||||
pid: worker.process.pid
|
|
||||||
};
|
|
||||||
|
|
||||||
if (code != null) msg.exitCode = code;
|
|
||||||
|
|
||||||
if (signal != null) msg.signal = signal;
|
|
||||||
|
|
||||||
logger.error(msg);
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
respawnTimestamp = Math.max(now, respawnTimestamp + 2000);
|
|
||||||
if (respawnTimestamp === now) {
|
|
||||||
tooManyCrashesTimestamp = now;
|
|
||||||
cluster.fork();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now - tooManyCrashesTimestamp > 60000) {
|
|
||||||
process.exitCode = 1;
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
|
||||||
|
|
||||||
logger.error({
|
|
||||||
message: "Too many crashes, exiting",
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
if (process.exitCode) return;
|
|
||||||
cluster.fork();
|
|
||||||
}, respawnTimestamp - now);
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
|
||||||
logger.init(VERSION);
|
|
||||||
|
|
||||||
logger.info({
|
|
||||||
message: "GenieACS UI starting",
|
|
||||||
pid: process.pid,
|
|
||||||
version: VERSION
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.on("listening", (worker, address) => {
|
|
||||||
logger.info({
|
|
||||||
message: "Worker listening",
|
|
||||||
pid: worker.process.pid,
|
|
||||||
address: address.address,
|
|
||||||
port: address.port
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.on("exit", restartWorker);
|
|
||||||
|
|
||||||
process.on("SIGINT", () => {
|
|
||||||
logger.info({
|
|
||||||
message: "Received signal SIGINT, exiting",
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
});
|
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
|
||||||
logger.info({
|
|
||||||
message: "Received signal SIGTERM, exiting",
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
cluster.setupMaster({ exec: "./server" });
|
|
||||||
|
|
||||||
let workerCount = config.server.workers;
|
|
||||||
|
|
||||||
if (!workerCount) workerCount = Math.max(2, require("os").cpus().length);
|
|
||||||
|
|
||||||
for (let i = 0; i < workerCount; ++i) cluster.fork();
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on("uncaughtException", err => {
|
|
||||||
logger.error({
|
|
||||||
message: "Uncaught exception in master process, exiting",
|
|
||||||
exception: err,
|
|
||||||
pid: process.pid
|
|
||||||
});
|
|
||||||
process.exitCode = 1;
|
|
||||||
cluster.removeListener("exit", restartWorker);
|
|
||||||
for (const pid in cluster.workers) cluster.workers[pid].kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Starting GenieACS UI
|
|
||||||
start();
|
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const configFile = JSON.parse(fs.readFileSync("./config-ui.json"));
|
const configFile = JSON.parse(fs.readFileSync("./config/config-ui.json"));
|
||||||
|
|
||||||
const config = loadConfig(configFile);
|
const config = loadConfig(configFile);
|
||||||
|
|
||||||
|
|||||||
@@ -1,249 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
const fs = require("fs");
|
|
||||||
const os = require("os");
|
|
||||||
|
|
||||||
const config = require("./config");
|
|
||||||
|
|
||||||
const REOPEN_EVERY = 60000;
|
|
||||||
|
|
||||||
const LOG_FORMAT = config.logger.logFormat;
|
|
||||||
const ACCESS_LOG_FORMAT = config.logger.accessLogFormat || LOG_FORMAT;
|
|
||||||
|
|
||||||
const defaultMeta = {};
|
|
||||||
|
|
||||||
let LOG_SYSTEMD = false;
|
|
||||||
let ACCESS_LOG_SYSTEMD = false;
|
|
||||||
|
|
||||||
let LOG_FILE, ACCESS_LOG_FILE;
|
|
||||||
|
|
||||||
let logStream = fs.createWriteStream(null, { fd: process.stderr.fd });
|
|
||||||
let logStat = fs.fstatSync(logStream.fd);
|
|
||||||
let accessLogStream = fs.createWriteStream(null, { fd: process.stdout.fd });
|
|
||||||
let accessLogStat = fs.fstatSync(accessLogStream.fd);
|
|
||||||
|
|
||||||
// Reopen if original files have been moved (e.g. logrotate)
|
|
||||||
function reopen() {
|
|
||||||
let counter = 1;
|
|
||||||
|
|
||||||
if (LOG_FILE) {
|
|
||||||
++counter;
|
|
||||||
fs.stat(LOG_FILE, (err, stat) => {
|
|
||||||
if (err && !err.message.startsWith("ENOENT:")) throw err;
|
|
||||||
|
|
||||||
if (!(stat && stat.dev === logStat.dev && stat.ino === logStat.ino)) {
|
|
||||||
logStream.end();
|
|
||||||
logStream = fs.createWriteStream(null, {
|
|
||||||
fd: fs.openSync(LOG_FILE, "a")
|
|
||||||
});
|
|
||||||
logStat = fs.fstatSync(logStream.fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--counter === 0)
|
|
||||||
setTimeout(reopen, REOPEN_EVERY - (Date.now() % REOPEN_EVERY)).unref();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ACCESS_LOG_FILE) {
|
|
||||||
++counter;
|
|
||||||
fs.stat(ACCESS_LOG_FILE, (err, stat) => {
|
|
||||||
if (err && !err.message.startsWith("ENOENT:")) throw err;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!(
|
|
||||||
stat &&
|
|
||||||
stat.dev === accessLogStat.dev &&
|
|
||||||
stat.ino === accessLogStat.ino
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
accessLogStream.end();
|
|
||||||
accessLogStream = fs.createWriteStream(null, {
|
|
||||||
fd: fs.openSync(ACCESS_LOG_FILE, "a")
|
|
||||||
});
|
|
||||||
accessLogStat = fs.fstatSync(accessLogStream.fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--counter === 0)
|
|
||||||
setTimeout(reopen, REOPEN_EVERY - (Date.now() % REOPEN_EVERY)).unref();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (--counter === 0)
|
|
||||||
setTimeout(reopen, REOPEN_EVERY - (Date.now() % REOPEN_EVERY)).unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
function init(version) {
|
|
||||||
defaultMeta.hostname = os.hostname();
|
|
||||||
defaultMeta.pid = process.pid;
|
|
||||||
defaultMeta.name = "genieacs-ui";
|
|
||||||
defaultMeta.version = version;
|
|
||||||
|
|
||||||
LOG_FILE = config.logger.logFile;
|
|
||||||
ACCESS_LOG_FILE = config.logger.accessLogFile;
|
|
||||||
|
|
||||||
if (LOG_FILE) {
|
|
||||||
logStream = fs.createWriteStream(null, { fd: fs.openSync(LOG_FILE, "a") });
|
|
||||||
logStat = fs.fstatSync(logStream.fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ACCESS_LOG_FILE) {
|
|
||||||
accessLogStream = fs.createWriteStream(null, {
|
|
||||||
fd: fs.openSync(ACCESS_LOG_FILE, "a")
|
|
||||||
});
|
|
||||||
accessLogStat = fs.fstatSync(accessLogStream.fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if logs are going to journald
|
|
||||||
const JOURNAL_STREAM = process.env["JOURNAL_STREAM"];
|
|
||||||
|
|
||||||
if (JOURNAL_STREAM) {
|
|
||||||
let [dev, inode] = JOURNAL_STREAM.split(":");
|
|
||||||
dev = parseInt(dev);
|
|
||||||
inode = parseInt(inode);
|
|
||||||
|
|
||||||
LOG_SYSTEMD = logStat.dev === dev && logStat.ino === inode;
|
|
||||||
ACCESS_LOG_SYSTEMD =
|
|
||||||
accessLogStat.dev === dev && accessLogStat.ino === inode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG_FILE || ACCESS_LOG_FILE)
|
|
||||||
setTimeout(reopen, REOPEN_EVERY - (Date.now() % REOPEN_EVERY)).unref();
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
accessLogStream.end();
|
|
||||||
logStream.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
function flatten(details) {
|
|
||||||
if (details.exception) {
|
|
||||||
details.exceptionName = details.exception.name;
|
|
||||||
details.exceptionMessage = details.exception.message;
|
|
||||||
details.exceptionStack = details.exception.stack;
|
|
||||||
delete details.exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (details.context) {
|
|
||||||
details.remoteAddress = details.context.request.ip;
|
|
||||||
if (details.context.state.user)
|
|
||||||
details.user = details.context.state.user.username;
|
|
||||||
delete details.context;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [k, v] of Object.entries(details))
|
|
||||||
if (v == null) delete details[k];
|
|
||||||
|
|
||||||
return details;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatJson(details, systemd) {
|
|
||||||
if (systemd) {
|
|
||||||
let severity = "";
|
|
||||||
if (details.severity === "info") severity = "<6>";
|
|
||||||
else if (details.severity === "warn") severity = "<4>";
|
|
||||||
else if (details.severity === "error") severity = "<3>";
|
|
||||||
|
|
||||||
return `${severity}${JSON.stringify(flatten(details))}${os.EOL}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${JSON.stringify(flatten(details))}${os.EOL}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatSimple(details, systemd) {
|
|
||||||
flatten(details);
|
|
||||||
|
|
||||||
let remote = "";
|
|
||||||
if (details.remoteAddress) {
|
|
||||||
if (details.user) remote = `${details.user}@${details.remoteAddress}: `;
|
|
||||||
else remote = `${details.remoteAddress}: `;
|
|
||||||
}
|
|
||||||
|
|
||||||
const keys = Object.keys(details);
|
|
||||||
const skip = {
|
|
||||||
user: 1,
|
|
||||||
remoteAddress: 1,
|
|
||||||
severity: 1,
|
|
||||||
timestamp: 1,
|
|
||||||
message: 1
|
|
||||||
};
|
|
||||||
|
|
||||||
let meta = "";
|
|
||||||
|
|
||||||
const kv = [];
|
|
||||||
for (const k of keys)
|
|
||||||
if (!skip[k]) kv.push(`${k}=${JSON.stringify(details[k])}`);
|
|
||||||
|
|
||||||
if (kv.length) meta = `; ${kv.join(" ")}`;
|
|
||||||
|
|
||||||
if (systemd) {
|
|
||||||
let severity = "";
|
|
||||||
if (details.severity === "info") severity = "<6>";
|
|
||||||
else if (details.severity === "warn") severity = "<4>";
|
|
||||||
else if (details.severity === "error") severity = "<3>";
|
|
||||||
|
|
||||||
return `${severity}${remote}${details.message}${meta}${os.EOL}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${details.timestamp} [${details.severity.toUpperCase()}] ${remote}${
|
|
||||||
details.message
|
|
||||||
}${meta}${os.EOL}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function log(details) {
|
|
||||||
details.timestamp = new Date().toISOString();
|
|
||||||
if (LOG_FORMAT === "json") {
|
|
||||||
details = Object.assign({}, defaultMeta, details);
|
|
||||||
logStream.write(formatJson(details, LOG_SYSTEMD));
|
|
||||||
} else {
|
|
||||||
logStream.write(formatSimple(details, LOG_SYSTEMD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function info(details) {
|
|
||||||
details.severity = "info";
|
|
||||||
log(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
function warn(details) {
|
|
||||||
details.severity = "warn";
|
|
||||||
log(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
function error(details) {
|
|
||||||
details.severity = "error";
|
|
||||||
log(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
function accessLog(details) {
|
|
||||||
details.timestamp = new Date().toISOString();
|
|
||||||
if (ACCESS_LOG_FORMAT === "json") {
|
|
||||||
Object.assign(details, defaultMeta);
|
|
||||||
accessLogStream.write(formatJson(details, ACCESS_LOG_SYSTEMD));
|
|
||||||
} else {
|
|
||||||
accessLogStream.write(formatSimple(details, ACCESS_LOG_SYSTEMD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function accessInfo(details) {
|
|
||||||
details.severity = "info";
|
|
||||||
accessLog(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
function accessWarn(details) {
|
|
||||||
details.severity = "warn";
|
|
||||||
accessLog(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
function accessError(details) {
|
|
||||||
details.severity = "error";
|
|
||||||
accessLog(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.init = init;
|
|
||||||
exports.close = close;
|
|
||||||
exports.info = info;
|
|
||||||
exports.warn = warn;
|
|
||||||
exports.error = error;
|
|
||||||
exports.accessInfo = accessInfo;
|
|
||||||
exports.accessWarn = accessWarn;
|
|
||||||
exports.accessError = accessError;
|
|
||||||
+6
-11
@@ -19,7 +19,6 @@
|
|||||||
"bin": "bin"
|
"bin": "bin"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"codemirror": "^5.40.0",
|
|
||||||
"jsonwebtoken": "^8.3.0",
|
"jsonwebtoken": "^8.3.0",
|
||||||
"koa-bodyparser": "^4.2.1",
|
"koa-bodyparser": "^4.2.1",
|
||||||
"koa-compress": "^3.0.0",
|
"koa-compress": "^3.0.0",
|
||||||
@@ -31,26 +30,23 @@
|
|||||||
"libxmljs": "^0.19.5",
|
"libxmljs": "^0.19.5",
|
||||||
"mongodb": "^3.1.10",
|
"mongodb": "^3.1.10",
|
||||||
"parsimmon": "^1.12.0",
|
"parsimmon": "^1.12.0",
|
||||||
"seedrandom": "^2.4.4",
|
"seedrandom": "^2.4.4"
|
||||||
"yaml": "^1.0.0"
|
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"redis": "^2.6.5"
|
"redis": "^2.6.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-eslint": "^8.2.6",
|
"babel-eslint": "^8.2.6",
|
||||||
"clean-webpack-plugin": "^0.1.19",
|
"codemirror": "^5.40.0",
|
||||||
"copy-webpack-plugin": "^4.5.2",
|
|
||||||
"cssnano": "^4.0.5",
|
"cssnano": "^4.0.5",
|
||||||
"eslint": "^5.10.0",
|
"eslint": "^5.10.0",
|
||||||
"mithril": "^1.1.6",
|
"mithril": "^1.1.6",
|
||||||
"postcss-cli": "^6.0.0",
|
|
||||||
"postcss-cssnext": "^3.1.0",
|
"postcss-cssnext": "^3.1.0",
|
||||||
"postcss-import": "^11.1.0",
|
"postcss-import": "^11.1.0",
|
||||||
"prettier": "^1.15.3",
|
"prettier": "^1.15.3",
|
||||||
"webpack": "^4.16.3",
|
"webpack": "^4.16.3",
|
||||||
"webpack-cli": "^3.1.0",
|
"webpack-node-externals": "^1.7.2",
|
||||||
"webpack-node-externals": "^1.7.2"
|
"yaml": "^1.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.14.0"
|
"node": ">=8.14.0"
|
||||||
@@ -60,8 +56,7 @@
|
|||||||
"configure": "if [ ! -f ./config/config.json ]; then cp ./config/config-sample.json ./config/config.json; cp ./config/config-ui-sample.json ./config/config-ui.json; fi",
|
"configure": "if [ ! -f ./config/config.json ]; then cp ./config/config-sample.json ./config/config.json; cp ./config/config-ui-sample.json ./config/config-ui.json; fi",
|
||||||
"install": "npm run configure",
|
"install": "npm run configure",
|
||||||
"test": "node test",
|
"test": "node test",
|
||||||
"lint": "eslint --fix lib ui; prettier --write \"lib/**/*.js\" \"ui/**/*.js\"",
|
"lint": "eslint --fix lib ui build bin/*; prettier --write \"lib/**/*.js\" \"ui/**/*.js\" \"build/**/*.js\" bin/*",
|
||||||
"build-ui": "npm run lint;webpack;postcss -c postcss.config.js ui/css/app.css -o dist/public/app.css",
|
"build": "node build/build"
|
||||||
"start-ui": "cd dist && node cluster"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
require("postcss-import"),
|
|
||||||
require("postcss-cssnext")({ warnForDuplicates: false }),
|
|
||||||
require("cssnano")
|
|
||||||
]
|
|
||||||
};
|
|
||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true
|
"browser": true,
|
||||||
|
"node": false
|
||||||
},
|
},
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
const nodeExternals = require("webpack-node-externals");
|
|
||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|
||||||
const CleanWebpackPlugin = require("clean-webpack-plugin");
|
|
||||||
const path = require("path");
|
|
||||||
|
|
||||||
const mode = "production";
|
|
||||||
|
|
||||||
function transformPackageJson(content) {
|
|
||||||
const pkg = JSON.parse(content);
|
|
||||||
delete pkg["devDependencies"];
|
|
||||||
pkg["scripts"] = {
|
|
||||||
"start-ui": "node cluster"
|
|
||||||
};
|
|
||||||
return JSON.stringify(pkg, null, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = [
|
|
||||||
{
|
|
||||||
mode: mode,
|
|
||||||
entry: "./lib/ui/server.js",
|
|
||||||
target: "node",
|
|
||||||
externals: [nodeExternals()],
|
|
||||||
output: {
|
|
||||||
filename: "server.js"
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new CleanWebpackPlugin(["dist"]),
|
|
||||||
new CopyWebpackPlugin(
|
|
||||||
[
|
|
||||||
{ from: "public/logo.svg", to: "public/logo.svg" },
|
|
||||||
{ from: "public/favicon.png", to: "public/favicon.png" },
|
|
||||||
{ from: "config/config-ui.json", to: "config-ui.json" },
|
|
||||||
{
|
|
||||||
from: "package.json",
|
|
||||||
to: "package.json",
|
|
||||||
transform: transformPackageJson
|
|
||||||
}
|
|
||||||
],
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: mode,
|
|
||||||
entry: "./lib/ui/cluster.js",
|
|
||||||
target: "node",
|
|
||||||
output: {
|
|
||||||
filename: "cluster.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
mode: mode,
|
|
||||||
entry: "./ui/app.js",
|
|
||||||
output: {
|
|
||||||
path: path.resolve(__dirname, "dist/public"),
|
|
||||||
filename: "app.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
Reference in new issue
Block a user