@libp2p/interface 0.0.1 → 0.1.0-e66f4891
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.
- package/dist/src/connection/index.d.ts +152 -53
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js.map +1 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +8 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/keys/index.d.ts.map +1 -1
- package/dist/src/keys/index.js.map +1 -1
- package/dist/src/peer-store/tags.d.ts.map +1 -1
- package/dist/src/peer-store/tags.js.map +1 -1
- package/dist/src/pubsub/index.d.ts +236 -0
- package/dist/src/pubsub/index.d.ts.map +1 -0
- package/dist/src/pubsub/index.js +36 -0
- package/dist/src/pubsub/index.js.map +1 -0
- package/dist/src/startable.d.ts.map +1 -1
- package/dist/src/startable.js.map +1 -1
- package/dist/src/stream-handler/index.d.ts +5 -0
- package/dist/src/stream-handler/index.d.ts.map +1 -1
- package/dist/src/stream-muxer/index.d.ts +6 -2
- package/dist/src/stream-muxer/index.d.ts.map +1 -1
- package/dist/src/stream-muxer/stream.d.ts +80 -21
- package/dist/src/stream-muxer/stream.d.ts.map +1 -1
- package/dist/src/stream-muxer/stream.js +224 -168
- package/dist/src/stream-muxer/stream.js.map +1 -1
- package/dist/src/transport/index.d.ts +5 -0
- package/dist/src/transport/index.d.ts.map +1 -1
- package/package.json +8 -11
- package/src/connection/index.ts +180 -59
- package/src/errors.ts +0 -1
- package/src/index.ts +8 -4
- package/src/keys/index.ts +0 -1
- package/src/peer-store/tags.ts +0 -1
- package/src/pubsub/index.ts +269 -0
- package/src/startable.ts +0 -1
- package/src/stream-handler/index.ts +6 -0
- package/src/stream-muxer/index.ts +7 -2
- package/src/stream-muxer/stream.ts +295 -186
- package/src/transport/index.ts +6 -0
- package/dist/src/connection/status.d.ts +0 -4
- package/dist/src/connection/status.d.ts.map +0 -1
- package/dist/src/connection/status.js +0 -4
- package/dist/src/connection/status.js.map +0 -1
- package/src/connection/status.ts +0 -4
|
@@ -37,10 +37,15 @@ export interface StreamMuxer extends Duplex<AsyncGenerator<Uint8Array>, Source<U
|
|
|
37
37
|
/**
|
|
38
38
|
* Close or abort all tracked streams and stop the muxer
|
|
39
39
|
*/
|
|
40
|
-
close: (
|
|
40
|
+
close: (options?: AbortOptions) => Promise<void>
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Close or abort all tracked streams and stop the muxer
|
|
44
|
+
*/
|
|
45
|
+
abort: (err: Error) => void
|
|
41
46
|
}
|
|
42
47
|
|
|
43
|
-
export interface StreamMuxerInit
|
|
48
|
+
export interface StreamMuxerInit {
|
|
44
49
|
/**
|
|
45
50
|
* A callback function invoked every time an incoming stream is opened
|
|
46
51
|
*/
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
// import { logger } from '@libp2p/logger'
|
|
2
1
|
import { abortableSource } from 'abortable-iterator'
|
|
3
|
-
import { anySignal } from 'any-signal'
|
|
4
2
|
import { type Pushable, pushable } from 'it-pushable'
|
|
3
|
+
import defer, { type DeferredPromise } from 'p-defer'
|
|
5
4
|
import { Uint8ArrayList } from 'uint8arraylist'
|
|
6
5
|
import { CodeError } from '../errors.js'
|
|
7
|
-
import type { Direction, Stream,
|
|
6
|
+
import type { Direction, ReadStatus, Stream, StreamStatus, StreamTimeline, WriteStatus } from '../connection/index.js'
|
|
7
|
+
import type { AbortOptions } from '../index.js'
|
|
8
8
|
import type { Source } from 'it-stream-types'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
interface Logger {
|
|
11
|
+
(formatter: any, ...args: any[]): void
|
|
12
|
+
error: (formatter: any, ...args: any[]) => void
|
|
13
|
+
trace: (formatter: any, ...args: any[]) => void
|
|
14
|
+
enabled: boolean
|
|
15
|
+
}
|
|
15
16
|
|
|
16
17
|
const ERR_STREAM_RESET = 'ERR_STREAM_RESET'
|
|
17
|
-
const
|
|
18
|
-
const ERR_SINK_ENDED = 'ERR_SINK_ENDED'
|
|
19
|
-
const ERR_DOUBLE_SINK = 'ERR_DOUBLE_SINK'
|
|
18
|
+
const ERR_SINK_INVALID_STATE = 'ERR_SINK_INVALID_STATE'
|
|
20
19
|
|
|
21
20
|
export interface AbstractStreamInit {
|
|
22
21
|
/**
|
|
@@ -30,10 +29,9 @@ export interface AbstractStreamInit {
|
|
|
30
29
|
direction: Direction
|
|
31
30
|
|
|
32
31
|
/**
|
|
33
|
-
*
|
|
34
|
-
* chunked and sent in multiple data messages
|
|
32
|
+
* A Logger implementation used to log stream-specific information
|
|
35
33
|
*/
|
|
36
|
-
|
|
34
|
+
log: Logger
|
|
37
35
|
|
|
38
36
|
/**
|
|
39
37
|
* User specific stream metadata
|
|
@@ -44,6 +42,32 @@ export interface AbstractStreamInit {
|
|
|
44
42
|
* Invoked when the stream ends
|
|
45
43
|
*/
|
|
46
44
|
onEnd?: (err?: Error | undefined) => void
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Invoked when the readable end of the stream is closed
|
|
48
|
+
*/
|
|
49
|
+
onCloseRead?: () => void
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Invoked when the writable end of the stream is closed
|
|
53
|
+
*/
|
|
54
|
+
onCloseWrite?: () => void
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Invoked when the the stream has been reset by the remote
|
|
58
|
+
*/
|
|
59
|
+
onReset?: () => void
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Invoked when the the stream has errored
|
|
63
|
+
*/
|
|
64
|
+
onAbort?: (err: Error) => void
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* How long to wait in ms for stream data to be written to the underlying
|
|
68
|
+
* connection when closing the writable end of the stream. (default: 500)
|
|
69
|
+
*/
|
|
70
|
+
closeTimeout?: number
|
|
47
71
|
}
|
|
48
72
|
|
|
49
73
|
function isPromise (res?: any): res is Promise<void> {
|
|
@@ -52,54 +76,60 @@ function isPromise (res?: any): res is Promise<void> {
|
|
|
52
76
|
|
|
53
77
|
export abstract class AbstractStream implements Stream {
|
|
54
78
|
public id: string
|
|
55
|
-
public
|
|
79
|
+
public direction: Direction
|
|
80
|
+
public timeline: StreamTimeline
|
|
81
|
+
public protocol?: string
|
|
56
82
|
public metadata: Record<string, unknown>
|
|
57
83
|
public source: AsyncGenerator<Uint8ArrayList, void, unknown>
|
|
84
|
+
public status: StreamStatus
|
|
85
|
+
public readStatus: ReadStatus
|
|
86
|
+
public writeStatus: WriteStatus
|
|
58
87
|
|
|
59
|
-
private readonly
|
|
60
|
-
private readonly
|
|
61
|
-
private readonly closeController: AbortController
|
|
62
|
-
private sourceEnded: boolean
|
|
63
|
-
private sinkEnded: boolean
|
|
64
|
-
private sinkSunk: boolean
|
|
88
|
+
private readonly sinkController: AbortController
|
|
89
|
+
private readonly sinkEnd: DeferredPromise<void>
|
|
65
90
|
private endErr: Error | undefined
|
|
66
91
|
private readonly streamSource: Pushable<Uint8ArrayList>
|
|
67
92
|
private readonly onEnd?: (err?: Error | undefined) => void
|
|
68
|
-
private readonly
|
|
93
|
+
private readonly onCloseRead?: () => void
|
|
94
|
+
private readonly onCloseWrite?: () => void
|
|
95
|
+
private readonly onReset?: () => void
|
|
96
|
+
private readonly onAbort?: (err: Error) => void
|
|
97
|
+
|
|
98
|
+
protected readonly log: Logger
|
|
69
99
|
|
|
70
100
|
constructor (init: AbstractStreamInit) {
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
this.
|
|
101
|
+
this.sinkController = new AbortController()
|
|
102
|
+
this.sinkEnd = defer()
|
|
103
|
+
this.log = init.log
|
|
104
|
+
|
|
105
|
+
// stream status
|
|
106
|
+
this.status = 'open'
|
|
107
|
+
this.readStatus = 'ready'
|
|
108
|
+
this.writeStatus = 'ready'
|
|
77
109
|
|
|
78
110
|
this.id = init.id
|
|
79
111
|
this.metadata = init.metadata ?? {}
|
|
80
|
-
this.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
open: Date.now()
|
|
84
|
-
}
|
|
112
|
+
this.direction = init.direction
|
|
113
|
+
this.timeline = {
|
|
114
|
+
open: Date.now()
|
|
85
115
|
}
|
|
86
|
-
|
|
116
|
+
|
|
87
117
|
this.onEnd = init.onEnd
|
|
118
|
+
this.onCloseRead = init?.onCloseRead
|
|
119
|
+
this.onCloseWrite = init?.onCloseWrite
|
|
120
|
+
this.onReset = init?.onReset
|
|
121
|
+
this.onAbort = init?.onAbort
|
|
88
122
|
|
|
89
123
|
this.source = this.streamSource = pushable<Uint8ArrayList>({
|
|
90
|
-
onEnd: () => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
if (isPromise(res)) {
|
|
96
|
-
res.catch(err => {
|
|
97
|
-
log.error('error while sending close read', err)
|
|
98
|
-
})
|
|
99
|
-
}
|
|
124
|
+
onEnd: (err) => {
|
|
125
|
+
if (err != null) {
|
|
126
|
+
this.log.trace('source ended with error', err)
|
|
127
|
+
} else {
|
|
128
|
+
this.log.trace('source ended')
|
|
100
129
|
}
|
|
101
130
|
|
|
102
|
-
this.
|
|
131
|
+
this.readStatus = 'closed'
|
|
132
|
+
this.onSourceEnd(err)
|
|
103
133
|
}
|
|
104
134
|
})
|
|
105
135
|
|
|
@@ -107,216 +137,295 @@ export abstract class AbstractStream implements Stream {
|
|
|
107
137
|
this.sink = this.sink.bind(this)
|
|
108
138
|
}
|
|
109
139
|
|
|
140
|
+
async sink (source: Source<Uint8ArrayList | Uint8Array>): Promise<void> {
|
|
141
|
+
if (this.writeStatus !== 'ready') {
|
|
142
|
+
throw new CodeError(`writable end state is "${this.writeStatus}" not "ready"`, ERR_SINK_INVALID_STATE)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
try {
|
|
146
|
+
this.writeStatus = 'writing'
|
|
147
|
+
|
|
148
|
+
const options: AbortOptions = {
|
|
149
|
+
signal: this.sinkController.signal
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (this.direction === 'outbound') { // If initiator, open a new stream
|
|
153
|
+
const res = this.sendNewStream(options)
|
|
154
|
+
|
|
155
|
+
if (isPromise(res)) {
|
|
156
|
+
await res
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
source = abortableSource(source, this.sinkController.signal, {
|
|
161
|
+
returnOnAbort: true
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
this.log.trace('sink reading from source')
|
|
165
|
+
|
|
166
|
+
for await (let data of source) {
|
|
167
|
+
data = data instanceof Uint8Array ? new Uint8ArrayList(data) : data
|
|
168
|
+
|
|
169
|
+
const res = this.sendData(data, options)
|
|
170
|
+
|
|
171
|
+
if (isPromise(res)) { // eslint-disable-line max-depth
|
|
172
|
+
await res
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
this.log.trace('sink finished reading from source')
|
|
177
|
+
this.writeStatus = 'done'
|
|
178
|
+
|
|
179
|
+
this.log.trace('sink calling closeWrite')
|
|
180
|
+
await this.closeWrite(options)
|
|
181
|
+
this.onSinkEnd()
|
|
182
|
+
} catch (err: any) {
|
|
183
|
+
this.log.trace('sink ended with error, calling abort with error', err)
|
|
184
|
+
this.abort(err)
|
|
185
|
+
|
|
186
|
+
throw err
|
|
187
|
+
} finally {
|
|
188
|
+
this.log.trace('resolve sink end')
|
|
189
|
+
this.sinkEnd.resolve()
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
110
193
|
protected onSourceEnd (err?: Error): void {
|
|
111
|
-
if (this.
|
|
194
|
+
if (this.timeline.closeRead != null) {
|
|
112
195
|
return
|
|
113
196
|
}
|
|
114
197
|
|
|
115
|
-
this.
|
|
116
|
-
this.sourceEnded = true
|
|
117
|
-
log.trace('%s stream %s source end - err: %o', this.stat.direction, this.id, err)
|
|
198
|
+
this.timeline.closeRead = Date.now()
|
|
118
199
|
|
|
119
200
|
if (err != null && this.endErr == null) {
|
|
120
201
|
this.endErr = err
|
|
121
202
|
}
|
|
122
203
|
|
|
123
|
-
|
|
124
|
-
|
|
204
|
+
this.onCloseRead?.()
|
|
205
|
+
|
|
206
|
+
if (this.timeline.closeWrite != null) {
|
|
207
|
+
this.log.trace('source and sink ended')
|
|
208
|
+
this.timeline.close = Date.now()
|
|
125
209
|
|
|
126
210
|
if (this.onEnd != null) {
|
|
127
211
|
this.onEnd(this.endErr)
|
|
128
212
|
}
|
|
213
|
+
} else {
|
|
214
|
+
this.log.trace('source ended, waiting for sink to end')
|
|
129
215
|
}
|
|
130
216
|
}
|
|
131
217
|
|
|
132
218
|
protected onSinkEnd (err?: Error): void {
|
|
133
|
-
if (this.
|
|
219
|
+
if (this.timeline.closeWrite != null) {
|
|
134
220
|
return
|
|
135
221
|
}
|
|
136
222
|
|
|
137
|
-
this.
|
|
138
|
-
this.sinkEnded = true
|
|
139
|
-
log.trace('%s stream %s sink end - err: %o', this.stat.direction, this.id, err)
|
|
223
|
+
this.timeline.closeWrite = Date.now()
|
|
140
224
|
|
|
141
225
|
if (err != null && this.endErr == null) {
|
|
142
226
|
this.endErr = err
|
|
143
227
|
}
|
|
144
228
|
|
|
145
|
-
|
|
146
|
-
|
|
229
|
+
this.onCloseWrite?.()
|
|
230
|
+
|
|
231
|
+
if (this.timeline.closeRead != null) {
|
|
232
|
+
this.log.trace('sink and source ended')
|
|
233
|
+
this.timeline.close = Date.now()
|
|
147
234
|
|
|
148
235
|
if (this.onEnd != null) {
|
|
149
236
|
this.onEnd(this.endErr)
|
|
150
237
|
}
|
|
238
|
+
} else {
|
|
239
|
+
this.log.trace('sink ended, waiting for source to end')
|
|
151
240
|
}
|
|
152
241
|
}
|
|
153
242
|
|
|
154
243
|
// Close for both Reading and Writing
|
|
155
|
-
close (): void {
|
|
156
|
-
log.trace('
|
|
244
|
+
async close (options?: AbortOptions): Promise<void> {
|
|
245
|
+
this.log.trace('closing gracefully')
|
|
157
246
|
|
|
158
|
-
this.
|
|
159
|
-
this.closeWrite()
|
|
160
|
-
}
|
|
247
|
+
this.status = 'closing'
|
|
161
248
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
249
|
+
await Promise.all([
|
|
250
|
+
this.closeRead(options),
|
|
251
|
+
this.closeWrite(options)
|
|
252
|
+
])
|
|
165
253
|
|
|
166
|
-
|
|
167
|
-
return
|
|
168
|
-
}
|
|
254
|
+
this.status = 'closed'
|
|
169
255
|
|
|
170
|
-
this.
|
|
256
|
+
this.log.trace('closed gracefully')
|
|
171
257
|
}
|
|
172
258
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
log.trace('%s stream %s closeWrite', this.stat.direction, this.id)
|
|
176
|
-
|
|
177
|
-
if (this.sinkEnded) {
|
|
259
|
+
async closeRead (options: AbortOptions = {}): Promise<void> {
|
|
260
|
+
if (this.readStatus === 'closing' || this.readStatus === 'closed') {
|
|
178
261
|
return
|
|
179
262
|
}
|
|
180
263
|
|
|
181
|
-
this.
|
|
264
|
+
this.log.trace('closing readable end of stream with starting read status "%s"', this.readStatus)
|
|
182
265
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
// when the close controller is aborted
|
|
186
|
-
const res = this.sendCloseWrite()
|
|
266
|
+
const readStatus = this.readStatus
|
|
267
|
+
this.readStatus = 'closing'
|
|
187
268
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
})
|
|
192
|
-
}
|
|
193
|
-
} catch (err) {
|
|
194
|
-
log.trace('%s stream %s error sending close', this.stat.direction, this.id, err)
|
|
269
|
+
if (readStatus === 'ready') {
|
|
270
|
+
this.log.trace('ending internal source queue')
|
|
271
|
+
this.streamSource.end()
|
|
195
272
|
}
|
|
196
273
|
|
|
197
|
-
this.
|
|
198
|
-
|
|
274
|
+
if (this.status !== 'reset' && this.status !== 'aborted') {
|
|
275
|
+
this.log.trace('send close read to remote')
|
|
276
|
+
await this.sendCloseRead(options)
|
|
277
|
+
}
|
|
199
278
|
|
|
200
|
-
|
|
201
|
-
abort (err: Error): void {
|
|
202
|
-
log.trace('%s stream %s abort', this.stat.direction, this.id, err)
|
|
203
|
-
// End the source with the passed error
|
|
204
|
-
this.streamSource.end(err)
|
|
205
|
-
this.abortController.abort()
|
|
206
|
-
this.onSinkEnd(err)
|
|
279
|
+
this.log.trace('closed readable end of stream')
|
|
207
280
|
}
|
|
208
281
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
this.streamSource.end(err)
|
|
214
|
-
this.onSinkEnd(err)
|
|
215
|
-
}
|
|
282
|
+
async closeWrite (options: AbortOptions = {}): Promise<void> {
|
|
283
|
+
if (this.writeStatus === 'closing' || this.writeStatus === 'closed') {
|
|
284
|
+
return
|
|
285
|
+
}
|
|
216
286
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
287
|
+
this.log.trace('closing writable end of stream with starting write status "%s"', this.writeStatus)
|
|
288
|
+
|
|
289
|
+
const writeStatus = this.writeStatus
|
|
290
|
+
|
|
291
|
+
if (this.writeStatus === 'ready') {
|
|
292
|
+
this.log.trace('sink was never sunk, sink an empty array')
|
|
293
|
+
await this.sink([])
|
|
220
294
|
}
|
|
221
295
|
|
|
222
|
-
this.
|
|
296
|
+
this.writeStatus = 'closing'
|
|
297
|
+
|
|
298
|
+
if (writeStatus === 'writing') {
|
|
299
|
+
// stop reading from the source passed to `.sink` in the microtask queue
|
|
300
|
+
// - this lets any data queued by the user in the current tick get read
|
|
301
|
+
// before we exit
|
|
302
|
+
await new Promise((resolve, reject) => {
|
|
303
|
+
queueMicrotask(() => {
|
|
304
|
+
this.log.trace('aborting source passed to .sink')
|
|
305
|
+
this.sinkController.abort()
|
|
306
|
+
this.sinkEnd.promise.then(resolve, reject)
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
}
|
|
223
310
|
|
|
224
|
-
if (this.
|
|
225
|
-
|
|
311
|
+
if (this.status !== 'reset' && this.status !== 'aborted') {
|
|
312
|
+
this.log.trace('send close write to remote')
|
|
313
|
+
await this.sendCloseWrite(options)
|
|
226
314
|
}
|
|
227
315
|
|
|
228
|
-
|
|
229
|
-
this.abortController.signal,
|
|
230
|
-
this.resetController.signal,
|
|
231
|
-
this.closeController.signal
|
|
232
|
-
])
|
|
316
|
+
this.writeStatus = 'closed'
|
|
233
317
|
|
|
234
|
-
|
|
235
|
-
|
|
318
|
+
this.log.trace('closed writable end of stream')
|
|
319
|
+
}
|
|
236
320
|
|
|
237
|
-
|
|
238
|
-
|
|
321
|
+
/**
|
|
322
|
+
* Close immediately for reading and writing and send a reset message (local
|
|
323
|
+
* error)
|
|
324
|
+
*/
|
|
325
|
+
abort (err: Error): void {
|
|
326
|
+
if (this.status === 'closed' || this.status === 'aborted' || this.status === 'reset') {
|
|
327
|
+
return
|
|
328
|
+
}
|
|
239
329
|
|
|
240
|
-
|
|
241
|
-
await res
|
|
242
|
-
}
|
|
243
|
-
}
|
|
330
|
+
this.log('abort with error', err)
|
|
244
331
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const res = this.sendData(data instanceof Uint8Array ? new Uint8ArrayList(data) : data)
|
|
332
|
+
// try to send a reset message
|
|
333
|
+
this.log('try to send reset to remote')
|
|
334
|
+
const res = this.sendReset()
|
|
249
335
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
336
|
+
if (isPromise(res)) {
|
|
337
|
+
res.catch((err) => {
|
|
338
|
+
this.log.error('error sending reset message', err)
|
|
339
|
+
})
|
|
340
|
+
}
|
|
253
341
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
342
|
+
this.status = 'aborted'
|
|
343
|
+
this.timeline.abort = Date.now()
|
|
344
|
+
this._closeSinkAndSource(err)
|
|
345
|
+
this.onAbort?.(err)
|
|
346
|
+
}
|
|
258
347
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Receive a reset message - close immediately for reading and writing (remote
|
|
350
|
+
* error)
|
|
351
|
+
*/
|
|
352
|
+
reset (): void {
|
|
353
|
+
if (this.status === 'closed' || this.status === 'aborted' || this.status === 'reset') {
|
|
354
|
+
return
|
|
355
|
+
}
|
|
262
356
|
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
} catch (err: any) {
|
|
267
|
-
if (err.type === 'aborted' && err.message === 'The operation was aborted') {
|
|
268
|
-
if (this.closeController.signal.aborted) {
|
|
269
|
-
return
|
|
270
|
-
}
|
|
357
|
+
const err = new CodeError('stream reset', ERR_STREAM_RESET)
|
|
271
358
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
359
|
+
this.status = 'reset'
|
|
360
|
+
this._closeSinkAndSource(err)
|
|
361
|
+
this.onReset?.()
|
|
362
|
+
}
|
|
276
363
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
364
|
+
_closeSinkAndSource (err?: Error): void {
|
|
365
|
+
this._closeSink(err)
|
|
366
|
+
this._closeSource(err)
|
|
367
|
+
}
|
|
282
368
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
const res = this.sendReset()
|
|
290
|
-
|
|
291
|
-
if (isPromise(res)) {
|
|
292
|
-
await res
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
this.stat.timeline.reset = Date.now()
|
|
296
|
-
} catch (err) {
|
|
297
|
-
log.trace('%s stream %s error sending reset', this.stat.direction, this.id, err)
|
|
298
|
-
}
|
|
299
|
-
}
|
|
369
|
+
_closeSink (err?: Error): void {
|
|
370
|
+
// if the sink function is running, cause it to end
|
|
371
|
+
if (this.writeStatus === 'writing') {
|
|
372
|
+
this.log.trace('end sink source')
|
|
373
|
+
this.sinkController.abort()
|
|
374
|
+
}
|
|
300
375
|
|
|
376
|
+
this.onSinkEnd(err)
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
_closeSource (err?: Error): void {
|
|
380
|
+
// if the source is not ending, end it
|
|
381
|
+
if (this.readStatus !== 'closing' && this.readStatus !== 'closed') {
|
|
382
|
+
this.log.trace('ending source with %d bytes to be read by consumer', this.streamSource.readableLength)
|
|
383
|
+
this.readStatus = 'closing'
|
|
301
384
|
this.streamSource.end(err)
|
|
302
|
-
|
|
385
|
+
}
|
|
386
|
+
}
|
|
303
387
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
388
|
+
/**
|
|
389
|
+
* The remote closed for writing so we should expect to receive no more
|
|
390
|
+
* messages
|
|
391
|
+
*/
|
|
392
|
+
remoteCloseWrite (): void {
|
|
393
|
+
if (this.readStatus === 'closing' || this.readStatus === 'closed') {
|
|
394
|
+
this.log('received remote close write but local source is already closed')
|
|
395
|
+
return
|
|
307
396
|
}
|
|
308
397
|
|
|
309
|
-
|
|
310
|
-
|
|
398
|
+
this.log.trace('remote close write')
|
|
399
|
+
this._closeSource()
|
|
400
|
+
}
|
|
311
401
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
402
|
+
/**
|
|
403
|
+
* The remote closed for reading so we should not send any more
|
|
404
|
+
* messages
|
|
405
|
+
*/
|
|
406
|
+
remoteCloseRead (): void {
|
|
407
|
+
if (this.writeStatus === 'closing' || this.writeStatus === 'closed') {
|
|
408
|
+
this.log('received remote close read but local sink is already closed')
|
|
409
|
+
return
|
|
317
410
|
}
|
|
318
411
|
|
|
319
|
-
this.
|
|
412
|
+
this.log.trace('remote close read')
|
|
413
|
+
this._closeSink()
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* The underlying muxer has closed, no more messages can be sent or will
|
|
418
|
+
* be received, close immediately to free up resources
|
|
419
|
+
*/
|
|
420
|
+
destroy (): void {
|
|
421
|
+
if (this.status === 'closed' || this.status === 'aborted' || this.status === 'reset') {
|
|
422
|
+
this.log('received destroy but we are already closed')
|
|
423
|
+
return
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
this.log.trace('muxer destroyed')
|
|
427
|
+
|
|
428
|
+
this._closeSinkAndSource()
|
|
320
429
|
}
|
|
321
430
|
|
|
322
431
|
/**
|
|
@@ -339,27 +448,27 @@ export abstract class AbstractStream implements Stream {
|
|
|
339
448
|
* Send a message to the remote muxer informing them a new stream is being
|
|
340
449
|
* opened
|
|
341
450
|
*/
|
|
342
|
-
abstract sendNewStream (): void | Promise<void>
|
|
451
|
+
abstract sendNewStream (options?: AbortOptions): void | Promise<void>
|
|
343
452
|
|
|
344
453
|
/**
|
|
345
454
|
* Send a data message to the remote muxer
|
|
346
455
|
*/
|
|
347
|
-
abstract sendData (buf: Uint8ArrayList): void | Promise<void>
|
|
456
|
+
abstract sendData (buf: Uint8ArrayList, options?: AbortOptions): void | Promise<void>
|
|
348
457
|
|
|
349
458
|
/**
|
|
350
459
|
* Send a reset message to the remote muxer
|
|
351
460
|
*/
|
|
352
|
-
abstract sendReset (): void | Promise<void>
|
|
461
|
+
abstract sendReset (options?: AbortOptions): void | Promise<void>
|
|
353
462
|
|
|
354
463
|
/**
|
|
355
464
|
* Send a message to the remote muxer, informing them no more data messages
|
|
356
465
|
* will be sent by this end of the stream
|
|
357
466
|
*/
|
|
358
|
-
abstract sendCloseWrite (): void | Promise<void>
|
|
467
|
+
abstract sendCloseWrite (options?: AbortOptions): void | Promise<void>
|
|
359
468
|
|
|
360
469
|
/**
|
|
361
470
|
* Send a message to the remote muxer, informing them no more data messages
|
|
362
471
|
* will be read by this end of the stream
|
|
363
472
|
*/
|
|
364
|
-
abstract sendCloseRead (): void | Promise<void>
|
|
473
|
+
abstract sendCloseRead (options?: AbortOptions): void | Promise<void>
|
|
365
474
|
}
|
package/src/transport/index.ts
CHANGED
|
@@ -96,6 +96,12 @@ export interface UpgraderOptions {
|
|
|
96
96
|
skipEncryption?: boolean
|
|
97
97
|
skipProtection?: boolean
|
|
98
98
|
muxerFactory?: StreamMuxerFactory
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The passed MultiaddrConnection has limits place on duration and/or data
|
|
102
|
+
* transfer amounts so is not expected to be open for very long.
|
|
103
|
+
*/
|
|
104
|
+
transient?: boolean
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
export interface Upgrader {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/connection/status.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,IAAI,SAAS,CAAA;AAC1B,eAAO,MAAM,OAAO,YAAY,CAAA;AAChC,eAAO,MAAM,MAAM,WAAW,CAAA"}
|