aquametalabs / aquameta

Web development platform built entirely in PostgreSQL
GNU General Public License v3.0
1.1k stars 52 forks source link

p2p: Design db-to-db communication patterns over WebRTC #215

Open erichanson opened 3 years ago

erichanson commented 3 years ago

Using WebRTC to enable peer-to-peer communication has long been a one of the dreams of the Aquameta architecture, a future where peers exchange data and bundles directly with each other. Immaturity of the standard and implementations has been a bottleneck though. The most mature implementations were in the browsers. (Funny story, we once tried to extract the WebRTC implementation out of Webkit and into a PostgreSQL background worker, a lofty goal that ended in tears.) But running WebRTC client-side really doesn't make sense for these purposes: When you close your browsers, your connection to peers goes away so two peers would have to be both online simultaneously, and have a browser tab open and active to communicate with each other.

Well, things have come a long way since then, and now that Aquameta is fully embracing the Go programming language, turns out there's a promising server-side implementation of WebRTC, named pion that might just make this doable.

So! There's some design work to be done here. WebRTC enables communication over their DataChannel API, but how do peers find each other, connect with each other, and communicate? What messages do peers send to each other? Is it bundle pulls, or generic REST API hits, or both? Can any peer talk to any other peer out there, or is there some kind of "add Sally as a friend" type thing? Is everybody added as a friend to the Aquameta hub, ala Tom of MySpace? What shared Stun server shall they use to handshake with each other? Since the stun server is the only centralized part of the communication channel, should it vary from one relationship to another? Discuss.

erichanson commented 3 years ago

Really great discussion of OTs vs CRDTs on HN.

For our purposes with VCS on rows, the commit-based (versus real-time) collaboration model (ala git) says "users make whatever changes they want locally in parallel, and if there are conflicts, they're merged after commits if there are merge conflicts." On the way other end of the spectrum is real-time editing, where everyone in the universe is editing a single copy of the same thing at the same time. Both have advantages and disadvantages in the "it depends" space, but maybe a nice middle ground to shoot for also relies on the UI to prompt the developers with useful decisions when two people start editing the same thing:

Answers will vary wildly depending on the scenario, and affect what the system should do under the hood.

To implement this, a developer would need to publish a sort of "soft lock" when they start editing a piece of data, which should probably happen under the hood via the UI. This "soft lock" doesn't prevent others from changing the same data on their local copy, but it does give the UI the opportunity to notify anyone editing the same piece of data that someone else is also changing it, or has changed it; and prompt to upgrade the editing session to a real-time one, if desired, or if not desired, at least put the two developers in touch with each other to make sensible decisions about the above questions.

I think of commits as disk and real-time as RAM. Real-time changes are really great to be aware of when people are both editing the same thing, and to give the opportunity to do actual collaborative document editing, or to say "hey we were both working on the same thing, why don't you just handle this." Maybe there's value in saving every dang keystroke a developer presses, and that too might be a useful part of the commit, but it also might not be in different scenarios.

But I do think the concept of a commit as a kind of mile-marker in time is still a valuable one. In CRDT, revision history is sort of a continuous stream, but the ability to explicitly mark a revision history at a specific state as determined by the developer/author seems essential.

Anyway the discussion of CRDTs not requiring a single central server is really interesting, and certainly required for a decentralized p2p network. Figuring out how this could work over WebRTC data channels would be really something.

erichanson commented 2 years ago

I used the peerjs WebRTC API before and it was really slick and turnkey. It's browser-based of course, but they had a nice API for handshake handling and it was a really well-designed dev experience I thought. I know they have their own stun server it uses by default but you can override it. Anyway just a nice library.

Was thinking we'd have like peer.stun_server table and maybe a peer.config table that points at the active config.stun_server_id. Or something. Discuss.