werift 0.24.4 → 0.25.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.
- package/README.md +116 -113
- package/lib/common/src/transport.d.ts +22 -2
- package/lib/common/src/transport.js +84 -26
- package/lib/common/src/transport.js.map +1 -1
- package/lib/ice/src/exceptions.d.ts +9 -0
- package/lib/ice/src/exceptions.js +23 -1
- package/lib/ice/src/exceptions.js.map +1 -1
- package/lib/ice/src/ice.d.ts +40 -0
- package/lib/ice/src/ice.js +194 -28
- package/lib/ice/src/ice.js.map +1 -1
- package/lib/ice/src/iceBase.d.ts +26 -0
- package/lib/ice/src/iceBase.js.map +1 -1
- package/lib/ice/src/stun/const.d.ts +7 -0
- package/lib/ice/src/stun/const.js +8 -0
- package/lib/ice/src/stun/const.js.map +1 -1
- package/lib/ice/src/stun/protocol.js +1 -4
- package/lib/ice/src/stun/protocol.js.map +1 -1
- package/lib/ice/src/stun/tcpProtocol.d.ts +7 -1
- package/lib/ice/src/stun/tcpProtocol.js +65 -14
- package/lib/ice/src/stun/tcpProtocol.js.map +1 -1
- package/lib/ice/src/stun/transaction.d.ts +12 -1
- package/lib/ice/src/stun/transaction.js +37 -4
- package/lib/ice/src/stun/transaction.js.map +1 -1
- package/lib/ice/src/turn/protocol.d.ts +40 -15
- package/lib/ice/src/turn/protocol.js +141 -32
- package/lib/ice/src/turn/protocol.js.map +1 -1
- package/lib/ice/src/types/model.d.ts +8 -0
- package/lib/ice/src/types/model.js.map +1 -1
- package/lib/index.mjs +6175 -4073
- package/lib/nonstandard/index.mjs +286 -1003
- package/lib/polyfill/dom.mjs +23794 -0
- package/lib/polyfill/index.mjs +23794 -0
- package/lib/rtp/src/extra/container/mp4/container.js +12 -4
- package/lib/rtp/src/extra/container/mp4/container.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4.js +8 -3
- package/lib/rtp/src/extra/processor/mp4.js.map +1 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js +3 -1
- package/lib/rtp/src/extra/processor/mp4Callback.js.map +1 -1
- package/lib/sctp/src/chunk.d.ts +5 -0
- package/lib/sctp/src/chunk.js +16 -11
- package/lib/sctp/src/chunk.js.map +1 -1
- package/lib/sctp/src/index.d.ts +3 -1
- package/lib/sctp/src/index.js +10 -1
- package/lib/sctp/src/index.js.map +1 -1
- package/lib/sctp/src/sctp.d.ts +12 -3
- package/lib/sctp/src/sctp.js +51 -18
- package/lib/sctp/src/sctp.js.map +1 -1
- package/lib/webrtc/src/const.js +2 -0
- package/lib/webrtc/src/const.js.map +1 -1
- package/lib/webrtc/src/errors.d.ts +9 -1
- package/lib/webrtc/src/errors.js +19 -0
- package/lib/webrtc/src/errors.js.map +1 -1
- package/lib/webrtc/src/media/codec.d.ts +5 -0
- package/lib/webrtc/src/media/codec.js +21 -0
- package/lib/webrtc/src/media/codec.js.map +1 -1
- package/lib/webrtc/src/media/codecCompatibility.d.ts +23 -0
- package/lib/webrtc/src/media/codecCompatibility.js +138 -0
- package/lib/webrtc/src/media/codecCompatibility.js.map +1 -0
- package/lib/webrtc/src/media/index.d.ts +1 -0
- package/lib/webrtc/src/media/index.js +1 -0
- package/lib/webrtc/src/media/index.js.map +1 -1
- package/lib/webrtc/src/media/router.d.ts +2 -0
- package/lib/webrtc/src/media/router.js +23 -3
- package/lib/webrtc/src/media/router.js.map +1 -1
- package/lib/webrtc/src/media/rtpReceiver.d.ts +12 -0
- package/lib/webrtc/src/media/rtpReceiver.js +35 -0
- package/lib/webrtc/src/media/rtpReceiver.js.map +1 -1
- package/lib/webrtc/src/media/rtpSender.d.ts +65 -4
- package/lib/webrtc/src/media/rtpSender.js +264 -35
- package/lib/webrtc/src/media/rtpSender.js.map +1 -1
- package/lib/webrtc/src/media/rtpTransceiver.d.ts +42 -0
- package/lib/webrtc/src/media/rtpTransceiver.js +157 -4
- package/lib/webrtc/src/media/rtpTransceiver.js.map +1 -1
- package/lib/webrtc/src/media/track.d.ts +29 -1
- package/lib/webrtc/src/media/track.js +164 -5
- package/lib/webrtc/src/media/track.js.map +1 -1
- package/lib/webrtc/src/nonstandard/index.d.ts +0 -1
- package/lib/webrtc/src/nonstandard/index.js +0 -1
- package/lib/webrtc/src/nonstandard/index.js.map +1 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js +2 -1
- package/lib/webrtc/src/nonstandard/recorder/writer/webm.js.map +1 -1
- package/lib/webrtc/src/nonstandard/userMedia.d.ts +1 -2
- package/lib/webrtc/src/nonstandard/userMedia.js +30 -14
- package/lib/webrtc/src/nonstandard/userMedia.js.map +1 -1
- package/lib/webrtc/src/peerConnection.d.ts +126 -5
- package/lib/webrtc/src/peerConnection.js +609 -136
- package/lib/webrtc/src/peerConnection.js.map +1 -1
- package/lib/webrtc/src/polyfill/api.d.ts +14 -0
- package/lib/webrtc/src/polyfill/api.js +23 -0
- package/lib/webrtc/src/polyfill/api.js.map +1 -0
- package/lib/webrtc/src/polyfill/browserIdentity.d.ts +11 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js +59 -0
- package/lib/webrtc/src/polyfill/browserIdentity.js.map +1 -0
- package/lib/webrtc/src/polyfill/dom.d.ts +11 -0
- package/lib/webrtc/src/polyfill/dom.js +18 -0
- package/lib/webrtc/src/polyfill/dom.js.map +1 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.d.ts +2 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js +22 -0
- package/lib/webrtc/src/polyfill/existingMediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/globals.d.ts +28 -0
- package/lib/webrtc/src/polyfill/globals.js +3 -0
- package/lib/webrtc/src/polyfill/globals.js.map +1 -0
- package/lib/webrtc/src/polyfill/index.d.ts +2 -0
- package/lib/webrtc/src/polyfill/index.js +19 -0
- package/lib/webrtc/src/polyfill/index.js.map +1 -0
- package/lib/webrtc/src/polyfill/install.d.ts +13 -0
- package/lib/webrtc/src/polyfill/install.js +266 -0
- package/lib/webrtc/src/polyfill/install.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaDevices.d.ts +38 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js +228 -0
- package/lib/webrtc/src/polyfill/mediaDevices.js.map +1 -0
- package/lib/webrtc/src/polyfill/mediaRegister.d.ts +51 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js +14 -0
- package/lib/webrtc/src/polyfill/mediaRegister.js.map +1 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.d.ts +3 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js +52 -0
- package/lib/webrtc/src/polyfill/peerConnectionConfig.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/callback.d.ts +16 -0
- package/lib/webrtc/src/polyfill/registers/callback.js +57 -0
- package/lib/webrtc/src/polyfill/registers/callback.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/empty.d.ts +2 -0
- package/lib/webrtc/src/polyfill/registers/empty.js +28 -0
- package/lib/webrtc/src/polyfill/registers/empty.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.d.ts +36 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js +242 -0
- package/lib/webrtc/src/polyfill/registers/mp4Webm.js.map +1 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.d.ts +17 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js +143 -0
- package/lib/webrtc/src/polyfill/registers/rtpRtcp.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.d.ts +18 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js +36 -0
- package/lib/webrtc/src/polyfill/rtcSessionDescription.js.map +1 -0
- package/lib/webrtc/src/polyfill/rtpCodec.d.ts +17 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js +93 -0
- package/lib/webrtc/src/polyfill/rtpCodec.js.map +1 -0
- package/lib/webrtc/src/polyfill/selectSettings.d.ts +31 -0
- package/lib/webrtc/src/polyfill/selectSettings.js +156 -0
- package/lib/webrtc/src/polyfill/selectSettings.js.map +1 -0
- package/lib/webrtc/src/polyfill/sourceIo.d.ts +21 -0
- package/lib/webrtc/src/polyfill/sourceIo.js +298 -0
- package/lib/webrtc/src/polyfill/sourceIo.js.map +1 -0
- package/lib/webrtc/src/polyfill/trackStop.d.ts +4 -0
- package/lib/webrtc/src/polyfill/trackStop.js +16 -0
- package/lib/webrtc/src/polyfill/trackStop.js.map +1 -0
- package/lib/webrtc/src/sctpManager.d.ts +2 -1
- package/lib/webrtc/src/sctpManager.js +5 -2
- package/lib/webrtc/src/sctpManager.js.map +1 -1
- package/lib/webrtc/src/sdp.d.ts +1 -1
- package/lib/webrtc/src/sdp.js +5 -6
- package/lib/webrtc/src/sdp.js.map +1 -1
- package/lib/webrtc/src/sdpManager.d.ts +38 -1
- package/lib/webrtc/src/sdpManager.js +236 -30
- package/lib/webrtc/src/sdpManager.js.map +1 -1
- package/lib/webrtc/src/secureTransportManager.d.ts +43 -12
- package/lib/webrtc/src/secureTransportManager.js +123 -47
- package/lib/webrtc/src/secureTransportManager.js.map +1 -1
- package/lib/webrtc/src/transceiverManager.d.ts +91 -6
- package/lib/webrtc/src/transceiverManager.js +477 -62
- package/lib/webrtc/src/transceiverManager.js.map +1 -1
- package/lib/webrtc/src/transport/ice.d.ts +8 -0
- package/lib/webrtc/src/transport/ice.js +17 -1
- package/lib/webrtc/src/transport/ice.js.map +1 -1
- package/lib/webrtc/src/transport/sctp.d.ts +3 -2
- package/lib/webrtc/src/transport/sctp.js +8 -2
- package/lib/webrtc/src/transport/sctp.js.map +1 -1
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# werift
|
|
2
2
|
|
|
3
|
-
werift (**We**b**
|
|
3
|
+
werift (**We**b**R**TC **I**mplementation **f**or **T**ypeScript) is a WebRTC implementation for Node.js written in TypeScript with a browser-compatible WebRTC API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
For the project overview, current features, examples, architecture, and interoperability information, see the [repository README](../../README.md).
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Install
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
```sh
|
|
10
|
+
npm install werift
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Browser-compatible WebRTC API
|
|
14
|
+
|
|
15
|
+
werift is designed so application code can use the familiar browser WebRTC model in Node.js: `RTCPeerConnection`, tracks and transceivers, `RTCDataChannel`, standard events, ICE configuration, offer/answer negotiation, and `getStats()`.
|
|
16
|
+
|
|
17
|
+
A small number of intentional or known edge-case differences remain for backward compatibility or unsupported legacy APIs. See [Browser API compatibility](../../docs/browser-api-compatibility.md) for those differences and the WPT strategy used to track exact browser behavior.
|
|
10
18
|
|
|
11
19
|
## Development setup
|
|
12
20
|
|
|
@@ -23,6 +31,8 @@ npm run wpt --workspace packages/webrtc
|
|
|
23
31
|
npm run wpt:coverage --workspace packages/webrtc
|
|
24
32
|
```
|
|
25
33
|
|
|
34
|
+
WPT reports use `v8-to-istanbul` directly to retain the V8 metrics used by the committed coverage baseline, independently of Vitest's AST-based coverage provider. Only observed TypeScript sources and source-mapped lines are measured.
|
|
35
|
+
|
|
26
36
|
Refresh the committed baselines when intentionally expanding upstream coverage:
|
|
27
37
|
|
|
28
38
|
```sh
|
|
@@ -30,133 +40,126 @@ npm run wpt --workspace packages/webrtc -- --update-baseline
|
|
|
30
40
|
WPT_UPDATE_COVERAGE_BASELINE=1 npm run wpt:coverage --workspace packages/webrtc
|
|
31
41
|
```
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
## Rejected, stopped and reused m-lines
|
|
34
44
|
|
|
35
|
-
|
|
36
|
-
- [API Reference](https://shinyoshiaki.github.io/werift-webrtc/website/build/docs/api)
|
|
45
|
+
A remote offer can contain audio/video sections that the local `codecs` cannot handle. `setRemoteDescription()` still succeeds and the answer rejects only those sections with port 0 at the same position (Issue #705). For example, an audio-only peer can answer a browser offer that bundles video without adding VP8:
|
|
37
46
|
|
|
38
|
-
|
|
47
|
+
```ts
|
|
48
|
+
const pc = new RTCPeerConnection({
|
|
49
|
+
codecs: { audio: [useOPUS()], video: [] },
|
|
50
|
+
});
|
|
51
|
+
await pc.setRemoteDescription(browserOffer); // audio + video in BUNDLE
|
|
52
|
+
await pc.setLocalDescription(await pc.createAnswer()); // video: m=video 0 ...
|
|
53
|
+
```
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
`mLineReuse` selects how inactive and stopped m-lines are written. It is fixed at construction time.
|
|
41
56
|
|
|
42
|
-
|
|
57
|
+
```ts
|
|
58
|
+
new RTCPeerConnection(); // mLineReuse: "compatible" (default)
|
|
59
|
+
new RTCPeerConnection({ mLineReuse: "aggressive" }); // legacy: inactive also uses port 0
|
|
60
|
+
```
|
|
43
61
|
|
|
44
|
-
|
|
62
|
+
| `mLineReuse` | accepted `inactive` | rejected / stopped |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| `"compatible"` (default) | non-zero port | port 0 |
|
|
65
|
+
| `"aggressive"` | port 0 | port 0 |
|
|
66
|
+
|
|
67
|
+
With `"aggressive"`, the remote side (browsers included) treats an inactive port 0 m-line as rejected, so once it is negotiated the transceiver becomes `stopped` and cannot be resumed by setting `direction` back to `"sendrecv"`. Add a new transceiver instead; it reuses that position. This differs from older werift versions. Use the default `"compatible"` if you need to pause and resume with `inactive`.
|
|
68
|
+
|
|
69
|
+
In `"compatible"`, `inactive` m-lines are kept and not reused. To reuse an m-line position, release it explicitly: call `transceiver.stop()` on the side that owns the track (in the browser, after `pc.removeTrack(sender)`) and renegotiate. The m-line is negotiated as port 0 and both sides stop it, then the next `addTransceiver()` / `addTrack()` of the same kind (browser or werift) takes that position with a new MID, so the number of m-lines does not grow. Choose `"aggressive"` only when you cannot change the remote side to call `stop()`.
|
|
70
|
+
|
|
71
|
+
- Rejected (`transceiver.rejected`): no common codec or remote port 0. No sender/receiver pipeline, router registration, `ontrack` or TWCC is set up for it.
|
|
72
|
+
- Stopped: `transceiver.stop()` releases media immediately and is negotiated as port 0 in the next local offer; `transceiver.stopped` becomes `true` when the answer is applied. An answerer that calls `stop()` answers `inactive` first and negotiates the stop in its own next offer.
|
|
73
|
+
- Reused: after the port 0 negotiation completes, `addTransceiver()` of the same kind takes that position with a new MID and a new transceiver, so the number of m-lines does not grow. Positions that are only stopping are not reused.
|
|
74
|
+
- `removeTrack(sender)` only detaches the track. `sender.replaceTrack(track)` plus `transceiver.direction = "sendrecv"` resumes sending on the same sender.
|
|
75
|
+
|
|
76
|
+
See [the design note](../../docs/design/705-media-rejection-and-removetrack.md) for BUNDLE, ICE candidate and rollback details.
|
|
77
|
+
|
|
78
|
+
## Documentation
|
|
79
|
+
|
|
80
|
+
- [Website](https://shinyoshiaki.github.io/werift-webrtc/website/build/)
|
|
81
|
+
- [API Reference](https://shinyoshiaki.github.io/werift-webrtc/website/build/docs/api)
|
|
82
|
+
- [Examples](../../examples)
|
|
83
|
+
- [Polyfill guide](../../docs/polyfill/README.md)
|
|
84
|
+
- [Browser API compatibility differences](../../docs/browser-api-compatibility.md)
|
|
45
85
|
|
|
46
|
-
|
|
86
|
+
## Demos
|
|
47
87
|
|
|
48
|
-
|
|
88
|
+
### MediaChannel
|
|
89
|
+
|
|
90
|
+
From the repository root:
|
|
49
91
|
|
|
50
92
|
```sh
|
|
51
|
-
|
|
93
|
+
npm run media
|
|
52
94
|
```
|
|
53
95
|
|
|
54
|
-
|
|
96
|
+
Open:
|
|
97
|
+
|
|
55
98
|
https://shinyoshiaki.github.io/werift-webrtc/examples/mediachannel/pubsub/answer
|
|
56
99
|
|
|
57
|
-
|
|
100
|
+
Use the browser console and `chrome://webrtc-internals/` for inspection.
|
|
58
101
|
|
|
59
|
-
|
|
102
|
+
### DataChannel
|
|
60
103
|
|
|
61
|
-
|
|
104
|
+
From the repository root:
|
|
62
105
|
|
|
63
106
|
```sh
|
|
64
|
-
|
|
107
|
+
npm run datachannel
|
|
65
108
|
```
|
|
66
109
|
|
|
67
|
-
|
|
110
|
+
Open:
|
|
111
|
+
|
|
68
112
|
https://shinyoshiaki.github.io/werift-webrtc/examples/datachannel/answer
|
|
69
113
|
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
- [ ]
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
## Road Map Towards 2.0
|
|
124
|
-
|
|
125
|
-
- [ ] API compatible with browser RTCPeerConnection
|
|
126
|
-
- [ ] ICE
|
|
127
|
-
- [ ] ICE restart
|
|
128
|
-
- [ ] SDP
|
|
129
|
-
- [ ] reuse inactive m-line
|
|
130
|
-
- [ ] Simulcast
|
|
131
|
-
- [ ] send
|
|
132
|
-
- [ ] support more cipher suites
|
|
133
|
-
|
|
134
|
-
## RTCPeerConnection W3C compatibility notes
|
|
135
|
-
|
|
136
|
-
API reference markdown can be regenerated with `cd packages/webrtc && npm run doc`.
|
|
137
|
-
For this task, the reviewable compatibility notes live in this README and in
|
|
138
|
-
`src/peerConnection.ts`; the generated `packages/webrtc/doc/` output is not
|
|
139
|
-
tracked in git, so it is not committed as part of this change.
|
|
140
|
-
|
|
141
|
-
| Status | API | Notes |
|
|
142
|
-
| --- | --- | --- |
|
|
143
|
-
| Added | `currentLocalDescription`, `pendingLocalDescription`, `currentRemoteDescription`, `pendingRemoteDescription`, `canTrickleIceCandidates`, `sctp` | Public getters now follow W3C-style pending/current description visibility and expose SCTP/canTrickle state. |
|
|
144
|
-
| Added | `setLocalDescription()` input compatibility | Accepts omitted `type`, empty `sdp`, and provisional `pranswer`. |
|
|
145
|
-
| Added | `setRemoteDescription()` input compatibility | Accepts `pranswer` and `rollback`, updating pending/current descriptions accordingly. |
|
|
146
|
-
| Added | `addIceCandidate()` input compatibility | Accepts omitted input, `null`, and `{ candidate: "" }` as end-of-candidates, validates `sdpMid` / `sdpMLineIndex` / `usernameFragment`, updates the matching remote m-section, rejects calls before `remoteDescription` is set, and rejects malformed candidate strings. |
|
|
147
|
-
| Added | `RTCConfiguration` compatibility | Accepts `iceServers`, `iceTransportPolicy`, `bundlePolicy`, `rtcpMuxPolicy: "require"`, `iceCandidatePoolSize: 0`, and `certificates`; `setConfiguration(getConfiguration())` round-trips without changing certificates. |
|
|
148
|
-
| Deferred | `bundlePolicy: "balanced"` round-trip | `"balanced"` is accepted for input compatibility, but it is internally normalized to werift's `"max-compat"` behavior, so `getConfiguration()` returns `"max-compat"`. |
|
|
149
|
-
| Added | `RTCIceServer.urls: string \| string[]` | Arrays are accepted and parsed in order. |
|
|
150
|
-
| Added | Standard event names | `signalingstatechange`, `iceconnectionstatechange`, `icegatheringstatechange`, `connectionstatechange`, `negotiationneeded`, `icecandidate`, `track`, and `datachannel` are emitted for `addEventListener`. |
|
|
151
|
-
| Not implemented | Legacy callback overloads | Kept out of scope because they are legacy browser APIs. |
|
|
152
|
-
| Not implemented | `addStream`, `removeStream`, `createDTMFSender` | These are obsolete; use `addTrack`, `removeTrack`, and transceiver/sender APIs instead. |
|
|
153
|
-
| Deferred | `close()` return type | Remains async for backward compatibility even though W3C defines synchronous `undefined`. |
|
|
154
|
-
| Deferred | `setLocalDescription()` return type | Non-rollback calls still return the applied `SessionDescription` instead of `Promise<void>` for backward compatibility; the local `rollback` path resolves with `undefined`. |
|
|
155
|
-
| Compatible | `setRemoteDescription()` return type | `setRemoteDescription()` resolves `Promise<void>` like the W3C API. |
|
|
156
|
-
| Deferred | `RTCPeerConnection.generateCertificate()` | `RTCCertificate` and `RTCConfiguration.certificates` are supported, but the static W3C helper is still optional work. |
|
|
157
|
-
|
|
158
|
-
# reference
|
|
159
|
-
|
|
160
|
-
- aiortc https://github.com/aiortc/aiortc
|
|
161
|
-
- pion/webrtc https://github.com/pion/webrtc
|
|
162
|
-
- etc ....
|
|
114
|
+
The outbound SCTP packet MTU can be configured independently from the
|
|
115
|
+
negotiated DataChannel message-size limit:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const peerConnection = new RTCPeerConnection({
|
|
119
|
+
sctp: { mtu: 1052 },
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`sctp.mtu` defaults to 1191 bytes (a maximum DATA payload of 1160 bytes per
|
|
124
|
+
fragment). It cannot be changed to a different value after the SCTP transport
|
|
125
|
+
has been created.
|
|
126
|
+
|
|
127
|
+
## Current implementation highlights
|
|
128
|
+
|
|
129
|
+
- Browser-compatible `RTCPeerConnection` API and standard WebRTC events
|
|
130
|
+
- STUN and TURN relay support, including TURN control transports over UDP, TCP, and TLS
|
|
131
|
+
- Full ICE, trickle ICE, ICE-Lite support/interoperability, ICE restart, and ICE-TCP
|
|
132
|
+
- DTLS-SRTP, SRTP, and SRTCP
|
|
133
|
+
- DataChannel over SCTP/DTLS
|
|
134
|
+
- Media sendonly / recvonly / sendrecv and multiple tracks
|
|
135
|
+
- RTP/RTCP feedback including SR/RR, PLI, REMB, Generic NACK, and Transport-Wide CC
|
|
136
|
+
- RTX and RED
|
|
137
|
+
- Receive-side simulcast
|
|
138
|
+
- Sender-side bandwidth estimation
|
|
139
|
+
- Browser-compatible `getStats()` reporting
|
|
140
|
+
- Compatibility validation backed by an allowlisted upstream WPT runner
|
|
141
|
+
|
|
142
|
+
See the [repository README](../../README.md#protocol-coverage-at-a-glance) for the broader feature checklist.
|
|
143
|
+
|
|
144
|
+
## Interoperability
|
|
145
|
+
|
|
146
|
+
The repository contains Chromium-focused browser E2E tests and a Firefox test runner. Safari interoperability is also community-verified: users have reported extensive real-world use with Safari in [Issue #346](https://github.com/shinyoshiaki/werift-webrtc/issues/346). Safari is not currently part of the automated browser E2E matrix, so this is community validation rather than a CI guarantee.
|
|
147
|
+
|
|
148
|
+
werift also participates in the independent [`sipsorcery/webrtc-interop`](https://github.com/sipsorcery/webrtc-interop) Peer Connection and Data Channel Echo matrices.
|
|
149
|
+
|
|
150
|
+
## Roadmap
|
|
151
|
+
|
|
152
|
+
Current work is focused on:
|
|
153
|
+
|
|
154
|
+
- improving documentation and WPT coverage
|
|
155
|
+
- closing remaining documented browser API edge-case differences
|
|
156
|
+
- simulcast send support
|
|
157
|
+
- additional cipher suites
|
|
158
|
+
- richer WebRTC statistics coverage
|
|
159
|
+
- continued unit, E2E, interoperability, and long-running reliability testing
|
|
160
|
+
|
|
161
|
+
## References
|
|
162
|
+
|
|
163
|
+
- [aiortc](https://github.com/aiortc/aiortc)
|
|
164
|
+
- [Pion WebRTC](https://github.com/pion/webrtc)
|
|
165
|
+
- [sipsorcery/webrtc-interop](https://github.com/sipsorcery/webrtc-interop)
|
|
@@ -4,6 +4,10 @@ import * as tls from "node:tls";
|
|
|
4
4
|
import { type AddressInfo } from "node:net";
|
|
5
5
|
import { type Address, type InterfaceAddresses } from "./network";
|
|
6
6
|
export type TlsConnectionOptions = Omit<tls.ConnectionOptions, "host" | "port" | "socket">;
|
|
7
|
+
export interface StreamTransportOptions {
|
|
8
|
+
/** Maximum time to wait for TCP/TLS connection establishment, in milliseconds. */
|
|
9
|
+
connectTimeoutMs?: number;
|
|
10
|
+
}
|
|
7
11
|
export declare class UdpTransport implements Transport {
|
|
8
12
|
private socketType;
|
|
9
13
|
private options;
|
|
@@ -21,6 +25,8 @@ export declare class UdpTransport implements Transport {
|
|
|
21
25
|
private init;
|
|
22
26
|
send: (data: Buffer, addr?: Address) => Promise<void>;
|
|
23
27
|
get address(): net.AddressInfo;
|
|
28
|
+
/** IP family of the bound socket: 4 for udp4, 6 for udp6. */
|
|
29
|
+
get addressFamily(): IpAddressFamily;
|
|
24
30
|
get host(): string;
|
|
25
31
|
get port(): number;
|
|
26
32
|
close: () => Promise<void>;
|
|
@@ -29,9 +35,10 @@ export declare class TcpTransport implements Transport {
|
|
|
29
35
|
readonly type: "tcp";
|
|
30
36
|
private readonly stream;
|
|
31
37
|
private constructor();
|
|
32
|
-
static init(addr: Address): Promise<TcpTransport>;
|
|
38
|
+
static init(addr: Address, options?: StreamTransportOptions): Promise<TcpTransport>;
|
|
33
39
|
private init;
|
|
34
40
|
get address(): net.AddressInfo;
|
|
41
|
+
get remoteAddress(): readonly [string, number] | undefined;
|
|
35
42
|
get closed(): boolean;
|
|
36
43
|
get onData(): (data: Buffer, addr: Address) => void;
|
|
37
44
|
set onData(handler: (data: Buffer, addr: Address) => void);
|
|
@@ -42,15 +49,17 @@ export declare class TlsTransport implements Transport {
|
|
|
42
49
|
readonly type: "tls";
|
|
43
50
|
private readonly stream;
|
|
44
51
|
private constructor();
|
|
45
|
-
static init(addr: Address, options?: TlsConnectionOptions): Promise<TlsTransport>;
|
|
52
|
+
static init(addr: Address, options?: TlsConnectionOptions, streamOptions?: StreamTransportOptions): Promise<TlsTransport>;
|
|
46
53
|
private init;
|
|
47
54
|
get address(): net.AddressInfo;
|
|
55
|
+
get remoteAddress(): readonly [string, number] | undefined;
|
|
48
56
|
get closed(): boolean;
|
|
49
57
|
get onData(): (data: Buffer, addr: Address) => void;
|
|
50
58
|
set onData(handler: (data: Buffer, addr: Address) => void);
|
|
51
59
|
send: (data: Buffer, addr?: Address) => Promise<void>;
|
|
52
60
|
close: () => Promise<void>;
|
|
53
61
|
}
|
|
62
|
+
export type IpAddressFamily = 4 | 6;
|
|
54
63
|
export interface Transport {
|
|
55
64
|
type: string;
|
|
56
65
|
address: AddressInfo;
|
|
@@ -58,4 +67,15 @@ export interface Transport {
|
|
|
58
67
|
onData: (data: Buffer, addr: Address) => void;
|
|
59
68
|
send: (data: Buffer, addr?: Address) => Promise<void>;
|
|
60
69
|
close: () => Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* IP family of a datagram socket. A datagram transport can only reach
|
|
72
|
+
* addresses of this family. Built-in UDP transports always set it; a custom
|
|
73
|
+
* transport that leaves it unset gets no family preference.
|
|
74
|
+
*/
|
|
75
|
+
addressFamily?: IpAddressFamily;
|
|
76
|
+
/**
|
|
77
|
+
* The peer a connected (stream) transport is talking to. Responses arrive
|
|
78
|
+
* from this address. Built-in TCP/TLS transports set it once connected.
|
|
79
|
+
*/
|
|
80
|
+
remoteAddress?: Address;
|
|
61
81
|
}
|
|
@@ -41,6 +41,7 @@ const node_net_1 = require("node:net");
|
|
|
41
41
|
const log_1 = require("./log");
|
|
42
42
|
const network_1 = require("./network");
|
|
43
43
|
const log = (0, log_1.debug)("werift-ice:packages/ice/src/transport.ts");
|
|
44
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 8000;
|
|
44
45
|
class UdpTransport {
|
|
45
46
|
constructor(socketType, options = {}) {
|
|
46
47
|
Object.defineProperty(this, "socketType", {
|
|
@@ -163,6 +164,10 @@ class UdpTransport {
|
|
|
163
164
|
get address() {
|
|
164
165
|
return this.socket.address();
|
|
165
166
|
}
|
|
167
|
+
/** IP family of the bound socket: 4 for udp4, 6 for udp6. */
|
|
168
|
+
get addressFamily() {
|
|
169
|
+
return this.socketType === "udp6" ? 6 : 4;
|
|
170
|
+
}
|
|
166
171
|
get host() {
|
|
167
172
|
return this.socket.address().address;
|
|
168
173
|
}
|
|
@@ -172,7 +177,7 @@ class UdpTransport {
|
|
|
172
177
|
}
|
|
173
178
|
exports.UdpTransport = UdpTransport;
|
|
174
179
|
class TcpTransport {
|
|
175
|
-
constructor(addr) {
|
|
180
|
+
constructor(addr, options = {}) {
|
|
176
181
|
Object.defineProperty(this, "type", {
|
|
177
182
|
enumerable: true,
|
|
178
183
|
configurable: true,
|
|
@@ -201,12 +206,18 @@ class TcpTransport {
|
|
|
201
206
|
await this.stream.close();
|
|
202
207
|
}
|
|
203
208
|
});
|
|
204
|
-
this.stream = new StreamTransport("tcp", () => (0, node_net_1.connect)({ port: addr[1], host: addr[0] }));
|
|
209
|
+
this.stream = new StreamTransport("tcp", () => (0, node_net_1.connect)({ port: addr[1], host: addr[0] }), undefined, options.connectTimeoutMs);
|
|
205
210
|
}
|
|
206
|
-
static async init(addr) {
|
|
207
|
-
const transport = new TcpTransport(addr);
|
|
208
|
-
|
|
209
|
-
|
|
211
|
+
static async init(addr, options = {}) {
|
|
212
|
+
const transport = new TcpTransport(addr, options);
|
|
213
|
+
try {
|
|
214
|
+
await transport.init();
|
|
215
|
+
return transport;
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
await transport.close();
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
210
221
|
}
|
|
211
222
|
async init() {
|
|
212
223
|
await this.stream.waitForConnect();
|
|
@@ -214,6 +225,9 @@ class TcpTransport {
|
|
|
214
225
|
get address() {
|
|
215
226
|
return this.stream.address;
|
|
216
227
|
}
|
|
228
|
+
get remoteAddress() {
|
|
229
|
+
return this.stream.remoteAddress;
|
|
230
|
+
}
|
|
217
231
|
get closed() {
|
|
218
232
|
return this.stream.closed;
|
|
219
233
|
}
|
|
@@ -226,7 +240,7 @@ class TcpTransport {
|
|
|
226
240
|
}
|
|
227
241
|
exports.TcpTransport = TcpTransport;
|
|
228
242
|
class TlsTransport {
|
|
229
|
-
constructor(addr, options = {}) {
|
|
243
|
+
constructor(addr, options = {}, streamOptions = {}) {
|
|
230
244
|
Object.defineProperty(this, "type", {
|
|
231
245
|
enumerable: true,
|
|
232
246
|
configurable: true,
|
|
@@ -259,12 +273,18 @@ class TlsTransport {
|
|
|
259
273
|
...options,
|
|
260
274
|
host: addr[0],
|
|
261
275
|
port: addr[1],
|
|
262
|
-
}));
|
|
276
|
+
}), undefined, streamOptions.connectTimeoutMs);
|
|
263
277
|
}
|
|
264
|
-
static async init(addr, options = {}) {
|
|
265
|
-
const transport = new TlsTransport(addr, options);
|
|
266
|
-
|
|
267
|
-
|
|
278
|
+
static async init(addr, options = {}, streamOptions = {}) {
|
|
279
|
+
const transport = new TlsTransport(addr, options, streamOptions);
|
|
280
|
+
try {
|
|
281
|
+
await transport.init();
|
|
282
|
+
return transport;
|
|
283
|
+
}
|
|
284
|
+
catch (error) {
|
|
285
|
+
await transport.close();
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
268
288
|
}
|
|
269
289
|
async init() {
|
|
270
290
|
await this.stream.waitForConnect();
|
|
@@ -272,6 +292,9 @@ class TlsTransport {
|
|
|
272
292
|
get address() {
|
|
273
293
|
return this.stream.address;
|
|
274
294
|
}
|
|
295
|
+
get remoteAddress() {
|
|
296
|
+
return this.stream.remoteAddress;
|
|
297
|
+
}
|
|
275
298
|
get closed() {
|
|
276
299
|
return this.stream.closed;
|
|
277
300
|
}
|
|
@@ -286,7 +309,7 @@ exports.TlsTransport = TlsTransport;
|
|
|
286
309
|
class StreamTransport {
|
|
287
310
|
constructor(type, createClient, connectEvent = type === "tls"
|
|
288
311
|
? "secureConnect"
|
|
289
|
-
: "connect") {
|
|
312
|
+
: "connect", connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS) {
|
|
290
313
|
Object.defineProperty(this, "createClient", {
|
|
291
314
|
enumerable: true,
|
|
292
315
|
configurable: true,
|
|
@@ -299,6 +322,12 @@ class StreamTransport {
|
|
|
299
322
|
writable: true,
|
|
300
323
|
value: connectEvent
|
|
301
324
|
});
|
|
325
|
+
Object.defineProperty(this, "connectTimeoutMs", {
|
|
326
|
+
enumerable: true,
|
|
327
|
+
configurable: true,
|
|
328
|
+
writable: true,
|
|
329
|
+
value: connectTimeoutMs
|
|
330
|
+
});
|
|
302
331
|
Object.defineProperty(this, "type", {
|
|
303
332
|
enumerable: true,
|
|
304
333
|
configurable: true,
|
|
@@ -329,6 +358,12 @@ class StreamTransport {
|
|
|
329
358
|
writable: true,
|
|
330
359
|
value: false
|
|
331
360
|
});
|
|
361
|
+
Object.defineProperty(this, "rejectConnecting", {
|
|
362
|
+
enumerable: true,
|
|
363
|
+
configurable: true,
|
|
364
|
+
writable: true,
|
|
365
|
+
value: void 0
|
|
366
|
+
});
|
|
332
367
|
Object.defineProperty(this, "send", {
|
|
333
368
|
enumerable: true,
|
|
334
369
|
configurable: true,
|
|
@@ -353,6 +388,7 @@ class StreamTransport {
|
|
|
353
388
|
writable: true,
|
|
354
389
|
value: async () => {
|
|
355
390
|
this.closed = true;
|
|
391
|
+
this.rejectConnecting?.(new Error(`${this.type} transport closed`));
|
|
356
392
|
this.client?.destroy();
|
|
357
393
|
}
|
|
358
394
|
});
|
|
@@ -368,27 +404,37 @@ class StreamTransport {
|
|
|
368
404
|
}
|
|
369
405
|
const client = this.createClient();
|
|
370
406
|
this.client = client;
|
|
371
|
-
this.connecting = new Promise((
|
|
372
|
-
|
|
407
|
+
this.connecting = new Promise((resolve, reject) => {
|
|
408
|
+
let settled = false;
|
|
409
|
+
const settle = (error) => {
|
|
410
|
+
if (settled)
|
|
411
|
+
return;
|
|
412
|
+
settled = true;
|
|
413
|
+
clearTimeout(timer);
|
|
414
|
+
client.off(this.connectEvent, onConnect);
|
|
373
415
|
client.off("error", onConnectError);
|
|
374
|
-
|
|
416
|
+
this.rejectConnecting = undefined;
|
|
417
|
+
error ? reject(error) : resolve();
|
|
418
|
+
};
|
|
419
|
+
const onConnect = () => {
|
|
420
|
+
settle();
|
|
375
421
|
};
|
|
376
422
|
const onConnectError = (error) => {
|
|
377
|
-
|
|
378
|
-
|
|
423
|
+
this.closed = true;
|
|
424
|
+
settle(error);
|
|
425
|
+
client.destroy();
|
|
379
426
|
};
|
|
427
|
+
const timer = setTimeout(() => {
|
|
428
|
+
this.closed = true;
|
|
429
|
+
settle(new Error(`${this.type} connect timed out after ${this.connectTimeoutMs}ms`));
|
|
430
|
+
client.destroy();
|
|
431
|
+
}, this.connectTimeoutMs);
|
|
432
|
+
this.rejectConnecting = (error) => settle(error);
|
|
380
433
|
client.once(this.connectEvent, onConnect);
|
|
381
434
|
client.once("error", onConnectError);
|
|
382
435
|
});
|
|
383
436
|
client.on("data", (data) => {
|
|
384
|
-
|
|
385
|
-
this.client.remoteAddress,
|
|
386
|
-
this.client.remotePort,
|
|
387
|
-
];
|
|
388
|
-
this.onData(data, addr);
|
|
389
|
-
});
|
|
390
|
-
client.on("end", () => {
|
|
391
|
-
this.connect();
|
|
437
|
+
this.onData(data, this.remoteAddress);
|
|
392
438
|
});
|
|
393
439
|
client.on("error", (error) => {
|
|
394
440
|
log(`${this.type} transport error`, error);
|
|
@@ -400,5 +446,17 @@ class StreamTransport {
|
|
|
400
446
|
get address() {
|
|
401
447
|
return {};
|
|
402
448
|
}
|
|
449
|
+
/** The peer the stream is connected to, once connected. */
|
|
450
|
+
get remoteAddress() {
|
|
451
|
+
const { remoteAddress, remotePort } = this.client;
|
|
452
|
+
if (!remoteAddress || !remotePort) {
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
return [stripZoneId(remoteAddress), remotePort];
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
/** Strip an IPv6 zone identifier, e.g. fe80::1%eth0 -> fe80::1. */
|
|
459
|
+
function stripZoneId(address) {
|
|
460
|
+
return address.split("%")[0];
|
|
403
461
|
}
|
|
404
462
|
//# sourceMappingURL=transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../common/src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RemoteInfo,\n type Socket,\n type SocketType,\n createSocket,\n} from \"dgram\";\n\nimport * as net from \"node:net\";\nimport * as tls from \"node:tls\";\n\nimport { type AddressInfo, type Socket as TcpSocket, connect } from \"node:net\";\nimport { debug } from \"./log\";\nimport {\n type Address,\n type InterfaceAddresses,\n findPort,\n interfaceAddress,\n normalizeFamilyNodeV18,\n} from \"./network\";\n\nconst log = debug(\"werift-ice:packages/ice/src/transport.ts\");\n\ntype StreamTransportType = \"tcp\" | \"tls\";\ntype StreamSocket = TcpSocket | tls.TLSSocket;\ntype StreamConnectEvent = \"connect\" | \"secureConnect\";\n\nexport type TlsConnectionOptions = Omit<\n tls.ConnectionOptions,\n \"host\" | \"port\" | \"socket\"\n>;\n\nexport class UdpTransport implements Transport {\n readonly type = \"udp\";\n readonly socket: Socket;\n rinfo?: Partial<Pick<RemoteInfo, \"address\" | \"port\">>;\n onData: (data: Buffer, addr: Address) => void = () => {};\n closed: boolean = false;\n\n private constructor(\n private socketType: SocketType,\n private options: {\n portRange?: [number, number];\n interfaceAddresses?: InterfaceAddresses;\n port?: number;\n } = {},\n ) {\n this.socket = createSocket(socketType);\n this.socket.on(\"message\", (data, info) => {\n if (normalizeFamilyNodeV18(info.family) === 6) {\n [info.address] = info.address.split(\"%\"); // example fe80::1d3a:8751:4ffd:eb80%wlp82s0\n }\n this.rinfo = info;\n try {\n this.onData(data, [info.address, info.port]);\n } catch (error) {\n log(\"onData error\", error);\n }\n });\n }\n\n static async init(\n type: SocketType,\n options: {\n portRange?: [number, number];\n port?: number;\n interfaceAddresses?: InterfaceAddresses;\n } = {},\n ) {\n const transport = new UdpTransport(type, options);\n await transport.init();\n return transport;\n }\n\n private async init() {\n const address = interfaceAddress(\n this.socketType,\n this.options.interfaceAddresses,\n );\n if (this.options.port) {\n this.socket.bind({ port: this.options.port, address });\n } else if (this.options.portRange) {\n const port = await findPort(\n this.options.portRange[0],\n this.options.portRange[1],\n this.socketType,\n this.options.interfaceAddresses,\n );\n this.socket.bind({ port, address });\n } else {\n this.socket.bind({ address });\n }\n await new Promise((r) => this.socket.once(\"listening\", r));\n }\n\n send = async (data: Buffer, addr?: Address) => {\n if (addr && !net.isIP(addr[0])) {\n // if address is not resolved, need to use send callback to handle dns failure.\n return new Promise<void>((r, f) => {\n this.socket.send(data, addr![1], addr![0], (error) => {\n if (error) {\n log(\"send error\", addr, data);\n f(error);\n } else {\n r();\n }\n });\n });\n } else {\n addr = addr ?? [this.rinfo?.address!, this.rinfo?.port!];\n // a preestablished remote address does not need a callback to verify dns.\n // this is faster because event loop is not used per packet.\n this.socket.send(data, addr[1], addr[0]);\n }\n };\n\n get address() {\n return this.socket.address();\n }\n\n get host() {\n return this.socket.address().address;\n }\n\n get port() {\n return this.socket.address().port;\n }\n\n close = () =>\n new Promise<void>((r) => {\n this.closed = true;\n this.socket.once(\"close\", r);\n try {\n this.socket.close();\n } catch (error) {\n r();\n }\n });\n}\n\nexport class TcpTransport implements Transport {\n readonly type = \"tcp\" as const;\n private readonly stream: StreamTransport;\n\n private constructor(addr: Address) {\n this.stream = new StreamTransport(\"tcp\", () =>\n connect({ port: addr[1], host: addr[0] }),\n );\n }\n\n static async init(addr: Address) {\n const transport = new TcpTransport(addr);\n await transport.init();\n return transport;\n }\n\n private async init() {\n await this.stream.waitForConnect();\n }\n\n get address() {\n return this.stream.address;\n }\n\n get closed() {\n return this.stream.closed;\n }\n\n get onData() {\n return this.stream.onData;\n }\n\n set onData(handler: (data: Buffer, addr: Address) => void) {\n this.stream.onData = handler;\n }\n\n send = async (data: Buffer, addr?: Address) => {\n await this.stream.send(data, addr);\n };\n\n close = async () => {\n await this.stream.close();\n };\n}\n\nexport class TlsTransport implements Transport {\n readonly type = \"tls\" as const;\n private readonly stream: StreamTransport;\n\n private constructor(addr: Address, options: TlsConnectionOptions = {}) {\n this.stream = new StreamTransport(\"tls\", () =>\n tls.connect({\n ...options,\n host: addr[0],\n port: addr[1],\n }),\n );\n }\n\n static async init(addr: Address, options: TlsConnectionOptions = {}) {\n const transport = new TlsTransport(addr, options);\n await transport.init();\n return transport;\n }\n\n private async init() {\n await this.stream.waitForConnect();\n }\n\n get address() {\n return this.stream.address;\n }\n\n get closed() {\n return this.stream.closed;\n }\n\n get onData() {\n return this.stream.onData;\n }\n\n set onData(handler: (data: Buffer, addr: Address) => void) {\n this.stream.onData = handler;\n }\n\n send = async (data: Buffer, addr?: Address) => {\n await this.stream.send(data, addr);\n };\n\n close = async () => {\n await this.stream.close();\n };\n}\n\nclass StreamTransport implements Transport {\n readonly type: StreamTransportType;\n private connecting!: Promise<void>;\n private client!: StreamSocket;\n onData: (data: Buffer, addr: Address) => void = () => {};\n closed = false;\n\n constructor(\n type: StreamTransportType,\n private createClient: () => StreamSocket,\n private connectEvent: StreamConnectEvent = type === \"tls\"\n ? \"secureConnect\"\n : \"connect\",\n ) {\n this.type = type;\n this.connect();\n }\n\n private connect() {\n if (this.closed) {\n return;\n }\n\n if (this.client) {\n this.client.destroy();\n }\n const client = this.createClient();\n this.client = client;\n this.connecting = new Promise((r, f) => {\n const onConnect = () => {\n client.off(\"error\", onConnectError);\n r();\n };\n const onConnectError = (error: Error) => {\n client.off(this.connectEvent, onConnect);\n f(error);\n };\n client.once(this.connectEvent, onConnect);\n client.once(\"error\", onConnectError);\n });\n\n client.on(\"data\", (data) => {\n const addr = [\n this.client.remoteAddress!,\n this.client.remotePort!,\n ] as Address;\n this.onData(data, addr);\n });\n client.on(\"end\", () => {\n this.connect();\n });\n client.on(\"error\", (error) => {\n log(`${this.type} transport error`, error);\n });\n }\n\n async waitForConnect() {\n await this.connecting;\n }\n\n get address() {\n return {} as AddressInfo;\n }\n\n send = async (data: Buffer, addr?: Address) => {\n void addr;\n await this.connecting;\n await new Promise<void>((resolve, reject) => {\n this.client.write(data, (err) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n };\n\n close = async () => {\n this.closed = true;\n this.client?.destroy();\n };\n}\n\nexport interface Transport {\n type: string;\n address: AddressInfo;\n closed: boolean;\n onData: (data: Buffer, addr: Address) => void;\n send: (data: Buffer, addr?: Address) => Promise<void>;\n close: () => Promise<void>;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../../../common/src/transport.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type RemoteInfo,\n type Socket,\n type SocketType,\n createSocket,\n} from \"dgram\";\n\nimport * as net from \"node:net\";\nimport * as tls from \"node:tls\";\n\nimport { type AddressInfo, type Socket as TcpSocket, connect } from \"node:net\";\nimport { debug } from \"./log\";\nimport {\n type Address,\n type InterfaceAddresses,\n findPort,\n interfaceAddress,\n normalizeFamilyNodeV18,\n} from \"./network\";\n\nconst log = debug(\"werift-ice:packages/ice/src/transport.ts\");\n\ntype StreamTransportType = \"tcp\" | \"tls\";\ntype StreamSocket = TcpSocket | tls.TLSSocket;\ntype StreamConnectEvent = \"connect\" | \"secureConnect\";\n\nexport type TlsConnectionOptions = Omit<\n tls.ConnectionOptions,\n \"host\" | \"port\" | \"socket\"\n>;\n\nexport interface StreamTransportOptions {\n /** Maximum time to wait for TCP/TLS connection establishment, in milliseconds. */\n connectTimeoutMs?: number;\n}\n\nconst DEFAULT_CONNECT_TIMEOUT_MS = 8000;\n\nexport class UdpTransport implements Transport {\n readonly type = \"udp\";\n readonly socket: Socket;\n rinfo?: Partial<Pick<RemoteInfo, \"address\" | \"port\">>;\n onData: (data: Buffer, addr: Address) => void = () => {};\n closed: boolean = false;\n\n private constructor(\n private socketType: SocketType,\n private options: {\n portRange?: [number, number];\n interfaceAddresses?: InterfaceAddresses;\n port?: number;\n } = {},\n ) {\n this.socket = createSocket(socketType);\n this.socket.on(\"message\", (data, info) => {\n if (normalizeFamilyNodeV18(info.family) === 6) {\n [info.address] = info.address.split(\"%\"); // example fe80::1d3a:8751:4ffd:eb80%wlp82s0\n }\n this.rinfo = info;\n try {\n this.onData(data, [info.address, info.port]);\n } catch (error) {\n log(\"onData error\", error);\n }\n });\n }\n\n static async init(\n type: SocketType,\n options: {\n portRange?: [number, number];\n port?: number;\n interfaceAddresses?: InterfaceAddresses;\n } = {},\n ) {\n const transport = new UdpTransport(type, options);\n await transport.init();\n return transport;\n }\n\n private async init() {\n const address = interfaceAddress(\n this.socketType,\n this.options.interfaceAddresses,\n );\n if (this.options.port) {\n this.socket.bind({ port: this.options.port, address });\n } else if (this.options.portRange) {\n const port = await findPort(\n this.options.portRange[0],\n this.options.portRange[1],\n this.socketType,\n this.options.interfaceAddresses,\n );\n this.socket.bind({ port, address });\n } else {\n this.socket.bind({ address });\n }\n await new Promise((r) => this.socket.once(\"listening\", r));\n }\n\n send = async (data: Buffer, addr?: Address) => {\n if (addr && !net.isIP(addr[0])) {\n // if address is not resolved, need to use send callback to handle dns failure.\n return new Promise<void>((r, f) => {\n this.socket.send(data, addr![1], addr![0], (error) => {\n if (error) {\n log(\"send error\", addr, data);\n f(error);\n } else {\n r();\n }\n });\n });\n } else {\n addr = addr ?? [this.rinfo?.address!, this.rinfo?.port!];\n // a preestablished remote address does not need a callback to verify dns.\n // this is faster because event loop is not used per packet.\n this.socket.send(data, addr[1], addr[0]);\n }\n };\n\n get address() {\n return this.socket.address();\n }\n\n /** IP family of the bound socket: 4 for udp4, 6 for udp6. */\n get addressFamily(): IpAddressFamily {\n return this.socketType === \"udp6\" ? 6 : 4;\n }\n\n get host() {\n return this.socket.address().address;\n }\n\n get port() {\n return this.socket.address().port;\n }\n\n close = () =>\n new Promise<void>((r) => {\n this.closed = true;\n this.socket.once(\"close\", r);\n try {\n this.socket.close();\n } catch (error) {\n r();\n }\n });\n}\n\nexport class TcpTransport implements Transport {\n readonly type = \"tcp\" as const;\n private readonly stream: StreamTransport;\n\n private constructor(addr: Address, options: StreamTransportOptions = {}) {\n this.stream = new StreamTransport(\n \"tcp\",\n () => connect({ port: addr[1], host: addr[0] }),\n undefined,\n options.connectTimeoutMs,\n );\n }\n\n static async init(addr: Address, options: StreamTransportOptions = {}) {\n const transport = new TcpTransport(addr, options);\n try {\n await transport.init();\n return transport;\n } catch (error) {\n await transport.close();\n throw error;\n }\n }\n\n private async init() {\n await this.stream.waitForConnect();\n }\n\n get address() {\n return this.stream.address;\n }\n\n get remoteAddress() {\n return this.stream.remoteAddress;\n }\n\n get closed() {\n return this.stream.closed;\n }\n\n get onData() {\n return this.stream.onData;\n }\n\n set onData(handler: (data: Buffer, addr: Address) => void) {\n this.stream.onData = handler;\n }\n\n send = async (data: Buffer, addr?: Address) => {\n await this.stream.send(data, addr);\n };\n\n close = async () => {\n await this.stream.close();\n };\n}\n\nexport class TlsTransport implements Transport {\n readonly type = \"tls\" as const;\n private readonly stream: StreamTransport;\n\n private constructor(\n addr: Address,\n options: TlsConnectionOptions = {},\n streamOptions: StreamTransportOptions = {},\n ) {\n this.stream = new StreamTransport(\n \"tls\",\n () =>\n tls.connect({\n ...options,\n host: addr[0],\n port: addr[1],\n }),\n undefined,\n streamOptions.connectTimeoutMs,\n );\n }\n\n static async init(\n addr: Address,\n options: TlsConnectionOptions = {},\n streamOptions: StreamTransportOptions = {},\n ) {\n const transport = new TlsTransport(addr, options, streamOptions);\n try {\n await transport.init();\n return transport;\n } catch (error) {\n await transport.close();\n throw error;\n }\n }\n\n private async init() {\n await this.stream.waitForConnect();\n }\n\n get address() {\n return this.stream.address;\n }\n\n get remoteAddress() {\n return this.stream.remoteAddress;\n }\n\n get closed() {\n return this.stream.closed;\n }\n\n get onData() {\n return this.stream.onData;\n }\n\n set onData(handler: (data: Buffer, addr: Address) => void) {\n this.stream.onData = handler;\n }\n\n send = async (data: Buffer, addr?: Address) => {\n await this.stream.send(data, addr);\n };\n\n close = async () => {\n await this.stream.close();\n };\n}\n\nclass StreamTransport implements Transport {\n readonly type: StreamTransportType;\n private connecting!: Promise<void>;\n private client!: StreamSocket;\n onData: (data: Buffer, addr: Address) => void = () => {};\n closed = false;\n private rejectConnecting?: (error: Error) => void;\n\n constructor(\n type: StreamTransportType,\n private createClient: () => StreamSocket,\n private connectEvent: StreamConnectEvent = type === \"tls\"\n ? \"secureConnect\"\n : \"connect\",\n private connectTimeoutMs = DEFAULT_CONNECT_TIMEOUT_MS,\n ) {\n this.type = type;\n this.connect();\n }\n\n private connect() {\n if (this.closed) {\n return;\n }\n\n if (this.client) {\n this.client.destroy();\n }\n const client = this.createClient();\n this.client = client;\n this.connecting = new Promise((resolve, reject) => {\n let settled = false;\n const settle = (error?: Error) => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n client.off(this.connectEvent, onConnect);\n client.off(\"error\", onConnectError);\n this.rejectConnecting = undefined;\n error ? reject(error) : resolve();\n };\n const onConnect = () => {\n settle();\n };\n const onConnectError = (error: Error) => {\n this.closed = true;\n settle(error);\n client.destroy();\n };\n const timer = setTimeout(() => {\n this.closed = true;\n settle(\n new Error(\n `${this.type} connect timed out after ${this.connectTimeoutMs}ms`,\n ),\n );\n client.destroy();\n }, this.connectTimeoutMs);\n this.rejectConnecting = (error) => settle(error);\n client.once(this.connectEvent, onConnect);\n client.once(\"error\", onConnectError);\n });\n\n client.on(\"data\", (data) => {\n this.onData(data, this.remoteAddress!);\n });\n client.on(\"error\", (error) => {\n log(`${this.type} transport error`, error);\n });\n }\n\n async waitForConnect() {\n await this.connecting;\n }\n\n get address() {\n return {} as AddressInfo;\n }\n\n /** The peer the stream is connected to, once connected. */\n get remoteAddress(): Address | undefined {\n const { remoteAddress, remotePort } = this.client;\n if (!remoteAddress || !remotePort) {\n return undefined;\n }\n return [stripZoneId(remoteAddress), remotePort];\n }\n\n send = async (data: Buffer, addr?: Address) => {\n void addr;\n await this.connecting;\n await new Promise<void>((resolve, reject) => {\n this.client.write(data, (err) => {\n if (err) {\n reject(err);\n return;\n }\n resolve();\n });\n });\n };\n\n close = async () => {\n this.closed = true;\n this.rejectConnecting?.(new Error(`${this.type} transport closed`));\n this.client?.destroy();\n };\n}\n\n/** Strip an IPv6 zone identifier, e.g. fe80::1%eth0 -> fe80::1. */\nfunction stripZoneId(address: string) {\n return address.split(\"%\")[0];\n}\n\nexport type IpAddressFamily = 4 | 6;\n\nexport interface Transport {\n type: string;\n address: AddressInfo;\n closed: boolean;\n onData: (data: Buffer, addr: Address) => void;\n send: (data: Buffer, addr?: Address) => Promise<void>;\n close: () => Promise<void>;\n /**\n * IP family of a datagram socket. A datagram transport can only reach\n * addresses of this family. Built-in UDP transports always set it; a custom\n * transport that leaves it unset gets no family preference.\n */\n addressFamily?: IpAddressFamily;\n /**\n * The peer a connected (stream) transport is talking to. Responses arrive\n * from this address. Built-in TCP/TLS transports set it once connected.\n */\n remoteAddress?: Address;\n}\n"]}
|
|
@@ -13,3 +13,12 @@ export declare class TransactionFailed extends TransactionError {
|
|
|
13
13
|
export declare class TransactionTimeout extends TransactionError {
|
|
14
14
|
get str(): string;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* The request target is an IP literal of a different family than the socket
|
|
18
|
+
* that would carry it, so it can never be delivered.
|
|
19
|
+
*/
|
|
20
|
+
export declare class AddressFamilyMismatch extends Error {
|
|
21
|
+
addr: Address;
|
|
22
|
+
socketFamily: 4 | 6;
|
|
23
|
+
constructor(addr: Address, socketFamily: 4 | 6);
|
|
24
|
+
}
|