@peerbit/stream 3.0.10 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,262 @@
1
+ import defer from "p-defer";
2
+ import GenericFIFO from "fast-fifo";
3
+ export class AbortError extends Error {
4
+ type;
5
+ code;
6
+ constructor(message, code) {
7
+ super(message ?? "The operation was aborted");
8
+ this.type = "aborted";
9
+ this.code = code ?? "ABORT_ERR";
10
+ }
11
+ }
12
+ /**
13
+ * Fifo but with total readableLength counter
14
+ */
15
+ class Uint8ArrayFifo extends GenericFIFO {
16
+ size = 0;
17
+ push(val) {
18
+ if (val.value) {
19
+ this.size += val.value.byteLength;
20
+ }
21
+ return super.push(val);
22
+ }
23
+ shift() {
24
+ const shifted = super.shift();
25
+ if (shifted?.value) {
26
+ this.size -= shifted.value.byteLength;
27
+ }
28
+ return shifted;
29
+ }
30
+ }
31
+ /**
32
+ * A queue consisting of multiple 'lanes' with different priority to be emptied.
33
+ * The lane with index 0 will empty before lane with index 1 etc..
34
+ * TODO add an additional proprty to control whether we we pick objects from slower lanes
35
+ * so no lane get really "stuck"
36
+ */
37
+ class Uint8arrayPriorityQueue {
38
+ lanes;
39
+ constructor(options = { lanes: 1 }) {
40
+ this.lanes = new Array(options.lanes);
41
+ for (let i = 0; i < this.lanes.length; i++) {
42
+ this.lanes[i] = new Uint8ArrayFifo();
43
+ }
44
+ }
45
+ get size() {
46
+ let sum = 0;
47
+ for (const lane of this.lanes) {
48
+ sum += lane.size;
49
+ }
50
+ return sum;
51
+ }
52
+ push(val, lane) {
53
+ return this.lanes[lane].push(val);
54
+ }
55
+ shift() {
56
+ // fetch the first non undefined item.
57
+ // by iterating from index 0 up we define that lanes with lower index have higher prioirity
58
+ for (const lane of this.lanes) {
59
+ const element = lane.shift();
60
+ if (element) {
61
+ return element;
62
+ }
63
+ }
64
+ return undefined;
65
+ }
66
+ isEmpty() {
67
+ for (const lane of this.lanes) {
68
+ if (!lane.isEmpty()) {
69
+ return false;
70
+ }
71
+ }
72
+ return true;
73
+ }
74
+ }
75
+ export function pushableLanes(options = {}) {
76
+ return _pushable(options);
77
+ }
78
+ // Modified from https://github.com/alanshaw/it-pushable
79
+ function _pushable(options) {
80
+ options = options ?? {};
81
+ let onEnd = options.onEnd;
82
+ let buffer = new Uint8arrayPriorityQueue(options.lanes ? { lanes: options.lanes } : undefined);
83
+ let pushable;
84
+ let onNext;
85
+ let ended;
86
+ let drain = defer();
87
+ const getNext = () => {
88
+ const next = buffer.shift();
89
+ if (next == null) {
90
+ return { done: true };
91
+ }
92
+ if (next.error != null) {
93
+ throw next.error;
94
+ }
95
+ return {
96
+ done: next.done === true,
97
+ // @ts-expect-error if done is false, value will be present
98
+ value: next.value
99
+ };
100
+ };
101
+ const waitNext = async () => {
102
+ try {
103
+ if (!buffer.isEmpty()) {
104
+ return getNext();
105
+ }
106
+ if (ended) {
107
+ return { done: true };
108
+ }
109
+ return await new Promise((resolve, reject) => {
110
+ onNext = (next, lane) => {
111
+ onNext = null;
112
+ buffer.push(next, lane);
113
+ try {
114
+ resolve(getNext());
115
+ }
116
+ catch (err) {
117
+ reject(err);
118
+ }
119
+ return pushable;
120
+ };
121
+ });
122
+ }
123
+ finally {
124
+ if (buffer.isEmpty()) {
125
+ // settle promise in the microtask queue to give consumers a chance to
126
+ // await after calling .push
127
+ queueMicrotask(() => {
128
+ drain.resolve();
129
+ drain = defer();
130
+ });
131
+ }
132
+ }
133
+ };
134
+ const bufferNext = (next, lane) => {
135
+ if (onNext != null) {
136
+ return onNext(next, lane);
137
+ }
138
+ buffer.push(next, lane);
139
+ return pushable;
140
+ };
141
+ const bufferError = (err) => {
142
+ buffer = new Uint8ArrayFifo();
143
+ if (onNext != null) {
144
+ return onNext({ error: err }, 0);
145
+ }
146
+ buffer.push({ error: err });
147
+ return pushable;
148
+ };
149
+ const push = (value, lane = 0) => {
150
+ if (ended) {
151
+ return pushable;
152
+ }
153
+ return bufferNext({ done: false, value }, lane);
154
+ };
155
+ const end = (err) => {
156
+ if (ended)
157
+ return pushable;
158
+ ended = true;
159
+ return err != null ? bufferError(err) : bufferNext({ done: true }, 0);
160
+ };
161
+ const _return = () => {
162
+ buffer = new Uint8ArrayFifo();
163
+ end();
164
+ return { done: true };
165
+ };
166
+ const _throw = (err) => {
167
+ end(err);
168
+ return { done: true };
169
+ };
170
+ pushable = {
171
+ [Symbol.asyncIterator]() {
172
+ return this;
173
+ },
174
+ next: waitNext,
175
+ return: _return,
176
+ throw: _throw,
177
+ push,
178
+ end,
179
+ get readableLength() {
180
+ return buffer.size;
181
+ },
182
+ getReadableLength(lane) {
183
+ if (lane == null) {
184
+ return buffer.size;
185
+ }
186
+ if (buffer instanceof Uint8arrayPriorityQueue) {
187
+ return buffer.lanes[lane].size;
188
+ }
189
+ throw new Error("Missing lane info");
190
+ },
191
+ onEmpty: async (options) => {
192
+ const signal = options?.signal;
193
+ signal?.throwIfAborted();
194
+ if (buffer.isEmpty()) {
195
+ return;
196
+ }
197
+ let cancel;
198
+ let listener;
199
+ if (signal != null) {
200
+ cancel = new Promise((resolve, reject) => {
201
+ listener = () => {
202
+ reject(new AbortError());
203
+ };
204
+ signal.addEventListener("abort", listener);
205
+ });
206
+ }
207
+ try {
208
+ await Promise.race([drain.promise, cancel]);
209
+ }
210
+ finally {
211
+ if (listener != null && signal != null) {
212
+ signal?.removeEventListener("abort", listener);
213
+ }
214
+ }
215
+ }
216
+ };
217
+ if (onEnd == null) {
218
+ return pushable;
219
+ }
220
+ const _pushable = pushable;
221
+ pushable = {
222
+ [Symbol.asyncIterator]() {
223
+ return this;
224
+ },
225
+ next() {
226
+ return _pushable.next();
227
+ },
228
+ throw(err) {
229
+ _pushable.throw(err);
230
+ if (onEnd != null) {
231
+ onEnd(err);
232
+ onEnd = undefined;
233
+ }
234
+ return { done: true };
235
+ },
236
+ return() {
237
+ _pushable.return();
238
+ if (onEnd != null) {
239
+ onEnd();
240
+ onEnd = undefined;
241
+ }
242
+ return { done: true };
243
+ },
244
+ push,
245
+ end(err) {
246
+ _pushable.end(err);
247
+ if (onEnd != null) {
248
+ onEnd(err);
249
+ onEnd = undefined;
250
+ }
251
+ return pushable;
252
+ },
253
+ get readableLength() {
254
+ return _pushable.readableLength;
255
+ },
256
+ onEmpty: (opts) => {
257
+ return _pushable.onEmpty(opts);
258
+ }
259
+ };
260
+ return pushable;
261
+ }
262
+ //# sourceMappingURL=pushable-lanes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pushable-lanes.js","sourceRoot":"","sources":["../../src/pushable-lanes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAC;AAC5B,OAAO,WAAW,MAAM,WAAW,CAAC;AAEpC,MAAM,OAAO,UAAW,SAAQ,KAAK;IACpC,IAAI,CAAS;IACb,IAAI,CAAS;IAEb,YAAY,OAAgB,EAAE,IAAa;QAC1C,KAAK,CAAC,OAAO,IAAI,2BAA2B,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,WAAW,CAAC;IACjC,CAAC;CACD;AA4ED;;GAEG;AACH,MAAM,cAAiD,SAAQ,WAE9D;IACA,IAAI,GAAW,CAAC,CAAC;IACjB,IAAI,CAAC,GAAY;QAChB,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;QACnC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,KAAK;QACJ,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,OAAO,EAAE,KAAK,EAAE,CAAC;YACpB,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;QACvC,CAAC;QACD,OAAO,OAAO,CAAC;IAChB,CAAC;CACD;AAED;;;;;GAKG;AACH,MAAM,uBAAuB;IAC5B,KAAK,CAAsB;IAC3B,YAAY,UAA6B,EAAE,KAAK,EAAE,CAAC,EAAE;QACpD,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,cAAc,EAAE,CAAC;QACtC,CAAC;IACF,CAAC;IAED,IAAI,IAAI;QACP,IAAI,GAAG,GAAG,CAAC,CAAC;QACZ,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC;QAClB,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IACD,IAAI,CAAC,GAAY,EAAE,IAAY;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IACD,KAAK;QACJ,sCAAsC;QACtC,2FAA2F;QAC3F,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,OAAO,EAAE,CAAC;gBACb,OAAO,OAAO,CAAC;YAChB,CAAC;QACF,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO;QACN,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrB,OAAO,KAAK,CAAC;YACd,CAAC;QACF,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAED,MAAM,UAAU,aAAa,CAC5B,UAAmB,EAAE;IAErB,OAAO,SAAS,CAAkC,OAAO,CAAC,CAAC;AAC5D,CAAC;AAED,wDAAwD;AACxD,SAAS,SAAS,CACjB,OAAiB;IAEjB,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC;IACxB,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC1B,IAAI,MAAM,GACT,IAAI,uBAAuB,CAC1B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CACpD,CAAC;IACH,IAAI,QAAa,CAAC;IAClB,IAAI,MAAmE,CAAC;IACxE,IAAI,KAAc,CAAC;IACnB,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;IAEpB,MAAM,OAAO,GAAG,GAA0B,EAAE;QAC3C,MAAM,IAAI,GAA+B,MAAM,CAAC,KAAK,EAAE,CAAC;QAExD,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,CAAC,KAAK,CAAC;QAClB,CAAC;QAED,OAAO;YACN,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI;YACxB,2DAA2D;YAC3D,KAAK,EAAE,IAAI,CAAC,KAAK;SACjB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,IAAoC,EAAE;QAC3D,IAAI,CAAC;YACJ,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;gBACvB,OAAO,OAAO,EAAE,CAAC;YAClB,CAAC;YAED,IAAI,KAAK,EAAE,CAAC;gBACX,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;YACvB,CAAC;YAED,OAAO,MAAM,IAAI,OAAO,CAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACnE,MAAM,GAAG,CAAC,IAAoB,EAAE,IAAY,EAAE,EAAE;oBAC/C,MAAM,GAAG,IAAI,CAAC;oBACd,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBAExB,IAAI,CAAC;wBACJ,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;oBACpB,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACd,MAAM,CAAC,GAAG,CAAC,CAAC;oBACb,CAAC;oBAED,OAAO,QAAQ,CAAC;gBACjB,CAAC,CAAC;YACH,CAAC,CAAC,CAAC;QACJ,CAAC;gBAAS,CAAC;YACV,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;gBACtB,sEAAsE;gBACtE,4BAA4B;gBAC5B,cAAc,CAAC,GAAG,EAAE;oBACnB,KAAK,CAAC,OAAO,EAAE,CAAC;oBAChB,KAAK,GAAG,KAAK,EAAE,CAAC;gBACjB,CAAC,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,IAAoB,EAAE,IAAY,EAAc,EAAE;QACrE,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACxB,OAAO,QAAQ,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,GAAU,EAAc,EAAE;QAC9C,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QAE9B,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACpB,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5B,OAAO,QAAQ,CAAC;IACjB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,CAAC,KAAe,EAAE,OAAe,CAAC,EAAc,EAAE;QAC9D,IAAI,KAAK,EAAE,CAAC;YACX,OAAO,QAAQ,CAAC;QACjB,CAAC;QAED,OAAO,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC;IACF,MAAM,GAAG,GAAG,CAAC,GAAW,EAAc,EAAE;QACvC,IAAI,KAAK;YAAE,OAAO,QAAQ,CAAC;QAC3B,KAAK,GAAG,IAAI,CAAC;QAEb,OAAO,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,MAAM,OAAO,GAAG,GAAe,EAAE;QAChC,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QAC9B,GAAG,EAAE,CAAC;QAEN,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,GAAU,EAAc,EAAE;QACzC,GAAG,CAAC,GAAG,CAAC,CAAC;QAET,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC,CAAC;IAEF,QAAQ,GAAG;QACV,CAAC,MAAM,CAAC,aAAa,CAAC;YACrB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,MAAM;QACb,IAAI;QACJ,GAAG;QACH,IAAI,cAAc;YACjB,OAAO,MAAM,CAAC,IAAI,CAAC;QACpB,CAAC;QAED,iBAAiB,CAAC,IAAa;YAC9B,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;gBAClB,OAAO,MAAM,CAAC,IAAI,CAAC;YACpB,CAAC;YAED,IAAI,MAAM,YAAY,uBAAuB,EAAE,CAAC;gBAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;YAChC,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,OAAsB,EAAE,EAAE;YACzC,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,CAAC;YAC/B,MAAM,EAAE,cAAc,EAAE,CAAC;YAEzB,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;gBACtB,OAAO;YACR,CAAC;YAED,IAAI,MAAiC,CAAC;YACtC,IAAI,QAAkC,CAAC;YAEvC,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACpB,MAAM,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;oBACxC,QAAQ,GAAG,GAAG,EAAE;wBACf,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC,CAAC;oBAC1B,CAAC,CAAC;oBAEF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAC5C,CAAC,CAAC,CAAC;YACJ,CAAC;YAED,IAAI,CAAC;gBACJ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;YAC7C,CAAC;oBAAS,CAAC;gBACV,IAAI,QAAQ,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;oBACxC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;gBAChD,CAAC;YACF,CAAC;QACF,CAAC;KACD,CAAC;IAEF,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,QAAQ,CAAC;IACjB,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC;IAE3B,QAAQ,GAAG;QACV,CAAC,MAAM,CAAC,aAAa,CAAC;YACrB,OAAO,IAAI,CAAC;QACb,CAAC;QACD,IAAI;YACH,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC;QACzB,CAAC;QACD,KAAK,CAAC,GAAU;YACf,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAErB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBACnB,KAAK,CAAC,GAAG,CAAC,CAAC;gBACX,KAAK,GAAG,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,MAAM;YACL,SAAS,CAAC,MAAM,EAAE,CAAC;YAEnB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBACnB,KAAK,EAAE,CAAC;gBACR,KAAK,GAAG,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,IAAI;QACJ,GAAG,CAAC,GAAU;YACb,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEnB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;gBACnB,KAAK,CAAC,GAAG,CAAC,CAAC;gBACX,KAAK,GAAG,SAAS,CAAC;YACnB,CAAC;YAED,OAAO,QAAQ,CAAC;QACjB,CAAC;QACD,IAAI,cAAc;YACjB,OAAO,SAAS,CAAC,cAAc,CAAC;QACjC,CAAC;QACD,OAAO,EAAE,CAAC,IAAmB,EAAE,EAAE;YAChC,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;KACD,CAAC;IAEF,OAAO,QAAQ,CAAC;AACjB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peerbit/stream",
3
- "version": "3.0.10",
3
+ "version": "3.1.0",
4
4
  "description": "A building block for direct streaming protocols",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -50,18 +50,20 @@
