UNPKG

jbd

Version:
627 lines (544 loc) 16.2 kB
/** * ========================================== * Name: Net * Author: Buddy-Deus * CreTime: 2014-11-20 * Description: 网络操作 * Log * 2015-06-09 初始化 * ========================================== */ jBD.define(function (module, exports, require) { "use strict"; const net = require("net"), http = require("http"), url = require("url"), qs = require("querystring"), error = jBD.error; let THttpClient, THttpServer; THttpClient = (TObject => { const METHOD = ["GET", "POST", "PUT", "DELETE"]; return TObject.extend({ className: "THttpClient", create: function (opt) { this.reset(); this.set(opt); jBD.each(METHOD, d => this[d.toLowerCase()] = function (data) { return this.oper(d, data); }); }, free: function () { this.header = null; this.uri = null; }, reset: function () { this.timeout = 300; this.header = {"Content-Type": "application/json"}; this.uri = url.parse("http://127.0.0.1"); return this; }, set: function (tag, value) { switch (tag) { default: if (arguments.length == 1) { switch (typeof(tag)) { case "string": this.set("url", tag); break; case "number": this.set("timeout", tag); break; case "object": if (tag) { this .set("url", tag.uri) .set("timeout", tag.timeout) .set("header", tag.header); } break; } } break; case "url": if (value && jBD.isString(value)) this.uri = url.parse(value); break; case "timeout": if (jBD.isNumber(value) && value > 0) this.timeout = value; break; case "header": if (jBD.isObject(value)) { jBD.each(value, (d, k) => this.header[k] = d); } break; } return this; }, oper: function (method, data) { let dtd = jBD.Deferred(), path = this.uri.path, header = this.header, req; if (!jBD.has(method = method.toUpperCase(), METHOD)) method = METHOD[0]; if (!data) delete header["Content-Length"]; else { switch (method) { case "get": if (!jBD.isSimple(data)) data = qs.stringify(data); path += (uri.query.length > 0 ? "&" : "?") + data; delete header["Content-Length"]; break; case "post": data = jBD.Conver.toString(data); header["Content-Length"] = data.length; break; } } let httpUtil = {}; httpUtil.post = function (uri, param, opts) { if (!opts) opts = {}; return new Promise(function (resolve, reject) { let postData, option, protocol, req; if (opts.hasOwnProperty("form-data") && !opts["form-data"]) postData = param; else postData = querystring.stringify(param); option = url.parse(uri); option["method"] = "POST"; option["headers"] = { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(postData, "utf8") }; if (opts.hasOwnProperty("headers")) { for (let k in opts["headers"]) option["headers"][k] = opts["headers"][k]; } protocol = option["protocol"] == "http:" ? http : https; req = protocol.request(option, function (res, body) { body = ""; res.on("data", chunk => body += chunk); res.on("end", () => resolve(body)); res.on("error", err => reject(err)); }); req.on("error", err => reject(err)); req.write(postData); req.end(); }); }; req = http.request( { method: method.toUpperCase(), host: this.uri.hostname, port: this.uri.port, path: path, timeout: this.timeout * 1000, headers: this.header }, res => { let body = ""; if (res.statusCode != 200) dtd.reject(error(101, res.statusCode), res); else { res .on("data", d => body += d) .on("end", json => { if (!jBD.isJSON(body)) dtd.resolve(body, res); else { json = jBD.Conver.toJSON(body); if (json.errorCode == void(0) || !json.errorCode) dtd.resolve(json, res); else dtd.reject(json); } }); } } ); req.on("error", e => dtd.reject(error(-999, e.message || ""), e)); if (method == "POST" && data.length > 0) req.write(data); req.end(); return dtd.promise(); } }); })(jBD.TObject); THttpServer = (TObject => { const STATE = { inited: 0, listening: 1, close: 2, error: 3 }, EVENT = ["listening", "error", "close"]; return TObject.extend({ className: "THttpServer", create: function (opt, router = opt) { let middle = this.__middle = {}, event = this.__event = {}; this.state = STATE.inited; this.reset().set(opt); this.__server = null; jBD.each(EVENT, key => { event[key] = []; middle[key] = plug[key] || []; }); this.listen = this.open; if (this.port < 1) this.open(this.port, this.host, this.max); }, free: function () { }, reset: function () { if (this.state != STATE.listening) { this.host = "0.0.0.0"; this.port = 8080; this.max = 0; this.timeout = 120; } return this; }, set: function (tag, value) { if (this.state != STATE.listening) { switch (tag) { default: if (arguments.length == 1) { switch (typeof (tag)) { case "string": this.set("host", tag); break; case "number": this.set("port", tag); break; case "object": if (tag) { this .set("host", tag.host) .set("port", tag.port) .set("max", tag.max) .set("timeout", tag.timeout); } break; } } break; case "host": if (value === "localhost") this.host = "127.0.0.1"; else if (jBD.Check.IP(value)) this.host = value; break; case "port": if (jBD.isNumber(value) && value > 0) this.port = value; break; case "max": if (jBD.isNumber(value) && value >= 0) this.max = value; break; case "timeout": if (jBD.isNumber(value) && value > 0) this.timeout = value; break; case "socket": if (jBD.isFunction(value)) this.socket = value; break; } } return this; }, open: function () { let _this = this; if (_this.state == STATE.listening) return _this; let serve; http.globalAgent.maxSockets = _this.max; serve = _this.__server = http.createServer(function () { }); jBD.each(EVENT, k => { if (k == "timeout") { serve.setTime(_this.timeout, function () { }); } else { serve.on(k, function (d) { switch (k) { case "listening": _this.state = true; _this.__date = new Date(); console.info("========================================"); console.info("HTTP Listening: " + _this.host + ":" + _this.port); console.info("****************************************\n"); break; case "close": _this.state = false; d = jBD.Date.ValueOf(jBD.Date.Dec(_this.__date)); console.info("\n****************************************"); console.info("HTTP Close: " + jBD.Conver.toString(new Date(), "yyyy-mm-dd hh:nn:ss.zzz")); console.info("HTTP Close: " + d.value + d.unit); console.info("========================================"); break; } }); } }); serve.listen(_this.port, _this.host); return _this; }, close: function () { this.__server.close(); } }); })(jBD.TObject); let API = {}; API.httpClientIP = req => req.headers["x-real-ip"] || req.headers["x-forwarded-for"] || (req.socket && req.socket.remoteAddress) || (req.connection && req.connection.remoteAddress || req.connection.socket.remoteAddress); /** * http客户端请求 * * @param {string|object} opt * @param {string} [opt.uri] * @param {string} [opt.method=get] * @param {number} [opt.timeout=300] * @param {object} [opt.header] * @param {string} [method] * @param {string|object} [data] * @param {function} callback * @returns {*} */ API.httpClient = function (opt, method, data = method, callback = data) { return (new THttpClient()).set(opt).oper(method, data || "").done(callback); }; /** * http服务端请求 * * @param {string|number|object} [opt] 启动参数 * @param {function} [socket] socket处理 * @returns {object} * @return {boolean} [STATE] */ API.httpServer = function (opt, socket) { return (new THttpServer()).set(opt).set("socket", socket); }; API.tcpClient = function (host, port, timeout) { const TYPE = ["error", "timeout", "connect", "close", "end", "data"], fmtOpt = function (host, port, timeout) { switch (arguments.length) { case 1: port = host; timeout = null; host = null; break; case 2: port = host; timeout = port; host = null; break; } this.HOST = jBD.isString(host) ? host : this.HOST; this.PORT = jBD.isNumber(port) && port > 0 ? port : this.PORT; this.TIMEOUT = jBD.isNumber(timeout) && timeout >= 0 ? timeout : this.TIMEOUT; if (this.HOST == "localhost") this.HOST = "127.0.0.1"; if (!jBD.Check.IP(this.HOST)) this.HOST = "0.0.0.0"; return this; }, middle = {}, api = { TYPE: "client", STATE: false, HOST: "127.0.0.1", PORT: 6140, TIMEOUT: 0, "set": function (type, func) { if (arguments.length == 1) { func = type; type = null; } if (!type) type = "data"; if (jBD.has(type, TYPE)) { switch (jBD.type(func, true)) { case "array": jBD.each(func, function (d) { api.set(type, d); }); break; case "function": if (middle[type]) middle[type].push(func); else middle[type] = [func]; break; } } return api; }, open: function (host, port, timeout) { fmtOpt.apply(api, arguments); if (api.TIMEOUT > 0) { client.setTimeout(api.TIMEOUT); client.setKeepAlive(true, api.TIMEOUT); } else { client.setTimeout(0); client.setKeepAlive(false); } if (!api.STATE) client.connect(api.PORT, api.HOST); }, close: function () { if (api.STATE) client.destroy(); }, end: function (data) { if (api.STATE) client.end.apply(client, arguments); }, send: function (data) { if (api.STATE) client.write.apply(client, arguments); } }; let client; switch (jBD.type(host, true)) { case "string": default: fmtOpt.call(api, host, port, timeout); break; case "object": client = host; api.TYPE = "server"; api.HOST = client.remoteAddress; api.PORT = client.remotePort; api.STATE = true; api.HOST = api.HOST.split(":"); api.HOST = api.HOST[api.HOST.length - 1]; if (jBD.isNumber(port)) fmtOpt.call(api, port); break; case "number": fmtOpt.call(api, host); break; } if (!client) client = new net.Socket(); jBD.each(TYPE, key => { client.on(key, data => { switch (key) { case "connect": api.STATE = true; break; case "end": case "close": api.STATE = false; break; } jBD.each(middle[key], d => { if (d.apply(api, [api, data]) === false) return false; }); }); }); if (arguments.length >= 1 && api.TYPE != "server") api.open(); return api; }; API.tcpServer = function (host, port, timeout) { const TYPE = ["listening", "error", "close", "timeout", "connect", "data", "end"], fmtOpt = function (host, port, timeout) { switch (arguments.length) { case 1: port = host; timeout = null; host = null; break; case 2: port = host; timeout = port; host = null; break; } this.HOST = jBD.isString(host) ? host : this.HOST; this.PORT = jBD.isNumber(port) && port > 0 ? port : this.PORT; this.TIMEOUT = jBD.isNumber(timeout) && timeout >= 0 ? timeout : this.TIMEOUT; if (this.HOST == "localhost") this.HOST = "127.0.0.1"; if (!jBD.Check.IP(this.HOST)) this.HOST = "0.0.0.0"; }, middle = {}, api = { socket: {length: 0}, STATE: false, HOST: "0.0.0.0", PORT: 6140, TIMEOUT: 0, "set": function (type, func) { if (arguments.length == 1) { func = type; type = null; } if (!type) type = "data"; if (jBD.has(type, TYPE)) { switch (jBD.type(func, true)) { case "array": jBD.each(func, d => api.set(type, d)); break; case "function": if (middle[type]) middle[type].push(func); else middle[type] = [func]; break; } } return api; }, open: function (host, port, timeout) { fmtOpt.apply(api, arguments); if (!api.STATE) { if (api.HOST) server.listen(api.PORT, api.HOST); } }, close: function () { if (api.STATE) server.close(); }, send: function (socket, data, out) { if (!api.STATE) return; if (arguments.length == 1) { data = socket; socket = null; } if (!socket) socket = api.socket; else if (api.socket.length < 1) return; else { if (out) { socket = {list: api.socket, key: socket, length: 0}; for (let k in socket.list) { if (k != "length" && k != socket.key) { socket[k] = socket.list[k]; socket.length++; } } if (socket.length < 1) return; else { delete socket.list; delete socket.key; } } else { if (socket = api.socket[socket]) socket = {t: socket}; else return; } } for (let k in socket) { if (k != "length") socket[k].send(data); } } }, server = net.createServer((socket, key) => { const delSocket = (api, key) => { return function () { if (api.socket[key]) { delete api.socket[key]; api.socket.length--; } } }; socket = API.tcpClient(socket, api.TIMEOUT); key = socket.HOST + ":" + socket.PORT; socket .set("error", middle.error) .set("timeout", middle.timeout) .set("end", delSocket(api, key)) .set("close", delSocket(api, key)) .set("close", middle.end) .set("data", middle.data); api.socket[key] = socket; api.socket.length++; jBD.each(middle.connect, d => { if (d.apply(api, [socket, key]) === false) return false; }); }); jBD.each(["listening", "error", "close"], key => { server.on(key, data => { if (key == "listening") { api.STATE = true; data = server.address(); console.info("========================================"); console.info("TCP Listening: " + data.address + ":" + data.port); console.info("****************************************\n"); } else api.STATE = false; if (key == "close") api.socket = {length: 0}; jBD.each(middle[key], d => { if (d(data) === false) return false; }); if (key == "close") { console.info("\n****************************************"); console.info("TCP Close: " + jBD.Conver.toString(new Date(), "yyyy-mm-dd hh:nn:ss.zzz")); console.info("========================================"); } }); }); if (arguments.length > 0) api.open.apply(api, arguments); return api; }; return API; }, {module: module, exports: this}, ["Conver", "Check"], "Net");