Comparing version 1.10.1 to 1.11.0
@@ -38,2 +38,3 @@ import * as DPapi from './dp-api'; | ||
* @param forceManualRelaying - determine relay nodes for requests/responses and enforce them for one hop messages, can not be used with zero hop | ||
* @param measureRPClatency - determine duration of actual RPC request from exit node, populates response stats | ||
*/ | ||
@@ -53,2 +54,3 @@ export type Ops = { | ||
readonly forceManualRelaying?: boolean; | ||
readonly measureRPClatency?: boolean; | ||
}; | ||
@@ -62,2 +64,3 @@ /** | ||
readonly provider?: string; | ||
readonly measureRPClatency?: boolean; | ||
}; | ||
@@ -115,2 +118,3 @@ /** | ||
private onVersions; | ||
private stats; | ||
} |
@@ -71,2 +71,3 @@ "use strict"; | ||
logLevel: 'info', | ||
measureRPClatency: false, | ||
}; | ||
@@ -119,3 +120,2 @@ const log = Utils.logger(['sdk']); | ||
const reqOps = this.requestOps(ops); | ||
// TODO fixme | ||
// eslint-disable-next-line no-async-promise-executor | ||
@@ -158,2 +158,3 @@ return new Promise(async (resolve, reject) => { | ||
counterOffset, | ||
measureRPClatency: reqOps.measureRPClatency, | ||
headers, | ||
@@ -200,3 +201,3 @@ hops: this.hops, | ||
this.sendSegment = (request, segment, entryNode, cacheEntry) => { | ||
const bef = Date.now(); | ||
const bef = performance.now(); | ||
const conn = { | ||
@@ -214,3 +215,5 @@ apiEndpoint: entryNode.apiEndpoint, | ||
.then((_json) => { | ||
const dur = Date.now() - bef; | ||
const aft = performance.now(); | ||
request.lastSegmentEndedAt = aft; | ||
const dur = Math.round(aft - bef); | ||
this.nodesColl.segmentSucceeded(request, segment, dur); | ||
@@ -255,2 +258,3 @@ }) | ||
counterOffset: fallback.counterOffset, | ||
measureRPClatency: origReq.measureRPClatency, | ||
headers: origReq.headers, | ||
@@ -288,3 +292,3 @@ hops: origReq.hops, | ||
this.resendSegment = (segment, request, entryNode, cacheEntry) => { | ||
const bef = Date.now(); | ||
const bef = performance.now(); | ||
NodeAPI.sendMessage({ | ||
@@ -301,3 +305,5 @@ apiEndpoint: entryNode.apiEndpoint, | ||
.then((_json) => { | ||
const dur = Date.now() - bef; | ||
const aft = performance.now(); | ||
request.lastSegmentEndedAt = aft; | ||
const dur = Math.round(aft - bef); | ||
this.nodesColl.segmentSucceeded(request, segment, dur); | ||
@@ -374,12 +380,18 @@ }) | ||
const { request, reject, resolve } = reqEntry; | ||
const responseTime = Date.now() - request.createdAt; | ||
log.verbose('response time for request %s: %s ms', request.id, responseTime); | ||
const responseTime = Math.round(performance.now() - request.startedAt); | ||
const stats = this.stats(responseTime, request, resp); | ||
log.verbose('response time for request %s: %d ms %o', request.id, responseTime, stats); | ||
this.nodesColl.requestSucceeded(request, responseTime); | ||
switch (resp.type) { | ||
case Payload.RespType.Resp: | ||
return resolve({ | ||
case Payload.RespType.Resp: { | ||
const r = { | ||
status: 200, | ||
text: () => new Promise((r) => r(JSON.stringify(resp.resp))), | ||
json: () => Promise.resolve(resp.resp), | ||
}); | ||
}; | ||
if (request.measureRPClatency) { | ||
r.stats = stats; | ||
} | ||
return resolve(r); | ||
} | ||
case Payload.RespType.CounterFail: { | ||
@@ -391,8 +403,13 @@ const counter = reqEntry.session.updatedTS; | ||
return reject('Message duplicate error. Exit node rejected already processed message'); | ||
case Payload.RespType.HttpError: | ||
return resolve({ | ||
case Payload.RespType.HttpError: { | ||
const r = { | ||
status: resp.status, | ||
text: () => Promise.resolve(resp.text), | ||
json: () => new Promise((r) => r(JSON.parse(resp.text))), | ||
}); | ||
}; | ||
if (request.measureRPClatency) { | ||
r.stats = stats; | ||
} | ||
return resolve(r); | ||
} | ||
case Payload.RespType.Error: | ||
@@ -416,2 +433,3 @@ return reject(`Error attempting JSON RPC call: ${resp.reason}`); | ||
: ops.forceManualRelaying ?? defaultOps.forceManualRelaying; | ||
const measureRPClatency = ops.measureRPClatency ?? defaultOps.measureRPClatency; | ||
return { | ||
@@ -430,2 +448,3 @@ discoveryPlatformEndpoint, | ||
forceManualRelaying, | ||
measureRPClatency, | ||
}; | ||
@@ -438,2 +457,3 @@ }; | ||
provider: ops.provider || this.ops.provider, | ||
measureRPClatency: ops.measureRPClatency ?? this.ops.measureRPClatency, | ||
}; | ||
@@ -545,2 +565,21 @@ } | ||
}; | ||
this.stats = (responseTime, request, resp) => { | ||
const segDur = Math.round(request.lastSegmentEndedAt - request.startedAt); | ||
if (request.measureRPClatency && | ||
'rDur' in resp && | ||
'eDur' in resp && | ||
resp.rDur && | ||
resp.eDur) { | ||
const rpcDur = resp.rDur; | ||
const exitNodeDur = resp.eDur; | ||
const hoprDur = responseTime - rpcDur - exitNodeDur - segDur; | ||
return { | ||
segDur, | ||
rpcDur, | ||
exitNodeDur, | ||
hoprDur, | ||
}; | ||
} | ||
return { segDur }; | ||
}; | ||
this.ops = this.sdkOps(ops); | ||
@@ -547,0 +586,0 @@ (this.ops.debugScope || this.ops.logLevel) && |
@@ -39,3 +39,3 @@ "use strict"; | ||
const InfoResponseTimeout = 10e3; // 10s | ||
const RelayNodesCompatVersions = ['2.0.6']; | ||
const RelayNodesCompatVersions = ['2.0.6', '2.0.7']; | ||
function create(entryNode, exitNodes, applicationTag, messageListener, hops, forceManualRelaying) { | ||
@@ -147,7 +147,7 @@ const entryData = EntryData.create(); | ||
function discover(np) { | ||
const startPingTime = Date.now(); | ||
const startPingTime = performance.now(); | ||
if (np.hops === 0 || !np.forceManualRelaying) { | ||
NodeAPI.version(np.entryNode) | ||
.then(() => { | ||
np.entryData.pingDuration = Date.now() - startPingTime; | ||
np.entryData.pingDuration = Math.round(performance.now() - startPingTime); | ||
np.log.verbose('version ping took %dms', np.entryData.pingDuration); | ||
@@ -177,3 +177,3 @@ }) | ||
} | ||
exitData.infoLatStarted = Date.now(); | ||
exitData.infoLatStarted = performance.now(); | ||
NodeAPI.sendMessage({ | ||
@@ -254,6 +254,6 @@ ...np.entryNode, | ||
function fetchMessages(np) { | ||
const bef = Date.now(); | ||
const bef = performance.now(); | ||
NodeAPI.retrieveMessages(np.entryNode, np.applicationTag) | ||
.then(({ messages }) => { | ||
const lat = Date.now() - bef; | ||
const lat = Math.round(performance.now() - bef); | ||
np.entryData.fetchMessagesSuccesses++; | ||
@@ -307,3 +307,4 @@ np.entryData.fetchMessagesLatencies.push(lat); | ||
exitData.counterOffset = Date.now() - counter; | ||
exitData.infoLatMs = exitData.infoLatStarted && Date.now() - exitData.infoLatStarted; | ||
exitData.infoLatMs = | ||
exitData.infoLatStarted && Math.round(performance.now() - exitData.infoLatStarted); | ||
exitData.infoFail = false; | ||
@@ -336,3 +337,3 @@ exitData.shRelays = shRelays; | ||
function incChannels(np, channels, peers, startPingTime) { | ||
np.entryData.pingDuration = Date.now() - startPingTime; | ||
np.entryData.pingDuration = Math.round(performance.now() - startPingTime); | ||
np.log.verbose('channel ping took %dms', np.entryData.pingDuration); | ||
@@ -339,0 +340,0 @@ // open channels |
@@ -58,5 +58,5 @@ "use strict"; | ||
return new Promise((resolve, reject) => { | ||
const start = Date.now(); | ||
const start = performance.now(); | ||
const check = () => { | ||
const now = Date.now(); | ||
const now = performance.now(); | ||
const elapsed = now - start; | ||
@@ -82,5 +82,5 @@ const res = NodeSel.routePair(this.nodePairs, this.forceManualRelaying); | ||
return new Promise((resolve, reject) => { | ||
const start = Date.now(); | ||
const start = performance.now(); | ||
const check = () => { | ||
const now = Date.now(); | ||
const now = performance.now(); | ||
const elapsed = now - start; | ||
@@ -271,3 +271,3 @@ const res = NodeSel.routePair(this.nodePairs, this.forceManualRelaying); | ||
}, []); | ||
log.verbose('removing %d routes: %s', removablePairs.length, removablePairs); | ||
log.verbose('removing %d redundant routes', removablePairs.length); | ||
while (removablePairs.length > 0 && toRemove > 0) { | ||
@@ -274,0 +274,0 @@ const idx = Utils.randomIdx(removablePairs); |
@@ -10,2 +10,3 @@ import * as JRPC from './jrpc'; | ||
relayPeerId?: string; | ||
wDur?: boolean; | ||
}; | ||
@@ -22,2 +23,4 @@ export declare enum RespType { | ||
resp: JRPC.Response; | ||
rDur?: number; | ||
eDur?: number; | ||
} | { | ||
@@ -32,2 +35,4 @@ type: RespType.CounterFail; | ||
text: string; | ||
rDur?: number; | ||
eDur?: number; | ||
} | { | ||
@@ -34,0 +39,0 @@ type: RespType.Error; |
@@ -7,3 +7,2 @@ export declare enum State { | ||
export type PerfData = { | ||
startedAt: number; | ||
latency?: number; | ||
@@ -13,3 +12,2 @@ state: State; | ||
export declare function ongoing(): { | ||
startedAt: number; | ||
state: State; | ||
@@ -16,0 +14,0 @@ }; |
@@ -12,3 +12,2 @@ "use strict"; | ||
return { | ||
startedAt: Date.now(), | ||
state: State.Ongoing, | ||
@@ -15,0 +14,0 @@ }; |
@@ -11,5 +11,7 @@ import * as compatCrypto from '@rpch/compat-crypto'; | ||
req: JRPC.Request; | ||
createdAt: number; | ||
entryPeerId: string; | ||
exitPeerId: string; | ||
startedAt: number; | ||
measureRPClatency: boolean; | ||
lastSegmentEndedAt?: number; | ||
headers?: Record<string, string>; | ||
@@ -27,3 +29,3 @@ hops?: number; | ||
*/ | ||
export declare function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, headers, hops, reqRelayPeerId, respRelayPeerId, }: { | ||
export declare function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, measureRPClatency, headers, hops, reqRelayPeerId, respRelayPeerId, }: { | ||
id: string; | ||
@@ -38,2 +40,3 @@ originalId?: string; | ||
counterOffset: number; | ||
measureRPClatency: boolean; | ||
headers?: Record<string, string>; | ||
@@ -40,0 +43,0 @@ hops?: number; |
@@ -36,4 +36,4 @@ "use strict"; | ||
*/ | ||
function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, headers, hops, reqRelayPeerId, respRelayPeerId, }) { | ||
const resEncode = Payload.encodeReq({ | ||
function create({ id, originalId, provider, req, clientId, entryPeerId, exitPeerId, exitPublicKey, counterOffset, measureRPClatency, headers, hops, reqRelayPeerId, respRelayPeerId, }) { | ||
const payload = { | ||
provider, | ||
@@ -45,3 +45,7 @@ clientId, | ||
relayPeerId: respRelayPeerId, | ||
}); | ||
}; | ||
if (measureRPClatency) { | ||
payload.wDur = true; | ||
} | ||
const resEncode = Payload.encodeReq(payload); | ||
if (Res.isErr(resEncode)) { | ||
@@ -67,3 +71,2 @@ return resEncode; | ||
req, | ||
createdAt: Date.now(), | ||
entryPeerId, | ||
@@ -74,4 +77,6 @@ exitPeerId, | ||
hops, | ||
measureRPClatency, | ||
reqRelayPeerId, | ||
respRelayPeerId, | ||
startedAt: performance.now(), | ||
}, | ||
@@ -78,0 +83,0 @@ session: resBox.session, |
@@ -6,4 +6,20 @@ import * as compatCrypto from '@rpch/compat-crypto'; | ||
import type { Request } from './request'; | ||
/** | ||
* Stats alongside Response. | ||
* segDur - duration of first segment http call started until last segment http call finished. | ||
* rpcDur - duration of RPC request from exit node | ||
* exitNodeDur - approximate execution duration up to encrypting and compressing response itself | ||
* hoprDur - estimated duration of segments during request - response cycle inside hopr network | ||
*/ | ||
export type Stats = { | ||
segDur: number; | ||
rpcDur: number; | ||
exitNodeDur: number; | ||
hoprDur: number; | ||
} | { | ||
segDur: number; | ||
}; | ||
export type Response = { | ||
status: number; | ||
stats?: Stats; | ||
text: () => Promise<string>; | ||
@@ -10,0 +26,0 @@ json: () => Promise<JRPC.Response>; |
@@ -1,2 +0,2 @@ | ||
declare const _default: "1.10.1"; | ||
declare const _default: "1.11.0"; | ||
export default _default; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = '1.10.1'; | ||
exports.default = '1.11.0'; |
# @rpch/sdk | ||
## 1.11.0 | ||
### Minor Changes | ||
- bee0cff: Allow requesting latency tracking from exit node | ||
Fix time measurements throughout the sdk making them clock independent | ||
## 1.10.1 | ||
@@ -4,0 +11,0 @@ |
{ | ||
"name": "@rpch/sdk", | ||
"version": "1.10.1", | ||
"version": "1.11.0", | ||
"license": "LGPL-3.0", | ||
@@ -5,0 +5,0 @@ "main": "./build/index.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
143530
3501