@ntlab/sms-gateway
Version:
245 lines (227 loc) • 8.94 kB
JavaScript
/**
* The MIT License (MIT)
*
* Copyright (c) 2018-2024 Toha <tohenk@yahoo.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Main App handler.
*/
const path = require('path');
const Cmd = require('@ntlab/ntlib/cmd');
if (require.main === module) {
Cmd.addBool('help', 'h', 'Show program usage').setAccessible(false);
Cmd.addVar('config', '', 'Read app configuration from file', 'config-file');
Cmd.addVar('url', 'u', 'Use terminal at URL if no configuration supplied', 'url');
Cmd.addVar('key', 'k', 'Terminal secret key', 'key');
Cmd.addVar('port', 'p', 'Set web server port to listen', 'port');
Cmd.addVar('plugins', '', 'Load plugins at start, separate each plugin with comma', 'plugins');
if (!Cmd.parse() || (Cmd.get('help') && usage())) {
process.exit();
}
}
const fs = require('fs');
const Logger = require('@ntlab/ntlib/logger');
const { Work } = require('@ntlab/work');
const database = {
dialect: 'mysql',
host: 'localhost',
port: 3306,
user: 'root',
password: null,
database: 'smsgw'
}
class App {
config = {}
initialize() {
let filename;
// read configuration from command line values
if (Cmd.get('config') && fs.existsSync(Cmd.get('config'))) {
filename = Cmd.get('config');
} else if (fs.existsSync(path.join(process.cwd(), 'config.json'))) {
filename = path.join(process.cwd(), 'config.json');
} else if (fs.existsSync(path.join(__dirname, 'config.json'))) {
filename = path.join(__dirname, 'config.json');
}
if (filename) {
filename = fs.realpathSync(filename);
console.log('Reading configuration %s', filename);
this.config = JSON.parse(fs.readFileSync(filename));
}
const workdir = this.config.workdir ? this.config.workdir : __dirname;
// check for default configuration
if (!this.config.database) {
this.config.database = database;
}
if (!this.config.countryCode) {
this.config.countryCode = '62';
}
if (!this.config.operatorFilename) {
this.config.operatorFilename = path.join(__dirname, 'Operator.ini');
}
if (!this.config.configdir) {
this.config.configdir = path.join(workdir, 'config');
}
if (!this.config.datadir) {
this.config.datadir = path.join(workdir, 'data');
}
if (!this.config.sessiondir) {
this.config.sessiondir = path.join(workdir, 'sessions');
}
if (!this.config.logdir) {
this.config.logdir = path.join(workdir, 'logs');
}
if (!this.config.secret) {
this.config.secret = this.hashgen();
console.log('Using secret: %s', this.config.secret);
}
if (!this.config.security) {
this.config.security = {};
}
if (!this.config.security.username) {
this.config.security.username = 'admin';
console.log('Web interface username using default: %s', this.config.security.username);
}
if (!this.config.security.password) {
this.config.security.password = this.hashgen();
console.log('Web interface password generated: %s', this.config.security.password);
}
if (!this.config.database.logging) {
const dblogger = new Logger(path.join(this.config.logdir, 'db.log'));
this.config.database.logging = (...args) => {
dblogger.log.apply(dblogger, args);
}
}
if (!this.config.ui) {
this.config.ui = '@ntlab/sms-gateway-ui';
}
this.config.plugins = Cmd.get('plugins');
// check pools
if (!this.config.pools) {
this.config.pools = [{
name: 'localhost',
url: Cmd.get('url') || 'http://localhost:8000',
key: Cmd.get('key') || ''
}];
}
this.config.getPath = function(path) {
let rootPath = this.rootPath;
if (rootPath) {
if (rootPath.substr(-1) === '/') {
rootPath = rootPath.substr(0, rootPath.length - 1);
}
if (rootPath) {
path = rootPath + path;
}
}
return path;
}
return true;
}
hashgen() {
const crypto = require('crypto');
const shasum = crypto.createHash('sha1');
shasum.update(new Date().toISOString() + (Math.random() * 1000000).toString());
return shasum.digest('hex').substr(0, 8);
}
createTerm() {
this.term = require('./term');
return this.term.init(this.config);
}
createUI() {
return new Promise((resolve, reject) => {
try {
this.ui = require(this.config.ui)(this.config);
} catch (err) {
console.error(`Web interface not available: ${this.config.ui} (${err})`);
}
resolve();
});
}
startTerm() {
return new Promise((resolve, reject) => {
// create server
const server = require('http').Server(this.ui ? this.ui : {});
// create socket.io server
const opts = {};
if (this.config.cors) {
opts.cors = this.config.cors;
} else {
opts.cors = {origin: '*'};
}
if (this.config.rootPath) {
opts.path = this.config.getPath('/socket.io/');
}
const { Server } = require('socket.io');
const io = new Server(server, opts);
const termio = require('socket.io-client');
this.term.setSocketIo(io);
this.term.setTermIo(termio);
// configure ui
if (this.ui) {
this.ui.title = 'SMS Gateway';
this.ui.term = this.ui.locals.term = this.term;
this.ui.authenticate = (username, password) => {
return username === this.config.security.username && password === this.config.security.password ?
true : false;
}
const packageInfo = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json')));
this.ui.about = {
title: packageInfo.description,
version: packageInfo.version,
author: packageInfo.author.name ? packageInfo.author.name + ' <' + packageInfo.author.email + '>' : packageInfo.author,
license: packageInfo.license
}
}
// start server
const port = Cmd.get('port') || 8080;
server.listen(port, () => {
console.log('Application ready on port %s...', port);
});
resolve();
});
}
run() {
if (this.initialize()) {
Work.works([
[w => this.createTerm()],
[w => this.createUI()],
[w => this.startTerm()],
]);
}
}
}
if (require.main === module) {
(function run() {
new App().run();
})();
function usage() {
console.log('Usage:');
console.log(' node %s [options]', path.basename(process.argv[1]));
console.log('');
console.log('Options:');
console.log(Cmd.dump());
console.log('');
return true;
}
} else {
module.exports = App;
}