core,presets: move tracker preset to core
This commit is contained in:
parent
e466e555c9
commit
6239d4cedd
@ -193,13 +193,13 @@ export class ACL extends EventEmitter {
|
||||
|
||||
_hrTimeBegin = process.hrtime();
|
||||
|
||||
_remoteHost = null;
|
||||
_sourceHost = null;
|
||||
|
||||
_remotePort = null;
|
||||
_sourcePort = null;
|
||||
|
||||
_dstHost = null;
|
||||
_targetHost = null;
|
||||
|
||||
_dstPort = null;
|
||||
_targetPort = null;
|
||||
|
||||
_totalOut = 0;
|
||||
|
||||
@ -237,8 +237,8 @@ export class ACL extends EventEmitter {
|
||||
|
||||
constructor({ remoteInfo, rules, max_tries = DEFAULT_MAX_TRIES }) {
|
||||
super();
|
||||
this._remoteHost = remoteInfo.host;
|
||||
this._remotePort = remoteInfo.port;
|
||||
this._sourceHost = remoteInfo.host;
|
||||
this._sourcePort = remoteInfo.port;
|
||||
this._rules = rules;
|
||||
this._maxTries = max_tries;
|
||||
}
|
||||
@ -261,7 +261,7 @@ export class ACL extends EventEmitter {
|
||||
|
||||
applyRule(rule) {
|
||||
const { isBan, upLimit, dlLimit } = rule;
|
||||
logger.debug(`[acl] [${this._remoteHost}:${this._remotePort}] apply rule: "${rule}"`);
|
||||
logger.debug(`[acl] [${this._sourceHost}:${this._sourcePort}] apply rule: "${rule}"`);
|
||||
|
||||
// ban
|
||||
if (isBan) {
|
||||
@ -283,7 +283,7 @@ export class ACL extends EventEmitter {
|
||||
|
||||
// determine timeout to resume
|
||||
const timeout = speed / upLimit * 1.1; // more 10% cost
|
||||
const direction = `[${this._remoteHost}:${this._remotePort}] -> [${this._dstHost}:${this._dstPort}]`;
|
||||
const direction = `[${this._sourceHost}:${this._sourcePort}] -> [${this._targetHost}:${this._targetPort}]`;
|
||||
logger.info(`[acl] ${direction} upload speed exceed: ${speed}b/s > ${upLimit}b/s, pause for ${timeout}s...`);
|
||||
|
||||
this.emit('action', { type: ACL_PAUSE_RECV });
|
||||
@ -308,7 +308,7 @@ export class ACL extends EventEmitter {
|
||||
|
||||
// determine timeout to resume
|
||||
const timeout = speed / dlLimit * 1.1; // more 10% cost
|
||||
const direction = `[${this._remoteHost}:${this._remotePort}] <- [${this._dstHost}:${this._dstPort}]`;
|
||||
const direction = `[${this._sourceHost}:${this._sourcePort}] <- [${this._targetHost}:${this._targetPort}]`;
|
||||
logger.info(`[acl] ${direction} download speed exceed: ${speed}b/s > ${dlLimit}b/s, pause for ${timeout}s...`);
|
||||
|
||||
this.emit('action', { type: ACL_PAUSE_SEND });
|
||||
@ -331,14 +331,14 @@ export class ACL extends EventEmitter {
|
||||
return false;
|
||||
}
|
||||
|
||||
setTargetAddress({ host, port }) {
|
||||
this._dstHost = host;
|
||||
this._dstPort = port;
|
||||
this.checkRule(host, port);
|
||||
setTargetAddress(host, port) {
|
||||
this._targetHost = host;
|
||||
this._targetPort = port;
|
||||
return this.checkRule(host, port);
|
||||
}
|
||||
|
||||
checkFailTimes(tries) {
|
||||
const host = this._remoteHost;
|
||||
const host = this._sourceHost;
|
||||
const maxTries = this._maxTries;
|
||||
if (tries[host] === undefined) {
|
||||
tries[host] = 0;
|
||||
@ -359,8 +359,13 @@ export class ACL extends EventEmitter {
|
||||
} else {
|
||||
this._totalIn += size;
|
||||
}
|
||||
this.checkRule(this._remoteHost, this._remotePort);
|
||||
this.checkRule(this._dstHost, this._dstPort);
|
||||
this.checkRule(this._sourceHost, this._sourcePort);
|
||||
this.checkRule(this._targetHost, this._targetPort);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._rules = null;
|
||||
this._cachedRules = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { PRESET_FAILED } from '../presets/actions';
|
||||
import { logger } from '../utils';
|
||||
|
||||
// .on('broadcast')
|
||||
// .on(`pre_${direction}`)
|
||||
// .on(`post_${direction}`)
|
||||
export class Pipe extends EventEmitter {
|
||||
|
||||
|
102
src/core/tracker.js
Normal file
102
src/core/tracker.js
Normal file
@ -0,0 +1,102 @@
|
||||
import format from 'filesize';
|
||||
import { logger } from '../utils';
|
||||
import { PIPE_ENCODE } from '../constants';
|
||||
|
||||
const TRACK_CHAR_UPLOAD = 'u';
|
||||
const TRACK_CHAR_DOWNLOAD = 'd';
|
||||
const TRACK_MAX_SIZE = 60;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Track data send/receive events, and print a part of them once connection closed.
|
||||
*
|
||||
* +---+-----------------------+---+
|
||||
* | C | d <--> u u <--> d | S |
|
||||
* +---+-----------------------+---+
|
||||
*
|
||||
*/
|
||||
export class Tracker {
|
||||
|
||||
// ['source', 'target', 'u', '20', 'u', '20', 'd', '10', ...]
|
||||
_tracks = [];
|
||||
|
||||
_config;
|
||||
_transport;
|
||||
|
||||
_sourceHost;
|
||||
_sourcePort;
|
||||
|
||||
_targetHost;
|
||||
_targetPort;
|
||||
|
||||
constructor({ config, transport, remoteInfo }) {
|
||||
this._config = config;
|
||||
this._transport = transport;
|
||||
this._sourceHost = remoteInfo.host;
|
||||
this._sourcePort = remoteInfo.port;
|
||||
this._tracks.push(`${this._sourceHost}:${this._sourcePort}`);
|
||||
}
|
||||
|
||||
setTargetAddress(host, port) {
|
||||
this._targetHost = host;
|
||||
this._targetPort = port;
|
||||
this._tracks.push(`${host}:${port}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* print connection track string, and only display the
|
||||
* leading and the trailing TRACK_MAX_SIZE / 2
|
||||
* @param tracks
|
||||
*/
|
||||
dump() {
|
||||
let strs = [];
|
||||
let dp = 0, db = 0;
|
||||
let up = 0, ub = 0;
|
||||
let ud = '';
|
||||
for (const el of this._tracks) {
|
||||
if (el === TRACK_CHAR_UPLOAD || el === TRACK_CHAR_DOWNLOAD) {
|
||||
if (ud === el) {
|
||||
continue;
|
||||
}
|
||||
ud = el;
|
||||
}
|
||||
if (Number.isInteger(el)) {
|
||||
if (ud === TRACK_CHAR_DOWNLOAD) {
|
||||
dp += 1;
|
||||
db += el;
|
||||
}
|
||||
if (ud === TRACK_CHAR_UPLOAD) {
|
||||
up += 1;
|
||||
ub += el;
|
||||
}
|
||||
}
|
||||
strs.push(el);
|
||||
}
|
||||
const perSize = Math.floor(TRACK_MAX_SIZE / 2);
|
||||
if (strs.length > TRACK_MAX_SIZE) {
|
||||
strs = strs.slice(0, perSize).concat([' ... ']).concat(strs.slice(-perSize));
|
||||
}
|
||||
db = format(db, { output: 'array' }).join('');
|
||||
ub = format(ub, { output: 'array' }).join('');
|
||||
const summary = this._config.is_client ? `out/in = ${up}/${dp}, ${ub}/${db}` : `in/out = ${dp}/${up}, ${db}/${ub}`;
|
||||
logger.info(`[tracker:${this._transport}] summary(${summary}) abstract(${strs.join(' ')})`);
|
||||
}
|
||||
|
||||
trace(type, size) {
|
||||
if (type === PIPE_ENCODE) {
|
||||
this._tracks.push(TRACK_CHAR_UPLOAD);
|
||||
this._tracks.push(size);
|
||||
} else {
|
||||
this._tracks.push(TRACK_CHAR_DOWNLOAD);
|
||||
this._tracks.push(size);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._tracks !== null) {
|
||||
this.dump();
|
||||
}
|
||||
this._tracks = null;
|
||||
}
|
||||
|
||||
}
|
@ -1,16 +1,5 @@
|
||||
// - pushed by relay
|
||||
|
||||
/**
|
||||
* {
|
||||
* type: CONNECTION_CREATED,
|
||||
* payload: {
|
||||
* host: '127.0.0.1',
|
||||
* port: 12345
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
export const CONNECTION_CREATED = '@action:connection_created';
|
||||
|
||||
/**
|
||||
* {
|
||||
* type: CONNECTION_CLOSED
|
||||
|
@ -1,5 +1,4 @@
|
||||
// functional
|
||||
import TrackerPreset from './tracker';
|
||||
import AutoConfPreset from './auto-conf';
|
||||
import MuxPreset from './mux';
|
||||
|
||||
@ -30,7 +29,6 @@ import AeadRandomCipherPreset from './aead-random-cipher';
|
||||
|
||||
const presetMap = {
|
||||
// functional
|
||||
'tracker': TrackerPreset,
|
||||
'auto-conf': AutoConfPreset,
|
||||
'mux': MuxPreset,
|
||||
|
||||
@ -91,7 +89,7 @@ export function getPresetClassByName(name) {
|
||||
try {
|
||||
clazz = require(name);
|
||||
} catch (err) {
|
||||
throw Error(`cannot load preset: "${name}" from built-in modules or external`);
|
||||
throw Error(`cannot load preset "${name}" from built-in modules or external`);
|
||||
}
|
||||
if (!checkPresetClass(clazz)) {
|
||||
throw Error(`definition of preset "${name}" is invalid`);
|
||||
|
@ -1,123 +0,0 @@
|
||||
import { IPreset } from './defs';
|
||||
import { CONNECTION_CREATED, CONNECT_TO_REMOTE } from './actions';
|
||||
import { logger } from '../utils';
|
||||
|
||||
const TRACK_CHAR_UPLOAD = 'u';
|
||||
const TRACK_CHAR_DOWNLOAD = 'd';
|
||||
const TRACK_MAX_SIZE = 60;
|
||||
|
||||
/**
|
||||
* @description
|
||||
* Track data send/receive events via this preset, and print a part of them after connection closed.
|
||||
*
|
||||
* +---+-----------------------+---+
|
||||
* | C | d <--> u u <--> d | S |
|
||||
* +---+-----------------------+---+
|
||||
*
|
||||
* @examples
|
||||
* {"name": "tracker"}
|
||||
*/
|
||||
export default class TrackerPreset extends IPreset {
|
||||
|
||||
// ['source', 'target', 'u', '20', 'u', '20', 'd', '10', ...]
|
||||
_tracks = [];
|
||||
|
||||
_transport;
|
||||
|
||||
_sourceHost;
|
||||
_sourcePort;
|
||||
|
||||
_targetHost;
|
||||
_targetPort;
|
||||
|
||||
onNotified({ type, payload }) {
|
||||
switch (type) {
|
||||
case CONNECTION_CREATED: {
|
||||
const { host, port, transport } = payload;
|
||||
if (this._sourceHost !== host && this._sourceHost !== port) {
|
||||
this._transport = transport;
|
||||
this._sourceHost = host;
|
||||
this._sourcePort = port;
|
||||
this._tracks.push(`${host}:${port}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CONNECT_TO_REMOTE: {
|
||||
const { host, port } = payload;
|
||||
if (this._targetHost !== host && this._targetPort !== port) {
|
||||
this._targetHost = host;
|
||||
this._targetPort = port;
|
||||
this._tracks.push(`${host}:${port}`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
if (this._tracks !== null) {
|
||||
this.dump(this._tracks);
|
||||
}
|
||||
this._tracks = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* print connection track string, and only display the
|
||||
* leading and the trailing TRACK_MAX_SIZE / 2
|
||||
* @param tracks
|
||||
*/
|
||||
dump(tracks) {
|
||||
let strs = [];
|
||||
let dp = 0, db = 0;
|
||||
let up = 0, ub = 0;
|
||||
let ud = '';
|
||||
for (const el of tracks) {
|
||||
if (el === TRACK_CHAR_UPLOAD || el === TRACK_CHAR_DOWNLOAD) {
|
||||
if (ud === el) {
|
||||
continue;
|
||||
}
|
||||
ud = el;
|
||||
}
|
||||
if (Number.isInteger(el)) {
|
||||
if (ud === TRACK_CHAR_DOWNLOAD) {
|
||||
dp += 1;
|
||||
db += el;
|
||||
}
|
||||
if (ud === TRACK_CHAR_UPLOAD) {
|
||||
up += 1;
|
||||
ub += el;
|
||||
}
|
||||
}
|
||||
strs.push(el);
|
||||
}
|
||||
const perSize = Math.floor(TRACK_MAX_SIZE / 2);
|
||||
if (strs.length > TRACK_MAX_SIZE) {
|
||||
strs = strs.slice(0, perSize).concat([' ... ']).concat(strs.slice(-perSize));
|
||||
}
|
||||
const summary = this._config.is_client ? `out/in = ${up}/${dp}, ${ub}b/${db}b` : `in/out = ${dp}/${up}, ${db}b/${ub}b`;
|
||||
logger.info(`[tracker:${this._transport}] summary(${summary}) abstract(${strs.join(' ')})`);
|
||||
}
|
||||
|
||||
beforeOut({ buffer }) {
|
||||
this._tracks.push(TRACK_CHAR_UPLOAD);
|
||||
this._tracks.push(buffer.length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
beforeIn({ buffer }) {
|
||||
this._tracks.push(TRACK_CHAR_DOWNLOAD);
|
||||
this._tracks.push(buffer.length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
beforeOutUdp(...args) {
|
||||
return this.beforeOut(...args);
|
||||
}
|
||||
|
||||
beforeInUdp(...args) {
|
||||
return this.beforeIn(...args);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user