50
50
  "dao.xyz"
51
51
  ],
52
52
  "devDependencies": {
53
- "@peerbit/libp2p-test-utils": "2.1.1",
53
+ "@peerbit/libp2p-test-utils": "2.1.2",
54
+ "@types/fast-fifo": "^1.0.2",
54
55
  "@types/yallist": "^4.0.1"
55
56
  },
56
57
  "dependencies": {
57
58
  "@dao-xyz/borsh": "^5.2.1",
58
59
  "@peerbit/cache": "2.0.6",
59
60
  "@peerbit/crypto": "2.1.7",
60
- "@peerbit/stream-interface": "^3.0.8",
61
+ "@peerbit/stream-interface": "^3.0.9",
61
62
  "abortable-iterator": "^5.0.1",
63
+ "fast-fifo": "^1.3.2",
62
64
  "libp2p": "^1.2.1",
63
65
  "p-queue": "^8.0.1",
64
66
  "yallist": "^4.0.0"
65
67
  },
66
- "gitHead": "82d6f528faf0a4e060e400314bc01bc7260c41a5"
68
+ "gitHead": "0953a22f7a7ad21e89d0d4ee0673b0569da27f87"
67
69
  }
package/src/index.ts CHANGED
@@ -3,8 +3,7 @@ import { pipe } from "it-pipe";
3
3
  import Queue from "p-queue";
