Implement the NetherNet protocol in @jsprismarine/nethernet
Status: accepted. Replaces the requirement in the NetherNet plan to use the npm nethernet package for the WebRTC side.
The server and our client ran NetherNet through nethernet (PrismarineJS's node-nethernet), with @jsprismarine/nethernet beside it for HTTP signaling, the identity, the LAN advertisement and join by address. We now write the rest ourselves, in TypeScript, in @jsprismarine/nethernet: offer, answer and candidate handling for server and client, the connection's message segmentation, the LAN discovery packets with their encryption, and the signal format. The npm package and protodef leave the workspace.
Why
- The WebRTC stack has to be ours to choose.
nethernetpicks its stack by name,weriftorwrtc, and takes no other. ADR 0006 moves NetherNet to libdatachannel, and getting a third stack in meant replacing a field on itsServer. - Its werift workarounds are for a werift we do not run. It pins werift 0.24.4 and patches around two of that release's bugs. We run 0.27 for its SCTP fixes, where both patches misfire, and
adaptPeerConnectionsexisted to undo them. - It hands us untyped objects. The server read the peer connection through
unknownand guards, to learn a player's address and to drain a kick. - It cannot be compiled ahead of time. It builds its packet codec at run time with
protodef's compiler, which generates code and runs it witheval. The scriptc build needs code that exists at build time. - The client gets what the server gets. One implementation, taking a WebRTC driver as an option, serves both.
What it costs
- About 1,500 lines of JavaScript to replace, and the wire compatibility that came with them. The LAN discovery encryption and the segmentation are the parts a mistake would break silently.
- We stop receiving
nethernet's fixes and protocol updates, and have to follow Bedrock's changes ourselves.
How we keep it compatible
Our client already joins Bedrock Dedicated Server in its tests, and cinnabar, a Bedrock client, joins our server in the client end-to-end suite. Those two run our code against implementations we did not write, in both directions, and are the check. nethernet is removed in the slice that replaces it.
Alternatives not taken
Ask nethernet for a backend option. It solves the first reason and none of the others, and depends on a release we do not control.
Keep swapping the backend object it holds. It works today and breaks when the package changes how it builds peer connections, without a type error.
Fork nethernet. A fork keeps the JavaScript, the protodef codec and the werift patches, and adds a package to publish.