const fs = require('fs'); const path = require('path'); const url = require('url'); const express = require('express'); const service_loader = require('./service-loader'); module.exports = class ServConServer { constructor(opts){ this._port = opts.port || 80; this._scanInterval = opts.scanInterval || 20000; this._scanTask = null; this._running = false; this._loaded = {}; this._router = null; this.serviceDirectory = opts.directory || path.join(process.cwd(), 'services'); this.app = express(); this.app.use((req, res, next) => this._dispatch(req, res, next)); this.server = null; } start(){ if(!this._running){ this._scanTask = setInterval(() => this._scanServices(), this._scanInterval); this._scanServices(); this.server = this.app.listen(this._port); this._running = true; } } stop(){ if(this._running){ clearInterval(this._scanTask); this._scanTask = null; this.server.close(); this._running = false; } } _loadService(fname, service_path){ console.log("Load Service",fname, service_path); service_loader.loadService(service_path, service => { this._loaded[fname] = service; }); } _scanServices(){ console.log('scan...'); fs.readdir(this.serviceDirectory, (err, files) => { if(err){ console.log('error while scanning services', err); }else { files.forEach(file => { let name = file.match(/^([a-z0-9\-\_]+)\.[0-9a-z]+$/i)[1]; let service_path = path.join(this.serviceDirectory, file); if(this._loaded[name]){ fs.stat(service_path, (err, stats) => { if(err){ console.error(err); }else if(stats.mtimeMs > this._loaded[name].modMs) { this._loadService(name, service_path); } }); }else { this._loadService(name, service_path); } }); } }); } _logRequest(req, res){ let time = process.hrtime(); let msg = `[${req.method.magenta}] ${req.url.magenta} "${req.header('user-agent')}"@${req.ip}`; res.on('finish', () => { let elapsed = process.hrtime(time); let reqTime = Math.ceil(elapsed[0] * 1000 + elapsed[1] / 1e6) + ''; console.debug(`${msg} [${reqTime.green}] ms`); }); } _dispatch(req, res, next){ this._logRequest(req, res); let req_url = url.parse(req.url); let req_url_tokens = req_url.pathname.split('/'); let service_name = req_url_tokens[1]; let service = this._loaded[service_name]; if(service){ let path_tokens_splice = req_url_tokens.splice(2); let new_path = '/'; path_tokens_splice.forEach(t => new_path += `${t}/`); req.url = `${new_path}${req_url.search || ''}`; service.router(req, res, next); }else { res.sendStatus(404); } } }