4
4
  import type { PeerId } from "@libp2p/interface";
5
5
  import type { Connection } from "@libp2p/interface";
6
- import type { Pushable } from "it-pushable";
7
- import { pushable } from "it-pushable";
6
+ import { PushableLanes, pushableLanes } from "./pushable-lanes.js";
8
7
  import type { Stream } from "@libp2p/interface";
9
8
  import { Uint8ArrayList } from "uint8arraylist";
10
9
  import { abortableSource } from "abortable-iterator";
@@ -13,7 +12,6 @@ import { MAX_ROUTE_DISTANCE, Routes } from "./routes.js";
13
12
  import type { IncomingStreamData, Registrar } from "@libp2p/interface-internal";
14
13
  import type { AddressManager } from "@libp2p/interface-internal";
15
14
  import type { ConnectionManager } from "@libp2p/interface-internal";
16
-
17
15
  import { PeerStore } from "@libp2p/interface";
18
16
  import pDefer from "p-defer";
19
17
 
@@ -53,7 +51,8 @@ import {
53
51
  TracedDelivery,
54
52
  AnyWhere,
55
53
  NotStartedError,
56
- deliveryModeHasReceiver
54
+ deliveryModeHasReceiver,
55
+ DeliveryError
57
56
  } from "@peerbit/stream-interface";
