This repository was archived by the owner on Dec 10, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathflowcontrol.ts
109 lines (100 loc) · 3.19 KB
/
flowcontrol.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import { Peer } from '../peer/peer'
import { BoundProtocol } from './boundprotocol'
interface Mrc {
[key: string]: {
base: number
req: number
}
}
interface FlowParams {
bv?: number
ble?: number
last?: number
}
export interface FlowControlOptions {
bl?: number
mrc?: Mrc
mrr?: number
}
/**
* LES flow control manager
* @memberof module:net/protocol
*/
export class FlowControl {
readonly bl: number
readonly mrc: Mrc
readonly mrr: number
readonly out: Map<string, FlowParams>;
readonly in: Map<string, FlowParams>
constructor(options?: FlowControlOptions) {
this.bl = options?.bl ?? 300000000
this.mrc = options?.mrc ?? {
GetBlockHeaders: { base: 1000, req: 1000 },
}
this.mrr = options?.mrr ?? 10000
this.out = new Map()
this.in = new Map()
}
/**
* Process reply message from an LES peer by updating its BLE value
* @param {Peer} peer LES peer
* @param {number} bv latest buffer value
*/
handleReply(peer: Peer, bv: number) {
const params = this.in.get(peer.id) ?? {}
params.ble = bv
params.last = Date.now()
this.in.set(peer.id, params)
}
/**
* Calculate maximum items that can be requested from an LES peer
* @param {Peer} peer LES peer
* @param messageName message name
* @return maximum count
*/
maxRequestCount(peer: Peer, messageName: string): number {
const now = Date.now()
const mrcBase = (peer.les as BoundProtocol).status.mrc[messageName].base
const mrcReq = (peer.les as BoundProtocol).status.mrc[messageName].req
const mrr = (peer.les as BoundProtocol).status.mrr
const bl = (peer.les as BoundProtocol).status.bl
const params = this.in.get(peer.id) ?? ({ ble: bl } as FlowParams)
if (params.last) {
// recharge BLE at rate of MRR when less than BL
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
params.ble = Math.min(params.ble! + mrr * (now - params.last), bl)
}
params.last = now
this.in.set(peer.id, params)
// calculate how many messages we can request from peer
return Math.max(Math.floor((params.ble! - mrcBase) / mrcReq), 0)
}
/**
* Calculate new buffer value for an LES peer after an incoming request is
* processed. If the new value is negative, the peer should be dropped by the
* caller.
* @param {Peer} peer LES peer
* @param messageName message name
* @param count number of items to request from peer
* @return new buffer value after request is sent (if negative, drop peer)
*/
handleRequest(peer: Peer, messageName: string, count: number): number {
const now = Date.now()
const params = this.out.get(peer.id) ?? {}
if (params.bv && params.last) {
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
params.bv = Math.min(params.bv + this.mrr * (now - params.last), this.bl)
} else {
params.bv = this.bl
}
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
params.bv -= this.mrc[messageName].base + this.mrc[messageName].req * count
params.last = now
if (params.bv < 0) {
this.out.delete(peer.id)
} else {
this.out.set(peer.id, params)
}
return params.bv
}
}