|
|
define([
|
|
|
"dojo/_base/declare",
|
|
|
"dojo/_base/lang",
|
|
|
"dojo/when",
|
|
|
"cluster",
|
|
|
"os",
|
|
|
"implab/safe",
|
|
|
"./HttpResponse",
|
|
|
"./BaseResponse",
|
|
|
"dojo/Deferred",
|
|
|
"./HttpException",
|
|
|
"@implab/core/log/trace!"],
|
|
|
function (declare, lang, when, cluster, os, safe, HttpResponse, BaseResponse, Deferred, HttpException, trace) {
|
|
|
return declare(null, {
|
|
|
_container: null,
|
|
|
_serverPort: null,
|
|
|
_bindAddr: null,
|
|
|
|
|
|
_useCluster: null,
|
|
|
|
|
|
_requestConfig: null,
|
|
|
_restartFailedWorkers: null,
|
|
|
|
|
|
// модули, обрабатывающие запрос.
|
|
|
_modules: null,
|
|
|
_handlers: null,
|
|
|
|
|
|
constructor: function (options) {
|
|
|
safe.argumentNotNull(options, "options");
|
|
|
safe.argumentNotNull(options.container, "options.container");
|
|
|
safe.argumentNotNull(options.serverPort, "options.serverPort");
|
|
|
safe.argumentNotNull(options.useCluster, "options.useCluster");
|
|
|
safe.argumentNotEmptyString(options.bindAddr, "options.bindAddr");
|
|
|
safe.argumentNotEmptyString(options.requestConfig, "options.requestConfig");
|
|
|
|
|
|
this.options = options || {};
|
|
|
this._modules = [];
|
|
|
|
|
|
this._container = options.container;
|
|
|
|
|
|
this._serverPort = options.serverPort;
|
|
|
this._bindAddr = options.bindAddr;
|
|
|
this._useCluster = options.useCluster;
|
|
|
this._restartFailedWorkers = options.restartFailedWorkers;
|
|
|
|
|
|
this._requestConfig = options.requestConfig;
|
|
|
|
|
|
this._container.getService("httpHandlers").forEach(handler => {
|
|
|
this.handle(handler);
|
|
|
});
|
|
|
},
|
|
|
|
|
|
start: function () {
|
|
|
let me = this;
|
|
|
const numCPUs = os.cpus().length;
|
|
|
if (cluster.isMaster && me._useCluster) {
|
|
|
// Fork workers.
|
|
|
for (let i = 0; i < numCPUs; i++) {
|
|
|
cluster.fork();
|
|
|
}
|
|
|
|
|
|
cluster.on('exit', function (worker, code, signal) {
|
|
|
if(me._restartFailedWorkers){
|
|
|
trace.log("worker {0} died. Signal {1}. Restarting ...", worker.process.pid, signal);
|
|
|
cluster.fork();
|
|
|
} else {
|
|
|
trace.log("worker {0} died.", worker.process.pid);
|
|
|
}
|
|
|
});
|
|
|
} else {
|
|
|
// Workers can share any TCP connection
|
|
|
// In this case it is an HTTP server
|
|
|
this.listen(this._serverPort, this._bindAddr);
|
|
|
}
|
|
|
},
|
|
|
|
|
|
listen: function (port, host) {
|
|
|
this._host = host;
|
|
|
this._port = port;
|
|
|
|
|
|
this._createServer(this.options, lang.hitch(this, "_handler")).listen(port, host, lang.hitch(this, "_listening"));
|
|
|
},
|
|
|
|
|
|
handle: function (module) {
|
|
|
if (module instanceof Function)
|
|
|
this._modules.push(module);
|
|
|
else if (module.invoke instanceof Function)
|
|
|
this._modules.push(function (req, next) {
|
|
|
return module.invoke(req, next);
|
|
|
});
|
|
|
else
|
|
|
throw "module shoud be a function or should have an invoke method";
|
|
|
},
|
|
|
|
|
|
_createServer: function () {
|
|
|
throw "NOT IMPLEMENTED";
|
|
|
},
|
|
|
|
|
|
_createRequest: function (container, req, res) {
|
|
|
return container.configure(this._requestConfig)
|
|
|
.then(function () {
|
|
|
let httpRequest = container.getService("httpRequest");
|
|
|
httpRequest.init(req, res);
|
|
|
return httpRequest;
|
|
|
});
|
|
|
},
|
|
|
|
|
|
//handler function to pass to the approperate server (like node.http)
|
|
|
_handler: function (req, res) {
|
|
|
let i = 0;
|
|
|
let me = this;
|
|
|
|
|
|
let requestContainer = this._container.createChildContainer();
|
|
|
|
|
|
when(this._createRequest(requestContainer, req, res), function (httpRequest) {
|
|
|
let next = function () {
|
|
|
if (i < me._modules.length) {
|
|
|
let module = me._modules[i];
|
|
|
i++;
|
|
|
try {
|
|
|
return when(module(httpRequest, next));
|
|
|
} catch (err) {
|
|
|
let d = new Deferred();
|
|
|
d.reject(err);
|
|
|
return d;
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
when(next(), function (result) {
|
|
|
if (!result)
|
|
|
throw "no response is provided, this is a serious bug";
|
|
|
|
|
|
if (result instanceof BaseResponse) {
|
|
|
result.send(res);
|
|
|
} else {
|
|
|
let httpResp = new HttpResponse();
|
|
|
httpResp.content = "BUG: " + result.toString();
|
|
|
httpResp.send(res);
|
|
|
}
|
|
|
requestContainer.dispose();
|
|
|
}).then(null, function (err) {
|
|
|
if (res.finished) {
|
|
|
trace.log("caught exception after the response is sent: {0}", err);
|
|
|
return;
|
|
|
}
|
|
|
let httpResp;
|
|
|
if (err instanceof HttpException)
|
|
|
httpResp = new HttpResponse(err.message, {
|
|
|
statusCode: err.code,
|
|
|
headers: err.headers
|
|
|
});
|
|
|
else
|
|
|
httpResp = new HttpResponse(err.toString(), {
|
|
|
statusCode: 500
|
|
|
});
|
|
|
httpResp.send(res);
|
|
|
requestContainer.dispose();
|
|
|
});
|
|
|
});
|
|
|
},
|
|
|
_listening: function () {
|
|
|
trace.log("Listening {0}:{1}", this._host, this._port);
|
|
|
},
|
|
|
|
|
|
});
|
|
|
});
|