58
57
 
59
58
  import { MultiAddrinfo } from "@peerbit/stream-interface";
@@ -63,6 +62,7 @@ export { BandwidthTracker }; // might be useful for others
63
62
  const logError = (e?: { message: string }) => {
64
63
  return logger.error(e?.message);
65
64
  };
65
+
66
66
  export interface PeerStreamsInit {
67
67
  peerId: PeerId;
68
68
  publicKey: PublicSignKey;
@@ -114,7 +114,8 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
114
114
  /**
115
115
  * Write stream - it's preferable to use the write method
116
116
  */
117
- public outboundStream?: Pushable<Uint8Array>;
117
+ public outboundStream?: PushableLanes<Uint8Array>;
118
+
118
119
  /**
119
120
  * Read stream
120
121
  */
@@ -122,11 +123,11 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
122
123
  /**
123
124
  * The raw outbound stream, as retrieved from conn.newStream
124
125
  */
125
- public _rawOutboundStream?: Stream;
126
+ public rawOutboundStream?: Stream;
126
127
  /**
127
128
  * The raw inbound stream, as retrieved from the callback from libp2p.handle
128
129
  */
129
- public _rawInboundStream?: Stream;
130
+ public rawInboundStream?: Stream;
130
131
  /**
131
132
  * An AbortController for controlled shutdown of the treams
132
133
  */
@@ -174,7 +175,7 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
174
175
  * Send a message to this peer.
175
176
  * Throws if there is no `stream` to write to available.
176
177
  */
177
- write(data: Uint8Array | Uint8ArrayList) {
178
+ write(data: Uint8Array | Uint8ArrayList, priority = false) {
178
179
  if (data.length > MAX_DATA_LENGTH_OUT) {
179
180
  throw new Error(
180
181
  `Message too large (${data.length * 1e-6}) mb). Needs to be less than ${
@@ -188,13 +189,13 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
188
189
  }
189
190
 
190
191
  this.usedBandWidthTracker.add(data.byteLength);
191
-
192
192
  this.outboundStream.push(
193
- data instanceof Uint8Array ? data : data.subarray()
193
+ data instanceof Uint8Array ? data : data.subarray(),
194
+ priority || this.outboundStream.getReadableLength(0) === 0 ? 0 : 1
194
195
  );
195
196
  }
196
197
 
197
- async waitForWrite(bytes: Uint8Array | Uint8ArrayList) {
198
+ async waitForWrite(bytes: Uint8Array | Uint8ArrayList, priority = false) {
198
199
  if (this.closed) {
199
200
  logger.error("Failed to send to stream: " + this.peerId + ". Closed");
200
201
  return;
@@ -233,13 +234,13 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
233
234
 
234
235
  await outboundPromise
235
236
  .then(() => {
236
- this.write(bytes);
237
+ this.write(bytes, priority);
237
238
  })
238
239
  .catch((error) => {
239
240
  throw error;
240
241
  });
241
242
  } else {
242
- this.write(bytes);
243
+ this.write(bytes, priority);
243
244
  }
244
245
  }
245
246
 
@@ -251,9 +252,9 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
251
252
  // The inbound stream is:
252
253
  // - abortable, set to only return on abort, rather than throw
253
254
  // - transformed with length-prefix transform
254
- this._rawInboundStream = stream;
255
+ this.rawInboundStream = stream;
255
256
  this.inboundStream = abortableSource(
256
- pipe(this._rawInboundStream, (source) =>
257
+ pipe(this.rawInboundStream, (source) =>
257
258
  lp.decode(source, { maxDataLength: MAX_DATA_LENGTH_IN })
258
259
  ),
259
260
  this.inboundAbortController.signal,
@@ -276,35 +277,23 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
276
277
  async attachOutboundStream(stream: Stream) {
277
278
  // If an outbound stream already exists, gently close it
278
279
  const _prevStream = this.outboundStream;
279
-
280
- this._rawOutboundStream = stream;
281
- this.outboundStream = pushable<Uint8Array>({
282
- objectMode: false,
283
- onEnd: () => {
284
- return stream.close().then(() => {
285
- if (this._rawOutboundStream === stream) {
286
- this.dispatchEvent(new CustomEvent("close"));
287
- this._rawOutboundStream = undefined;
288
- this.outboundStream = undefined;
289
- }
290
- });
291
- }
292
- });
280
+ if (_prevStream) {
281
+ logger.info(
282
+ `Stream already exist. This can be due to that you are opening two or more connections to ${this.peerId.toString()}. A stream will only be created for the first succesfully created connection`
283
+ );
284
+ return;
285
+ }
286
+ this.rawOutboundStream = stream;
287
+ this.outboundStream = pushableLanes({ lanes: 2 });
293
288
 
294
289
  pipe(
295
290
  this.outboundStream,
296
291
  (source) => lp.encode(source),
297
- this._rawOutboundStream
292
+ this.rawOutboundStream
298
293
  ).catch(logError);
299
294
 
300
295
  // Emit if the connection is new
301
296
  this.dispatchEvent(new CustomEvent("stream:outbound"));
302
-
303
- if (_prevStream != null) {
304
- // End the stream without emitting a close event
305
- await _prevStream.end();
306
- }
307
- return this.outboundStream;
308
297
  }
309
298
 
310
299
  /**
@@ -320,21 +309,23 @@ export class PeerStreams extends TypedEventEmitter<PeerStreamEvents> {
320
309
  // End the outbound stream
321
310
  if (this.outboundStream != null) {
322
311
  await this.outboundStream.return();
323
- await this._rawOutboundStream?.close();
312
+ await this.rawOutboundStream?.abort(new AbortError("Closed"));
324
313
  }
314
+
325
315
  // End the inbound stream
326
316
  if (this.inboundStream != null) {
327
317
  this.inboundAbortController.abort();
328
- await this._rawInboundStream?.close();
318
+ await this.rawInboundStream?.close();
329
319
  }
330
320
 
331
321
  this.usedBandWidthTracker.stop();
332
322
 
333
323
  this.dispatchEvent(new CustomEvent("close"));
334
324
 
335
- this._rawOutboundStream = undefined;
325
+ this.rawOutboundStream = undefined;
336
326
  this.outboundStream = undefined;
337
- this._rawInboundStream = undefined;
327
+
328
+ this.rawInboundStream = undefined;
338
329
  this.inboundStream = undefined;
339
330
  }
340
331
  }
@@ -815,7 +806,7 @@ export abstract class DirectStream<
815
806
  const dependent = this.routes.getDependent(peerKeyHash);
816
807
 
817
808
  // make neighbour unreachables
818
- this.removePeerFromRoutes(peerKeyHash);
809
+ this.removePeerFromRoutes(peerKeyHash, true);
819
810
 
820
811
  if (dependent.length > 0) {
821
812
  await this.publishMessage(
@@ -836,7 +827,11 @@ export abstract class DirectStream<
836
827
  logger.debug("connection ended:" + peerKey.toString());
837
828
  }
838
829
 
839
- public removePeerFromRoutes(hash: string) {
830
+ public removePeerFromRoutes(hash: string, deleteIfNeighbour = false) {
831
+ if (this.peers.has(hash) && !deleteIfNeighbour) {
832
+ return;
833
+ }
834
+
840
835
  const unreachable = this.routes.remove(hash);
841
836
  for (const node of unreachable) {
842
837
  this.onPeerUnreachable(node); // TODO types
@@ -1375,9 +1370,13 @@ export abstract class DirectStream<
1375
1370
  })
1376
1371
  .then(() => true)
1377
1372
  .catch((e) => {
1378
- if (e instanceof TimeoutError) {
1373
+ if (e instanceof DeliveryError) {
1374
+ return false;
1375
+ } else if (e instanceof NotStartedError) {
1379
1376
  return false;
1380
- } else if (e instanceof AbortError || e instanceof NotStartedError) {
1377
+ } else if (e instanceof TimeoutError) {
1378
+ return false;
1379
+ } else if (e instanceof AbortError) {
1381
1380
  return false;
1382
1381
  } else {
1383
1382
  throw e;
@@ -1557,8 +1556,16 @@ export abstract class DirectStream<
1557
1556
  const onUnreachable =
1558
1557
  !relayed &&
1559
1558
  ((ev) => {
1560
- messageToSet.delete(ev.detail.hashcode());
1561
- checkDone();
1559
+ const deletedReceiver = messageToSet.delete(ev.detail.hashcode());
1560
+ if (deletedReceiver) {
1561
+ // Only reject if we are the sender
1562
+ clear();
1563
+ deliveryDeferredPromise.reject(
1564
+ new DeliveryError(
1565
+ `At least one recipent became unreachable while delivering messsage of type$ ${message.constructor.name}} to ${ev.detail.hashcode()}`
1566
+ )
1567
+ );
1568
+ }
1562
1569
  });
1563
1570
 
1564
1571
  onUnreachable && this.addEventListener("peer:unreachable", onUnreachable);
@@ -1591,10 +1598,8 @@ export abstract class DirectStream<
1591
1598
 
1592
1599
  if (!hasAll && willGetAllAcknowledgements) {
1593
1600
  deliveryDeferredPromise.reject(
1594
- new TimeoutError(
1595
- `${
1596
- this.publicKeyHash
1597
- } Failed to get message ${idString} ${filterMessageForSeenCounter} ${[
1601
+ new DeliveryError(
1602
+ `Failed to get message ${idString} ${filterMessageForSeenCounter} ${[
1598
1603
  ...messageToSet
1599
1604
  ]} delivery acknowledges from all nodes (${
1600
1605
  fastestNodesReached.size
@@ -1688,6 +1693,11 @@ export abstract class DirectStream<
1688
1693
  if (this.stopping || !this.started) {
1689
1694
  throw new NotStartedError();
1690
1695
  }
1696
+ const isPriorityMessage =
1697
+ message.header.mode instanceof SilentDelivery ||
1698
+ message.header.mode instanceof AnyWhere
1699
+ ? false
1700
+ : true;
1691
1701
 
1692
1702
  let delivereyPromise: Promise<void> | undefined = undefined as any;
1693
1703
 
@@ -1755,7 +1765,8 @@ export abstract class DirectStream<
1755
1765
  const promises: Promise<any>[] = [];
1756
1766
  for (const [neighbour, _distantPeers] of fanout) {
1757
1767
  const stream = this.peers.get(neighbour);
1758
- stream && promises.push(stream.waitForWrite(bytes));
1768
+ stream &&
1769
+ promises.push(stream.waitForWrite(bytes, isPriorityMessage));
1759
1770
  }
1760
1771
  await Promise.all(promises);
1761
1772
  return delivereyPromise; // we are done sending the message in all direction with updates 'to' lists
@@ -1801,7 +1812,7 @@ export abstract class DirectStream<
1801
1812
 
1802
1813
  sentOnce = true;
1803
1814
 
1804
- promises.push(id.waitForWrite(bytes));
1815
+ promises.push(id.waitForWrite(bytes, isPriorityMessage));
1805
1816
  }
1806
1817
  await Promise.all(promises);
1807
1818
 
@@ -1948,7 +1959,8 @@ export abstract class DirectStream<
1948
1959
  getQueuedBytes(): number {
1949
1960
  let sum = 0;
1950
1961
  for (const peer of this.peers) {
1951
- sum += peer[1].outboundStream?.readableLength || 0;
1962
+ const out = peer[1].outboundStream;
1963
+ sum += out ? out.readableLength : 0;
1952
1964
  }
1953
1965
  return sum;
1954
1966
  }