@yuants/protocol
Advanced tools
Comparing version
@@ -162,2 +162,26 @@ /** | ||
/** | ||
* Request to copy data records to receiver terminal. | ||
* | ||
* Response when all data records arrived the target. | ||
* | ||
* 1. The source terminal asks the target terminal to copy data records to the receiver terminal. | ||
* 2. The target terminal push data records to the receiver terminal. | ||
* the receiver terminal MUST implement `UpdateDataRecords`. | ||
* the target terminal serially micro-batching calls `UpdateDataRecords` to the receiver terminal. | ||
* 3. After all data records arrived the receiver terminal, the target terminal responses to the source terminal. | ||
* | ||
* E1. the target terminal SHOULD response error if any error occurred during the process. | ||
* | ||
* Recommended if the source terminal does not care about the content of data records. | ||
* | ||
* @public | ||
*/ | ||
declare interface ICopyDataRecordsRequest extends IQueryDataRecordsRequest { | ||
/** | ||
* the receiver terminal that will receive `UpdateDataRecords` messages. | ||
*/ | ||
receiver_terminal_id: string; | ||
} | ||
/** | ||
* Data Record | ||
@@ -1493,2 +1517,3 @@ * 数据记录 | ||
feed: (channel_id: string, data: any, target_terminal_id: string) => void; | ||
copyDataRecords: (req: ICopyDataRecordsRequest, target_terminal_id: string) => Observable<undefined>; | ||
queryDataRecords: <T>(req: IQueryDataRecordsRequest, target_terminal_id: string) => Observable<IDataRecord<T>>; | ||
@@ -1495,0 +1520,0 @@ updateDataRecords: (records: IDataRecord<any>[], target_terminal_id: string) => Observable<never>; |
import { batchGroupBy, rateLimitMap, switchMapWithComplete } from '@yuants/utils'; | ||
import { isNode } from 'browser-or-node'; | ||
import { EMPTY, Subject, bufferCount, catchError, concatMap, concatWith, defer, delayWhen, distinct, distinctUntilChanged, filter, first, from, groupBy, map, mergeAll, mergeMap, of, pairwise, repeat, retry, share, shareReplay, takeWhile, tap, timeout, timer, toArray, } from 'rxjs'; | ||
import { EMPTY, Subject, bufferCount, catchError, concatMap, concatWith, defer, delayWhen, distinct, distinctUntilChanged, filter, first, from, groupBy, interval, map, mergeAll, mergeMap, of, pairwise, repeat, retry, share, shareReplay, takeWhile, tap, timeout, timer, toArray, } from 'rxjs'; | ||
import { v4 } from 'uuid'; | ||
@@ -26,2 +26,3 @@ import { createConnectionJson } from './create-connection'; | ||
const FrameTransmittedTotal = PromRegistry.create('counter', 'terminal_frame_transmitted_total', 'terminal_frame_transmitted_total Terminal frame transmitted'); | ||
const MetricSubmitOrderCount = PromRegistry.create('counter', 'account_submit_order_count'); | ||
/** | ||
@@ -101,8 +102,59 @@ * Terminal | ||
} | ||
return group.pipe(tap((msg) => { | ||
const preHandleAction$ = new Subject(); | ||
const postHandleAction$ = new Subject(); | ||
// ISSUE: Keepalive for every queued request before they are handled, | ||
preHandleAction$.subscribe(({ req }) => { | ||
const sub = interval(5000).subscribe(() => { | ||
this._conn.output$.next({ | ||
trace_id: req.trace_id, | ||
method: req.method, | ||
// ISSUE: Reverse source / target as response, otherwise the host cannot guarantee the forwarding direction | ||
source_terminal_id: this.terminalInfo.terminal_id, | ||
target_terminal_id: req.source_terminal_id, | ||
}); | ||
}); | ||
postHandleAction$ | ||
.pipe( | ||
// | ||
first(({ req: req1 }) => req1 === req)) | ||
.subscribe(() => { | ||
sub.unsubscribe(); | ||
}); | ||
}); | ||
// Metrics | ||
preHandleAction$.subscribe(({ req }) => { | ||
const tsStart = Date.now(); | ||
RequestReceivedTotal.inc({ | ||
method: msg.method, | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
}); | ||
postHandleAction$.pipe(first(({ req: req1 }) => req1 === req)).subscribe(({ req, res }) => { | ||
var _a, _b, _c, _d; | ||
const labels = { | ||
server_id: this.terminalInfo.terminal_id, | ||
method: res.method, | ||
code: `${res.frame !== undefined ? 0 : (_b = (_a = res.res) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : 520}`, | ||
}; | ||
MetricWsRequestTotal.inc(labels); | ||
MetricWsRequestDurationBucket.observe(Date.now() - tsStart, labels); | ||
if (res.res !== undefined) { | ||
ResponseTransmittedTotal.inc({ | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
code: `${res.frame !== undefined ? 0 : (_d = (_c = res.res) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : 520}`, | ||
}); | ||
} | ||
if (res.frame !== undefined) { | ||
FrameTransmittedTotal.inc({ | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
}); | ||
} | ||
}); | ||
}); | ||
return group.pipe(tap((msg) => { | ||
preHandleAction$.next({ req: msg }); | ||
}), groupBy((msg) => msg.source_terminal_id), | ||
@@ -121,5 +173,4 @@ // Token Bucket Algorithm | ||
}, this._serviceRateLimit[subGroup.key]))), mergeMap((msg) => { | ||
const tsStart = Date.now(); | ||
const output$ = new Subject(); | ||
const res$ = msg.res ? of(msg) : handler(msg, output$); | ||
const res$ = msg.res ? of(msg) : defer(() => handler(msg, output$)); | ||
// ISSUE: output$.pipe(...) must be returned first to ensure that mergeMap has been subscribed before res$ starts write into output$ | ||
@@ -145,25 +196,4 @@ setTimeout(() => { | ||
// ISSUE: Reverse source / target as response, otherwise the host cannot guarantee the forwarding direction | ||
source_terminal_id: this.terminalInfo.terminal_id, target_terminal_id: msg.source_terminal_id }))), tap((resp) => { | ||
var _a, _b, _c, _d; | ||
const labels = { | ||
server_id: this.terminalInfo.terminal_id, | ||
method: resp.method, | ||
code: `${resp.frame !== undefined ? 0 : (_b = (_a = resp.res) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : 520}`, | ||
}; | ||
MetricWsRequestTotal.inc(labels); | ||
MetricWsRequestDurationBucket.observe(Date.now() - tsStart, labels); | ||
if (resp.res !== undefined) { | ||
ResponseTransmittedTotal.inc({ | ||
method: msg.method, | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
code: `${resp.frame !== undefined ? 0 : (_d = (_c = resp.res) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : 520}`, | ||
}); | ||
} | ||
if (resp.frame !== undefined) { | ||
FrameTransmittedTotal.inc({ | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
}); | ||
} | ||
source_terminal_id: this.terminalInfo.terminal_id, target_terminal_id: msg.source_terminal_id }))), tap((res) => { | ||
postHandleAction$.next({ req: msg, res }); | ||
})); | ||
@@ -197,3 +227,2 @@ }, concurrency)); | ||
this.setupPredefinedMiddleware = () => { | ||
const MetricSubmitOrderCount = PromRegistry.create('counter', 'account_submit_order_count'); | ||
this._conn.input$ | ||
@@ -321,2 +350,12 @@ .pipe( | ||
}; | ||
this.copyDataRecords = (req, target_terminal_id) => this.request('CopyDataRecords', target_terminal_id, req).pipe(mergeMap((msg) => { | ||
if (msg.res) { | ||
if (msg.res.code !== 0) { | ||
throw Error(`ServerError: ${msg.res.code}: ${msg.res.message}`); | ||
} | ||
// emit an signal to indicate that the copy is complete | ||
return of(void 0); | ||
} | ||
return EMPTY; | ||
})); | ||
this.queryDataRecords = (req, target_terminal_id) => this.request('QueryDataRecords', target_terminal_id, req).pipe(mergeMap((msg) => { | ||
@@ -323,0 +362,0 @@ if (msg.frame) { |
@@ -5,3 +5,3 @@ import { Observable, Subject } from 'rxjs'; | ||
import { IService, ITerminalMessage } from './services'; | ||
import { IQueryDataRecordsRequest, IRemoveDataRecordsRequest } from './services/data-record'; | ||
import { ICopyDataRecordsRequest, IQueryDataRecordsRequest, IRemoveDataRecordsRequest } from './services/data-record'; | ||
import { IQueryHistoryOrdersRequest, IQueryPeriodsRequest, IQueryProductsRequest } from './services/pull'; | ||
@@ -74,2 +74,3 @@ declare type IServiceHandler<T extends string = string> = T extends keyof IService ? (msg: ITerminalMessage & Pick<IService[T], 'req'> & { | ||
feed: (channel_id: string, data: any, target_terminal_id: string) => void; | ||
copyDataRecords: (req: ICopyDataRecordsRequest, target_terminal_id: string) => Observable<undefined>; | ||
queryDataRecords: <T>(req: IQueryDataRecordsRequest, target_terminal_id: string) => Observable<IDataRecord<T>>; | ||
@@ -76,0 +77,0 @@ updateDataRecords: (records: IDataRecord<any>[], target_terminal_id: string) => Observable<never>; |
@@ -29,2 +29,3 @@ "use strict"; | ||
const FrameTransmittedTotal = metrics_1.PromRegistry.create('counter', 'terminal_frame_transmitted_total', 'terminal_frame_transmitted_total Terminal frame transmitted'); | ||
const MetricSubmitOrderCount = metrics_1.PromRegistry.create('counter', 'account_submit_order_count'); | ||
/** | ||
@@ -104,8 +105,59 @@ * Terminal | ||
} | ||
return group.pipe((0, rxjs_1.tap)((msg) => { | ||
const preHandleAction$ = new rxjs_1.Subject(); | ||
const postHandleAction$ = new rxjs_1.Subject(); | ||
// ISSUE: Keepalive for every queued request before they are handled, | ||
preHandleAction$.subscribe(({ req }) => { | ||
const sub = (0, rxjs_1.interval)(5000).subscribe(() => { | ||
this._conn.output$.next({ | ||
trace_id: req.trace_id, | ||
method: req.method, | ||
// ISSUE: Reverse source / target as response, otherwise the host cannot guarantee the forwarding direction | ||
source_terminal_id: this.terminalInfo.terminal_id, | ||
target_terminal_id: req.source_terminal_id, | ||
}); | ||
}); | ||
postHandleAction$ | ||
.pipe( | ||
// | ||
(0, rxjs_1.first)(({ req: req1 }) => req1 === req)) | ||
.subscribe(() => { | ||
sub.unsubscribe(); | ||
}); | ||
}); | ||
// Metrics | ||
preHandleAction$.subscribe(({ req }) => { | ||
const tsStart = Date.now(); | ||
RequestReceivedTotal.inc({ | ||
method: msg.method, | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
}); | ||
postHandleAction$.pipe((0, rxjs_1.first)(({ req: req1 }) => req1 === req)).subscribe(({ req, res }) => { | ||
var _a, _b, _c, _d; | ||
const labels = { | ||
server_id: this.terminalInfo.terminal_id, | ||
method: res.method, | ||
code: `${res.frame !== undefined ? 0 : (_b = (_a = res.res) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : 520}`, | ||
}; | ||
MetricWsRequestTotal.inc(labels); | ||
MetricWsRequestDurationBucket.observe(Date.now() - tsStart, labels); | ||
if (res.res !== undefined) { | ||
ResponseTransmittedTotal.inc({ | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
code: `${res.frame !== undefined ? 0 : (_d = (_c = res.res) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : 520}`, | ||
}); | ||
} | ||
if (res.frame !== undefined) { | ||
FrameTransmittedTotal.inc({ | ||
method: req.method, | ||
source_terminal_id: req.source_terminal_id, | ||
target_terminal_id: req.target_terminal_id, | ||
}); | ||
} | ||
}); | ||
}); | ||
return group.pipe((0, rxjs_1.tap)((msg) => { | ||
preHandleAction$.next({ req: msg }); | ||
}), (0, rxjs_1.groupBy)((msg) => msg.source_terminal_id), | ||
@@ -124,5 +176,4 @@ // Token Bucket Algorithm | ||
}, this._serviceRateLimit[subGroup.key]))), (0, rxjs_1.mergeMap)((msg) => { | ||
const tsStart = Date.now(); | ||
const output$ = new rxjs_1.Subject(); | ||
const res$ = msg.res ? (0, rxjs_1.of)(msg) : handler(msg, output$); | ||
const res$ = msg.res ? (0, rxjs_1.of)(msg) : (0, rxjs_1.defer)(() => handler(msg, output$)); | ||
// ISSUE: output$.pipe(...) must be returned first to ensure that mergeMap has been subscribed before res$ starts write into output$ | ||
@@ -148,25 +199,4 @@ setTimeout(() => { | ||
// ISSUE: Reverse source / target as response, otherwise the host cannot guarantee the forwarding direction | ||
source_terminal_id: this.terminalInfo.terminal_id, target_terminal_id: msg.source_terminal_id }))), (0, rxjs_1.tap)((resp) => { | ||
var _a, _b, _c, _d; | ||
const labels = { | ||
server_id: this.terminalInfo.terminal_id, | ||
method: resp.method, | ||
code: `${resp.frame !== undefined ? 0 : (_b = (_a = resp.res) === null || _a === void 0 ? void 0 : _a.code) !== null && _b !== void 0 ? _b : 520}`, | ||
}; | ||
MetricWsRequestTotal.inc(labels); | ||
MetricWsRequestDurationBucket.observe(Date.now() - tsStart, labels); | ||
if (resp.res !== undefined) { | ||
ResponseTransmittedTotal.inc({ | ||
method: msg.method, | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
code: `${resp.frame !== undefined ? 0 : (_d = (_c = resp.res) === null || _c === void 0 ? void 0 : _c.code) !== null && _d !== void 0 ? _d : 520}`, | ||
}); | ||
} | ||
if (resp.frame !== undefined) { | ||
FrameTransmittedTotal.inc({ | ||
source_terminal_id: msg.source_terminal_id, | ||
target_terminal_id: msg.target_terminal_id, | ||
}); | ||
} | ||
source_terminal_id: this.terminalInfo.terminal_id, target_terminal_id: msg.source_terminal_id }))), (0, rxjs_1.tap)((res) => { | ||
postHandleAction$.next({ req: msg, res }); | ||
})); | ||
@@ -200,3 +230,2 @@ }, concurrency)); | ||
this.setupPredefinedMiddleware = () => { | ||
const MetricSubmitOrderCount = metrics_1.PromRegistry.create('counter', 'account_submit_order_count'); | ||
this._conn.input$ | ||
@@ -324,2 +353,12 @@ .pipe( | ||
}; | ||
this.copyDataRecords = (req, target_terminal_id) => this.request('CopyDataRecords', target_terminal_id, req).pipe((0, rxjs_1.mergeMap)((msg) => { | ||
if (msg.res) { | ||
if (msg.res.code !== 0) { | ||
throw Error(`ServerError: ${msg.res.code}: ${msg.res.message}`); | ||
} | ||
// emit an signal to indicate that the copy is complete | ||
return (0, rxjs_1.of)(void 0); | ||
} | ||
return rxjs_1.EMPTY; | ||
})); | ||
this.queryDataRecords = (req, target_terminal_id) => this.request('QueryDataRecords', target_terminal_id, req).pipe((0, rxjs_1.mergeMap)((msg) => { | ||
@@ -326,0 +365,0 @@ if (msg.frame) { |
{ | ||
"name": "@yuants/protocol", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"main": "lib/index.js", | ||
@@ -5,0 +5,0 @@ "module": "dist/index.js", |
{ | ||
"libraries/protocol/CHANGELOG.json": "8df586f82f2d3d3b7b9292acd9d5f8cda5fa7218", | ||
"libraries/protocol/CHANGELOG.md": "7373c789bdf112f6ea85d0d4dc5043728731f952", | ||
"libraries/protocol/CHANGELOG.json": "cd9e5dd829c2c878b3b44d920c5f0d6d2d250034", | ||
"libraries/protocol/CHANGELOG.md": "a0056d29d4a2a0e226ad26aa399d5d51d85a25d6", | ||
"libraries/protocol/api-extractor.json": "62f4fd324425b9a235f0c117975967aab09ced0c", | ||
@@ -8,4 +8,4 @@ "libraries/protocol/config/jest.config.json": "4bb17bde3ee911163a3edb36a6eb71491d80b1bd", | ||
"libraries/protocol/config/typescript.json": "854907e8a821f2050f6533368db160c649c25348", | ||
"libraries/protocol/etc/protocol.api.md": "2e77d7558c0ce8717e2c6e1edfbb3b8360c9cef3", | ||
"libraries/protocol/package.json": "ccc18b8101c62e2e1cac69fc5af533150a9187a3", | ||
"libraries/protocol/etc/protocol.api.md": "ae5fa06dd3f9005237ee8caf3ee296910c2034df", | ||
"libraries/protocol/package.json": "d6846064b752c86a939251fff945a2820d4483c6", | ||
"libraries/protocol/src/create-connection.ts": "61e4df11402da2785fb5a9ed024b381e69047ba2", | ||
@@ -25,3 +25,4 @@ "libraries/protocol/src/index.ts": "3d8a31fc7c1416d5b7040fd4365802c33640a143", | ||
"libraries/protocol/src/services/subscription.ts": "11557b8ec69c281676905b31ea6214e854c7d476", | ||
"libraries/protocol/src/terminal.ts": "319af428ed49412b5bc6411aa49ba386797a7b08", | ||
"libraries/protocol/src/terminal.test.ts": "d438966d1f1c0636dfcbfa8deb4131240faf3112", | ||
"libraries/protocol/src/terminal.ts": "335be6a681b4f99a506e324b7856cb12be5a526b", | ||
"libraries/protocol/src/utils/account-info.ts": "6649d81925bf3cbc92fa44a0a33391727f027c38", | ||
@@ -28,0 +29,0 @@ "libraries/protocol/src/utils/index.ts": "fb0d1c7ff9a05bb2fedbfcc1050101fc6f18cb80", |
@@ -361,2 +361,6 @@ ## API Report File for "@yuants/protocol" | ||
_conn: IConnection<ITerminalMessage>; | ||
// Warning: (ae-forgotten-export) The symbol "ICopyDataRecordsRequest" needs to be exported by the entry point index.d.ts | ||
// | ||
// (undocumented) | ||
copyDataRecords: (req: ICopyDataRecordsRequest, target_terminal_id: string) => Observable<undefined>; | ||
datasourceIds$: Observable<string[]>; | ||
@@ -363,0 +367,0 @@ feed: (channel_id: string, data: any, target_terminal_id: string) => void; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
891042
2.47%114
5.56%14062
1.55%3
200%