mirror of
https://github.com/alibaba/anyproxy.git
synced 2025-04-24 08:41:31 +00:00
feat: refact wsServer, wsServerMgr, ruleLoader, systemProxyMgr into TS
This commit is contained in:
parent
4497160284
commit
bcb7451579
@ -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) {
|
||||
|
@ -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
|
||||
|
44
lib/log.ts
44
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;
|
||||
|
@ -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');
|
||||
|
@ -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.
|
||||
|
@ -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<string> {
|
||||
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<NodeJS.Module> {
|
||||
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<NodeJS.Module> {
|
||||
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 = {
|
@ -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;
|
||||
},
|
||||
};
|
@ -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;
|
112
lib/util.ts
112
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<string>) {
|
||||
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<string>) {
|
||||
// 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<string>) {
|
||||
}
|
||||
}
|
||||
return headerObj;
|
||||
};
|
||||
}
|
||||
|
||||
function getAllIpAddress (): Array<string> {
|
||||
function getAllIpAddress(): string[] {
|
||||
const allIp = [];
|
||||
|
||||
Object.keys(networkInterfaces).map((nic) => {
|
||||
@ -226,7 +226,7 @@ function getAllIpAddress (): Array<string> {
|
||||
});
|
||||
|
||||
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<number> {
|
||||
function getFreePort(): Promise<number> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = require('net').createServer();
|
||||
server.unref();
|
||||
@ -283,7 +285,7 @@ function getFreePort (): Promise<number> {
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
|
@ -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,12 +87,12 @@ class wsServer {
|
||||
self.recorder = recorder;
|
||||
}
|
||||
|
||||
start() {
|
||||
public start(): Promise<any> {
|
||||
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,
|
||||
@ -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<any> {
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
self.wss.close((e) => {
|
||||
@ -173,4 +198,4 @@ class wsServer {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = wsServer;
|
||||
module.exports = WsServer;
|
@ -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,
|
||||
};
|
||||
|
@ -13,6 +13,7 @@
|
||||
"ordered-imports": false,
|
||||
"only-arrow-functions": false,
|
||||
"no-reference": false,
|
||||
"forin": false,
|
||||
"typedef": [
|
||||
true,
|
||||
"call-signature",
|
||||
|
1
typings/index.d.ts
vendored
1
typings/index.d.ts
vendored
@ -85,4 +85,5 @@ declare interface OneLevelObjectType {
|
||||
|
||||
declare interface IExecScriptResult {
|
||||
status: number;
|
||||
stdout?: string;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user