From bcb74515798915ac3dc5045f02f354b860146c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=9A=E7=84=B6?= Date: Wed, 29 Aug 2018 14:51:36 +0800 Subject: [PATCH] feat: refact wsServer, wsServerMgr, ruleLoader, systemProxyMgr into TS --- bin/startServer.js | 2 +- lib/httpsServerMgr.ts | 6 +- lib/log.ts | 44 ++++---- lib/proxy.js | 4 +- lib/requestHandler/index.ts | 2 +- lib/{ruleLoader.js => ruleLoader.ts} | 16 +-- lib/{rule_default.js => rule_default.ts} | 10 +- lib/{systemProxyMgr.js => systemProxyMgr.ts} | 46 +++++--- lib/util.ts | 112 ++++++++++--------- lib/{wsServer.js => wsServer.ts} | 87 +++++++++----- lib/{wsServerMgr.js => wsServerMgr.ts} | 23 ++-- tslint.json | 1 + typings/index.d.ts | 1 + 13 files changed, 199 insertions(+), 155 deletions(-) rename lib/{ruleLoader.js => ruleLoader.ts} (79%) rename lib/{rule_default.js => rule_default.ts} (70%) rename lib/{systemProxyMgr.js => systemProxyMgr.ts} (79%) rename lib/{wsServer.js => wsServer.ts} (64%) rename lib/{wsServerMgr.js => wsServerMgr.ts} (58%) diff --git a/bin/startServer.js b/bin/startServer.js index 4afb6c7..f2d15eb 100644 --- a/bin/startServer.js +++ b/bin/startServer.js @@ -3,7 +3,7 @@ */ const ruleLoader = require('../dist/ruleLoader'); -const logUtil = require('../dist/log'); +const logUtil = require('../dist/log').default; const AnyProxy = require('../dist/proxy'); module.exports = function startServer(program) { diff --git a/lib/httpsServerMgr.ts b/lib/httpsServerMgr.ts index 6d29c22..28f17c0 100644 --- a/lib/httpsServerMgr.ts +++ b/lib/httpsServerMgr.ts @@ -9,11 +9,10 @@ import * as color from 'colorful'; import * as WebSocket from 'ws'; import * as constants from 'constants'; import * as AsyncTask from 'async-task-mgr'; -import Recorder from './recorder'; import certMgr from './certMgr'; import logUtil from './log'; import util from './util'; -import * as wsServerMgr from './wsServerMgr'; +import wsServerMgr from './wsServerMgr'; import * as co from 'co'; // // manage https servers @@ -31,8 +30,7 @@ import * as co from 'co'; // asyncTask = require('async-task-mgr'); declare type THttpsRequestHanlder = (req: http.IncomingMessage, userRes: http.ServerResponse) => void; -declare type TWsRequestHandler = - (userRule: AnyProxyRule, recorder: Recorder, wsClient: WebSocket, wsReq: http.IncomingMessage) => void; +declare type TWsRequestHandler = (wsClient: WebSocket, wsReq: http.IncomingMessage) => void; const createSecureContext = tls.createSecureContext || (crypto as any).createSecureContext; // using sni to avoid multiple ports diff --git a/lib/log.ts b/lib/log.ts index e4a02e4..4c22a31 100644 --- a/lib/log.ts +++ b/lib/log.ts @@ -1,5 +1,5 @@ 'use strict'; - +/*tslint:disable:no-console */ import * as color from 'colorful'; import util from './util'; @@ -12,7 +12,7 @@ enum LogLevelMap { rule_error = 2, warn = 3, debug = 4, -}; +} function setPrintStatus(status: boolean): void { ifPrint = !!status; @@ -22,7 +22,7 @@ function setLogLevel(level: string): void { logLevel = parseInt(level, 10); } -function printLog(content: string, type?: LogLevelMap) { +function printLog(content: string, type?: LogLevelMap): void { if (!ifPrint) { return; } @@ -75,35 +75,34 @@ function printLog(content: string, type?: LogLevelMap) { } } -module.exports.printLog = printLog; - -function debug (content): void { +function debug(content: string): void { printLog(content, LogLevelMap.debug); -}; +} -function info (content): void { +function info(content: string): void { printLog(content, LogLevelMap.tip); -}; +} -function warn (content) { +function warn(content: string): void { printLog(content, LogLevelMap.warn); -}; +} -function error (content) { +function error(content: string): void { printLog(content, LogLevelMap.system_error); -}; +} -function ruleError (content) { +function ruleError(content: string): void { printLog(content, LogLevelMap.rule_error); -}; +} -module.exports.setPrintStatus = setPrintStatus; -module.exports.setLogLevel = setLogLevel; -module.exports.T_TIP = LogLevelMap.tip; -module.exports.T_ERR = LogLevelMap.system_error; -module.exports.T_RULE_ERROR = LogLevelMap.rule_error; -module.exports.T_WARN = LogLevelMap.warn; -module.exports.T_DEBUG = LogLevelMap.debug; +// module.exports.setPrintStatus = setPrintStatus; +// module.exports.setLogLevel = setLogLevel; +// module.exports.T_TIP = LogLevelMap.tip; +// module.exports.T_ERR = LogLevelMap.system_error; +// module.exports.T_RULE_ERROR = LogLevelMap.rule_error; +// module.exports.T_WARN = LogLevelMap.warn; +// module.exports.T_DEBUG = LogLevelMap.debug; +// module.exports.printLog = printLog; const LogUtil = { setPrintStatus, @@ -121,5 +120,4 @@ const LogUtil = { T_DEBUG: LogLevelMap.debug, }; -exports.LogUtil = LogUtil; export default LogUtil; diff --git a/lib/proxy.js b/lib/proxy.js index b7fea5a..78a3549 100644 --- a/lib/proxy.js +++ b/lib/proxy.js @@ -6,12 +6,12 @@ const http = require('http'), color = require('colorful'), certMgr = require('./certMgr').default, Recorder = require('./recorder').default, - logUtil = require('./log'), + logUtil = require('./log').default, util = require('./util').default, events = require('events'), co = require('co'), WebInterface = require('./webInterface'), - wsServerMgr = require('./wsServerMgr'), + wsServerMgr = require('./wsServerMgr').default, ThrottleGroup = require('stream-throttle').ThrottleGroup; // const memwatch = require('memwatch-next'); diff --git a/lib/requestHandler/index.ts b/lib/requestHandler/index.ts index 99e526d..e39e526 100644 --- a/lib/requestHandler/index.ts +++ b/lib/requestHandler/index.ts @@ -414,7 +414,7 @@ class RequestHandler { public wsIntercept: boolean; public connectReqHandler: () => void; private userRequestHandler: () => void; - private wsHandler: () => void; + private wsHandler: (wsClient: WebSocket, wsReq: http.IncomingMessage) => void; private httpsServerMgr: HttpsServerMgr; /** * Creates an instance of RequestHandler. diff --git a/lib/ruleLoader.js b/lib/ruleLoader.ts similarity index 79% rename from lib/ruleLoader.js rename to lib/ruleLoader.ts index 8ec9037..1dfae17 100644 --- a/lib/ruleLoader.js +++ b/lib/ruleLoader.ts @@ -1,9 +1,9 @@ 'use strict'; -const proxyUtil = require('./util').default; -const path = require('path'); -const fs = require('fs'); -const request = require('request'); +import proxyUtil from './util'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as request from 'request'; const cachePath = proxyUtil.getAnyProxyPath('cache'); @@ -13,7 +13,7 @@ const cachePath = proxyUtil.getAnyProxyPath('cache'); * @param {any} url * @returns {string} cachePath */ -function cacheRemoteFile(url) { +function cacheRemoteFile(url: string): Promise { return new Promise((resolve, reject) => { request(url, (error, response, body) => { if (error) { @@ -39,7 +39,7 @@ function cacheRemoteFile(url) { * @param {any} filePath * @returns module */ -function loadLocalPath(filePath) { +function loadLocalPath(filePath: string): Promise { return new Promise((resolve, reject) => { const ruleFilePath = path.resolve(process.cwd(), filePath); if (fs.existsSync(ruleFilePath)) { @@ -57,14 +57,14 @@ function loadLocalPath(filePath) { * @param {any} urlOrPath * @returns module */ -function requireModule(urlOrPath) { +function requireModule(urlOrPath: string): Promise { return new Promise((resolve, reject) => { if (/^http/i.test(urlOrPath)) { resolve(cacheRemoteFile(urlOrPath)); } else { resolve(urlOrPath); } - }).then(localPath => loadLocalPath(localPath)); + }).then((localPath: string) => loadLocalPath(localPath)); } module.exports = { diff --git a/lib/rule_default.js b/lib/rule_default.ts similarity index 70% rename from lib/rule_default.js rename to lib/rule_default.ts index dc74910..da0091d 100644 --- a/lib/rule_default.js +++ b/lib/rule_default.ts @@ -17,7 +17,7 @@ module.exports = { * @param {buffer} requestDetail.response.body * @returns */ - *beforeSendRequest(requestDetail) { + *beforeSendRequest(requestDetail: AnyProxyRequestDetail): Generator { return null; }, @@ -28,7 +28,7 @@ module.exports = { * @param {object} requestDetail * @param {object} responseDetail */ - *beforeSendResponse(requestDetail, responseDetail) { + *beforeSendResponse(requestDetail: AnyProxyRequestDetail, responseDetail: AnyProxyReponseDetail): Generator { return null; }, @@ -40,7 +40,7 @@ module.exports = { * @param {any} requestDetail * @returns */ - *beforeDealHttpsRequest(requestDetail) { + *beforeDealHttpsRequest(requestDetail: AnyProxyRequestDetail): Generator { return null; }, @@ -51,7 +51,7 @@ module.exports = { * @param {any} error * @returns */ - *onError(requestDetail, error) { + *onError(requestDetail: AnyProxyRequestDetail, error: NodeJS.ErrnoException): Generator { return null; }, @@ -63,7 +63,7 @@ module.exports = { * @param {any} error * @returns */ - *onConnectError(requestDetail, error) { + *onConnectError(requestDetail: AnyProxyRequestDetail, error: NodeJS.ErrnoException): Generator { return null; }, }; diff --git a/lib/systemProxyMgr.js b/lib/systemProxyMgr.ts similarity index 79% rename from lib/systemProxyMgr.js rename to lib/systemProxyMgr.ts index 353bd6b..a94a742 100644 --- a/lib/systemProxyMgr.js +++ b/lib/systemProxyMgr.ts @@ -1,12 +1,21 @@ -'use strict' +'use strict'; +/* tslint:disable:max-line-length */ +import * as child_process from 'child_process'; +import logUtil from './log'; -const child_process = require('child_process'); +declare interface IProxyManager { + networkType?: string; + getNetworkType?: () => string; + enableGlobalProxy?: (ip: string, port: string, proxyType: 'http' | 'https') => void; + disableGlobalProxy?: (proxyType: 'http' | 'https') => void; + getProxyState?: () => IExecScriptResult; +} const networkTypes = ['Ethernet', 'Thunderbolt Ethernet', 'Wi-Fi']; -function execSync(cmd) { - let stdout, - status = 0; +function execSync(cmd: string): IExecScriptResult { + let stdout; + let status = 0; try { stdout = child_process.execSync(cmd); } catch (err) { @@ -16,7 +25,7 @@ function execSync(cmd) { return { stdout: stdout.toString(), - status + status, }; } @@ -51,13 +60,12 @@ function execSync(cmd) { * ------------------------------------------------------------------------ */ -const macProxyManager = {}; - -macProxyManager.getNetworkType = () => { - for (let i = 0; i < networkTypes.length; i++) { - const type = networkTypes[i], - result = execSync('networksetup -getwebproxy ' + type); +const macProxyManager: IProxyManager = { +}; +macProxyManager.getNetworkType = function(): string { + for (const type of networkTypes) { + const result = execSync('networksetup -getwebproxy ' + type); if (result.status === 0) { macProxyManager.networkType = type; return type; @@ -70,7 +78,7 @@ macProxyManager.getNetworkType = () => { macProxyManager.enableGlobalProxy = (ip, port, proxyType) => { if (!ip || !port) { - console.log('failed to set global proxy server.\n ip and port are required.'); + logUtil.warn('failed to set global proxy server.\n ip and port are required.'); return; } @@ -125,11 +133,11 @@ macProxyManager.getProxyState = () => { * ------------------------------------------------------------------------ */ -const winProxyManager = {}; +const winProxyManager: IProxyManager = {}; winProxyManager.enableGlobalProxy = (ip, port) => { if (!ip && !port) { - console.log('failed to set global proxy server.\n ip and port are required.'); + logUtil.warn('failed to set global proxy server.\n ip and port are required.'); return; } @@ -145,8 +153,12 @@ winProxyManager.enableGlobalProxy = (ip, port) => { winProxyManager.disableGlobalProxy = () => execSync('reg add "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings" /v ProxyEnable /t REG_DWORD /d 0 /f'); -winProxyManager.getProxyState = () => '' +winProxyManager.getProxyState = () => { + return { + status: -1, + }; +}; -winProxyManager.getNetworkType = () => '' +winProxyManager.getNetworkType = () => ''; module.exports = /^win/.test(process.platform) ? winProxyManager : macProxyManager; diff --git a/lib/util.ts b/lib/util.ts index 5f15d97..683a9d9 100644 --- a/lib/util.ts +++ b/lib/util.ts @@ -15,12 +15,13 @@ import * as color from 'colorful'; import { Buffer } from 'buffer'; import { execSync } from 'child_process'; import logUtil from './log'; +import * as os from 'os'; +import { IncomingHttpHeaders } from 'http'; - -const networkInterfaces = require('os').networkInterfaces(); +const networkInterfaces = os.networkInterfaces(); // {"Content-Encoding":"gzip"} --> {"content-encoding":"gzip"} -function lower_keys (obj: object): object { +function lower_keys(obj: object): object { for (const key in obj) { const val = obj[key]; delete obj[key]; @@ -29,15 +30,15 @@ function lower_keys (obj: object): object { } return obj; -}; +} -function merge (baseObj: object, extendObj: object): object { +function merge(baseObj: object, extendObj: object): object { for (const key in extendObj) { baseObj[key] = extendObj[key]; } return baseObj; -}; +} function getUserHome(): string { return process.env.HOME || process.env.USERPROFILE; @@ -51,7 +52,7 @@ function getAnyProxyHome(): string { return home; } -function getAnyProxyPath (pathName): string { +function getAnyProxyPath(pathName: string): string { const home = getAnyProxyHome(); const targetPath = path.join(home, pathName); if (!fs.existsSync(targetPath)) { @@ -63,41 +64,41 @@ function getAnyProxyPath (pathName): string { /** * 简易字符串render替换 */ -function simpleRender (str: string, object: object, regexp: RegExp) { +function simpleRender(str: string, object: object, regexp: RegExp): string { return String(str).replace(regexp || (/\{\{([^{}]+)\}\}/g), (match, name) => { if (match.charAt(0) === '\\') { return match.slice(1); } return (object[name] != null) ? object[name] : ''; }); -}; +} /** * 读取指定目录下的子目录 */ -function filewalker (root: string, cb: Function) { +function filewalker(root: string, cb: (err: Error, result: any) => void): void { root = root || process.cwd(); const ret = { directory: [], - file: [] + file: [], }; fs.readdir(root, (err, list) => { if (list && list.length) { list.map((item) => { - const fullPath = path.join(root, item), - stat = fs.lstatSync(fullPath); + const fullPath = path.join(root, item); + const stat = fs.lstatSync(fullPath); if (stat.isFile()) { ret.file.push({ name: item, - fullPath + fullPath, }); } else if (stat.isDirectory()) { ret.directory.push({ name: item, - fullPath + fullPath, }); } }); @@ -105,20 +106,20 @@ function filewalker (root: string, cb: Function) { cb && cb.apply(null, [null, ret]); }); -}; +} /* * 获取文件所对应的content-type以及content-length等信息 * 比如在useLocalResponse的时候会使用到 */ -function contentType (filepath: string): string { +function contentType(filepath: string): string { return mime.contentType(path.extname(filepath)) || ''; -}; +} /* * 读取file的大小,以byte为单位 */ -function contentLength (filepath: string): number { +function contentLength(filepath: string): number { try { const stat = fs.statSync(filepath); return stat.size; @@ -127,30 +128,30 @@ function contentLength (filepath: string): number { logUtil.printLog(color.red(e)); return 0; } -}; +} /* * remove the cache before requiring, the path SHOULD BE RELATIVE TO UTIL.JS */ -function freshRequire (modulePath: string): NodeModule { +function freshRequire(modulePath: string): NodeModule { delete require.cache[require.resolve(modulePath)]; return require(modulePath); -}; +} /* * format the date string * @param date Date or timestamp * @param formatter YYYYMMDDHHmmss */ -function formatDate (date: Date | number, formatter: string): string { - let finalDate : Date; +function formatDate(date: Date | number, formatter: string): string { + let finalDate: Date; if (typeof date !== 'object') { finalDate = new Date(date); } else { finalDate = date; } - const transform = function (value) { - return value < 10 ? '0' + value : value; + const transform = function(value: number): string { + return value < 10 ? '0' + value : '' + value; }; return formatter.replace(/^YYYY|MM|DD|hh|mm|ss/g, (match) => { switch (match) { @@ -167,11 +168,10 @@ function formatDate (date: Date | number, formatter: string): string { case 'ss': return transform(finalDate.getSeconds()); default: - return '' + return ''; } }); -}; - +} /** * get headers(Object) from rawHeaders(Array) @@ -179,9 +179,9 @@ function formatDate (date: Date | number, formatter: string): string { */ -function getHeaderFromRawHeaders (rawHeaders: Array) { +function getHeaderFromRawHeaders(rawHeaders: string[]): IncomingHttpHeaders { const headerObj = {}; - const _handleSetCookieHeader = function (key, value) { + const handleSetCookieHeader = function(key: string, value: string): void { if (headerObj[key].constructor === Array) { headerObj[key].push(value); } else { @@ -204,7 +204,7 @@ function getHeaderFromRawHeaders (rawHeaders: Array) { // headers with same fields could be combined with comma. Ref: https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 // set-cookie should NOT be combined. Ref: https://tools.ietf.org/html/rfc6265 if (key.toLowerCase() === 'set-cookie') { - _handleSetCookieHeader(key, value); + handleSetCookieHeader(key, value); } else { headerObj[key] = headerObj[key] + ',' + value; } @@ -212,9 +212,9 @@ function getHeaderFromRawHeaders (rawHeaders: Array) { } } return headerObj; -}; +} -function getAllIpAddress (): Array { +function getAllIpAddress(): string[] { const allIp = []; Object.keys(networkInterfaces).map((nic) => { @@ -226,7 +226,7 @@ function getAllIpAddress (): Array { }); return allIp.length ? allIp : ['127.0.0.1']; -}; +} function deleteFolderContentsRecursive(dirPath: string, ifClearFolderItself: boolean): void { if (!dirPath.trim() || dirPath === '/') { @@ -254,7 +254,9 @@ function deleteFolderContentsRecursive(dirPath: string, ifClearFolderItself: boo } catch (er) { if (process.platform === 'win32' && (er.code === 'ENOTEMPTY' || er.code === 'EBUSY' || er.code === 'EPERM')) { // Retry on windows, sometimes it takes a little time before all the files in the directory are gone - if (Date.now() - start > 1000) throw er; + if (Date.now() - start > 1000) { + throw er; + } } else if (er.code === 'ENOENT') { break; } else { @@ -269,7 +271,7 @@ function deleteFolderContentsRecursive(dirPath: string, ifClearFolderItself: boo } } -function getFreePort (): Promise { +function getFreePort(): Promise { return new Promise((resolve, reject) => { const server = require('net').createServer(); server.unref(); @@ -283,7 +285,7 @@ function getFreePort (): Promise { }); } -function collectErrorLog (error: any): string { +function collectErrorLog(error: any): string { if (error && error.code && error.toString()) { return error.toString(); } else { @@ -291,40 +293,41 @@ function collectErrorLog (error: any): string { try { const errorString = error.toString(); if (errorString.indexOf('You may only yield a function') >= 0) { - result = 'Function is not yieldable. Did you forget to provide a generator or promise in rule file ? \nFAQ http://anyproxy.io/4.x/#faq'; + result = 'Function is not yieldable. Did you forget to provide a generator or promise in rule file ? ' + + '\nFAQ http://anyproxy.io/4.x/#faq'; } - } catch (e) {} - return result + } catch (e) { logUtil.error(e.stack); } + return result; } } -function isFunc (source: object): boolean { +function isFunc(source: object): boolean { return source && Object.prototype.toString.call(source) === '[object Function]'; -}; +} /** * @param {object} content * @returns the size of the content */ -function getByteSize (content: Buffer): number { +function getByteSize(content: Buffer): number { return Buffer.byteLength(content); -}; +} /* * identify whether the */ -function isIpDomain (domain: string): boolean { +function isIpDomain(domain: string): boolean { if (!domain) { return false; } const ipReg = /^\d+?\.\d+?\.\d+?\.\d+?$/; return ipReg.test(domain); -}; +} -function execScriptSync (cmd: string): object { - let stdout, - status = 0; +function execScriptSync(cmd: string): object { + let stdout; + let status = 0; try { stdout = execSync(cmd); } catch (err) { @@ -334,14 +337,13 @@ function execScriptSync (cmd: string): object { return { stdout: stdout.toString(), - status + status, }; -}; +} -function guideToHomePage (): void { +function guideToHomePage(): void { logUtil.info('Refer to http://anyproxy.io for more detail'); -}; - +} const Util = { lower_keys, diff --git a/lib/wsServer.js b/lib/wsServer.ts similarity index 64% rename from lib/wsServer.js rename to lib/wsServer.ts index 7ab654a..d81ac63 100644 --- a/lib/wsServer.js +++ b/lib/wsServer.ts @@ -1,20 +1,43 @@ 'use strict'; -//websocket server manager +// websocket server manager +import * as WebSocket from 'ws'; +import Recorder from './recorder'; +import logUtil from './log'; +import { Server } from 'http'; -const WebSocketServer = require('ws').Server; -const logUtil = require('./log'); +declare interface IWsMessage { + type?: 'error' | 'body'; + error?: string; + reqRef?: string; + content?: { + id: number; + body: string; + error?: string; + }; +} -function resToMsg(msg, recorder, cb) { - let result = {}, - jsonData; +declare interface IWsServerConfig { + server: Server; +} + +declare interface IMultiMessageQueue { + type: 'updateMultiple' | 'updateLatestWsMsg'; + content: AnyProxyRecorder.WsResourceInfo[] | AnyProxyRecorder.WsResourceInfo; +} + +const WebSocketServer = WebSocket.Server; + +function resToMsg(msg: string, recorder: Recorder, cb: (result: IWsMessage) => void): void { + let result: IWsMessage = {}; + let jsonData; try { jsonData = JSON.parse(msg); } catch (e) { result = { type: 'error', - error: 'failed to parse your request : ' + e.toString() + error: 'failed to parse your request : ' + e.toString(), }; cb && cb(result); return; @@ -31,12 +54,12 @@ function resToMsg(msg, recorder, cb) { result.content = { id: null, body: null, - error: err.toString() + error: err.toString(), }; } else { result.content = { id: jsonData.id, - body: data.toString() + body: data.toString(), }; } cb && cb(result); @@ -46,10 +69,13 @@ function resToMsg(msg, recorder, cb) { } } -//config.server +// config.server -class wsServer { - constructor(config, recorder) { +class WsServer { + private config: IWsServerConfig; + private recorder: Recorder; + private wss: WebSocket.Server; + constructor(config: IWsServerConfig, recorder: Recorder) { if (!recorder) { throw new Error('proxy recorder is required'); } else if (!config || !config.server) { @@ -61,18 +87,18 @@ class wsServer { self.recorder = recorder; } - start() { + public start(): Promise { const self = this; const config = self.config; const recorder = self.recorder; return new Promise((resolve, reject) => { - //web socket interface + // web socket interface const wss = new WebSocketServer({ server: config.server, clientTracking: true, }); resolve(); - + // the queue of the messages to be delivered let messageQueue = []; // the flat to indicate wheter to broadcast the record @@ -83,12 +109,12 @@ class wsServer { sendMultipleMessage(); }, 50); - function sendMultipleMessage(data) { + function sendMultipleMessage(data?: AnyProxyRecorder.WsResourceInfo): void { // if the flag goes to be true, and there are records to send if (broadcastFlag && messageQueue.length > 0) { - wss && wss.broadcast({ + wss && broadcast({ type: 'updateMultiple', - content: messageQueue + content: messageQueue, }); messageQueue = []; broadcastFlag = false; @@ -97,7 +123,7 @@ class wsServer { } } - wss.broadcast = function (data) { + function broadcast(data?: IMultiMessageQueue | string): void { if (typeof data === 'object') { try { data = JSON.stringify(data); @@ -105,17 +131,17 @@ class wsServer { console.error('==> errorr when do broadcast ', e, data); } } - for (const client of wss.clients) { + wss.clients.forEach(function(client: WebSocket): void { try { client.send(data); } catch (e) { logUtil.printLog('websocket failed to send data, ' + e, logUtil.T_ERR); } - } - }; + }); + } wss.on('connection', (ws) => { - ws.on('message', (msg) => { + ws.on('message', (msg: string) => { resToMsg(msg, recorder, (res) => { res && ws.send(JSON.stringify(res)); }); @@ -130,28 +156,27 @@ class wsServer { logUtil.printLog('websocket error, ' + e, logUtil.T_ERR); }); - wss.on('close', () => { }); + wss.on('close', (err: Error) => { logUtil.error(err.stack); }); recorder.on('update', (data) => { try { sendMultipleMessage(data); } catch (e) { - console.log('ws error'); - console.log(e); + logUtil.error('ws error'); + logUtil.error(e.stack); } }); recorder.on('updateLatestWsMsg', (data) => { try { // console.info('==> update latestMsg ', data); - wss && wss.broadcast({ + wss && broadcast({ type: 'updateLatestWsMsg', - content: data + content: data, }); } catch (e) { logUtil.error(e.message); logUtil.error(e.stack); - console.error(e); } }); @@ -159,7 +184,7 @@ class wsServer { }); } - closeAll() { + public closeAll(): Promise { const self = this; return new Promise((resolve, reject) => { self.wss.close((e) => { @@ -173,4 +198,4 @@ class wsServer { } } -module.exports = wsServer; +module.exports = WsServer; diff --git a/lib/wsServerMgr.js b/lib/wsServerMgr.ts similarity index 58% rename from lib/wsServerMgr.js rename to lib/wsServerMgr.ts index 62e5a50..fa04bf1 100644 --- a/lib/wsServerMgr.js +++ b/lib/wsServerMgr.ts @@ -2,8 +2,9 @@ * manage the websocket server * */ -const ws = require('ws'); -const logUtil = require('./log.js'); +import * as ws from 'ws'; +import * as http from 'http'; +import logUtil from './log.js'; const WsServer = ws.Server; @@ -13,9 +14,12 @@ const WsServer = ws.Server; {string} config.server {handler} config.handler */ -function getWsServer(config) { +function getWsServer(config: { + server: http.Server; + connHandler: (wsClient: ws, wsReq: http.IncomingMessage) => void; +}): ws.Server { const wss = new WsServer({ - server: config.server + server: config.server, }); wss.on('connection', config.connHandler); @@ -24,16 +28,19 @@ function getWsServer(config) { headers.push('x-anyproxy-websocket:true'); }); - wss.on('error', e => { + wss.on('error', (e) => { logUtil.error(`error in websocket proxy: ${e.message},\r\n ${e.stack}`); - console.error('error happened in proxy websocket:', e) + console.error('error happened in proxy websocket:', e); }); - wss.on('close', e => { + wss.on('close', (e) => { console.error('==> closing the ws server'); }); return wss; } -module.exports.getWsServer = getWsServer; +export default { + getWsServer, +}; + diff --git a/tslint.json b/tslint.json index 6635f17..f770284 100644 --- a/tslint.json +++ b/tslint.json @@ -13,6 +13,7 @@ "ordered-imports": false, "only-arrow-functions": false, "no-reference": false, + "forin": false, "typedef": [ true, "call-signature", diff --git a/typings/index.d.ts b/typings/index.d.ts index 63b80b8..5564e63 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -85,4 +85,5 @@ declare interface OneLevelObjectType { declare interface IExecScriptResult { status: number; + stdout?: string; } \ No newline at end of file