-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdraft-toomim-braid-00.txt
818 lines (606 loc) · 34.2 KB
/
draft-toomim-braid-00.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
Internet-Draft M. Toomim
Expires: Jan 8, 2020 Invisible College
Intended status: Proposed Standard R. Walker
Invisible College
July 8, 2019
::::::::: ::::::::: ::: ::::::::::: :::::::::
:+: :+: :+: :+: :+: :+: :+: :+: :+:
+:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+
+#++:++#+ +#++:++#: +#++:++#++: +#+ +#+ +:+
+#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+
#+# #+# #+# #+# #+# #+# #+# #+# #+#
######### ### ### ### ### ########### #########
The Braid Protocol: Synchronization for HTTP
draft-toomim-braid-00
Todo:
- Define "state"
- Explain time and space for someone who could get confused by that idea
- Explain the configurable merge types better.
> Introduction and abstract were good
> Synchronization was good
> As a whole it makes sense
> - There's a clear need
> - There's a clear benefit
> Really liked the network messages, and the explanation of each msg.
- Proposed Changes to HTTP -> Proposed Extension to HTTP
- Move the Linked JSON out of there and into its own proposed new
content-type
- Say that you connect on websocket at path __connect_to_braid__, and
then send messages as described below.
Abstract
Braid is an extension to HTTP that transforms it from a state
*transfer* protocol into a state *synchronization* protocol. Braid
puts the power of Operational Transform and CRDTs onto the web,
improving network performance and robustness, and enabling
peer-to-peer web applications.
At the same time, Braid creates an open standard for the dynamic
internal state of websites. Programmers can access state uniformly,
whether local or on another website. This creates a separation of UI
from State, and allows any user to edit or choose their own UI for any
website's state.
We have a working prototype of the Braid, and have deployed it with
production websites. This memo describes the protocol, how it differs
from today's HTTP, and a plan to deploy it in a backwards-compatible
way, where web developers can opt into the new synchronization
features without breaking the rest of the web.
Status of this Memo
This Internet-Draft is submitted in full conformance with the
provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task
Force (IETF), its areas, and its working groups. Note that other
groups may also distribute working documents as Internet-Drafts. The
list of current Internet-Drafts is at
http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months
and may be updated, replaced, or obsoleted by other documents at any
time. It is inappropriate to use Internet-Drafts as reference
material or to cite them other than as "work in progress."
The list of current Internet-Drafts can be accessed at
https://www.ietf.org/1id-abstracts.html
The list of Internet-Draft Shadow Directories can be accessed at
https://www.ietf.org/shadow.html
Table of Contents
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Synchronization . . . . . . . . . . . . . . . . . . . . . . . . 7
3. Deployment and Upgrade Plan . . . . . . . . . . . . . . . . . 10
4. Proposed Changes to HTTP. . . . . . . . . . . . . . . . . . . 11
4.1. Linked JSON . . . . . . . . . . . . . . . . . . . . . . . 12
4.2. Generalized request/response . . . . . . . . . . . . . . . 13
4.3. Subscriptions . . . . . . . . . . . . . . . . . . . . . . 14
4.4. Versioning . . . . . . . . . . . . . . . . . . . . . . . . 15
4.4.1. Versions . . . . . . . . . . . . . . . . . . . . . . . . 16
4.4.2. Patches . . . . . . . . . . . . . . . . . . . . . . . . 17
4.4.3. Merge Types . . . . . . . . . . . . . . . . . . . . . . . 18
4.4.4. Acknowledgements . . . . . . . . . . . . . . . . . . . . 19
5. Network Messages . . . . . . . . . . . . . . . . . . . . . . 20
6. Security Considerations . . . . . . . . . . . . . . . . . . . 23
7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 23
8. Copyright Notice . . . . . . . . . . . . . . . . . . . . . . 23
9. Author's Address . . . . . . . . . . . . . . . . . . . . . . 23
1. Introduction
HTTP is designed to transfer static pages. If a page changes, it is
the client's responsibility to issue another GET request. This made
sense when pages were static and written by hand. However, today's
websites are dynamic, generated from databases, and continuously
mutate as their state changes. Now we need state *synchronization*,
not just state *transfer*.
Unfortunately, there is no standard way to synchronize. Instead,
programmers write non-standard code; wiring together custom protocols
over WebSockets and long-polling XMLHTTPrequests with stacks of
Javascript frameworks. The task of connecting a UI with data is one
that every dynamic website has to do, but there is no standard way to
do it.
======= HTTP Websites ======= ====== Braid Websites ======
Today's websites are Braid generalizes HTTP and
generated from multiple REST into a uniform standard
layers of state across that synchronizes state
multiple computers. Each within and between dynamic
layer has a different API. websites.
x Non-standard state API o Standard state API
_Client__
/ \
: o o o o : Webpage DOM o o o o State
: \| \| : \| \|
: x x : HTML Templates o o State
: /| /| : /| /|
: x x x x : JS Models o o o o State
\ | | | | / | | | |
| | | | | | | |
o o o o - http:// - o o o o - braid:// -
/ | | | | \ | | | |
: x x x x : Views o o o o State
: | \| | : | \| |
: x x x : Controllers o o o State
: \ / \| : \ / \|
: x x : Models o o State
: \ / : \ /
\.... x ../ Database o State
Server
Today's programmers have to On the braid, each piece of
learn each API, and wire them state (o) has a URL; whether
together, making sure that public, or internal to a
changes to shared state client or server. Any state
synchronize across all can be a function of other
layers and computers. state, and dynamically
recomputes when its
dependencies change. Braid
guarantees the network will
synchronize.
As the web becomes more dynamic and data-driven, the complexity of the
non-standard Javascript stack grows, and an increasing amount of data
is inaccessible to the open web. The result is a web which is open on
the surface, but closed internally: websites can link to each other's
*pages*, but cannot easily share each other's internal *state*.
We can solve this by generalizing HTTP into a *synchronization*
protocol, which replaces the complex Javascript stack, while providing
new features, and making website internal state accessible anywhere
desired, and realtime synchronized by default.
We have a working prototype of the Braid protocol, and have deployed
it with production websites. The prototype is implemented as a
polyfill library, which adds Braid features to existing browsers and
servers.
This document describes the new protocol, how it differs from today's
HTTP, and a plan to deploy it in a backwards-compatible way, where web
developers can opt into the new synchronization features without
breaking the rest of the web.
2. Synchronization
Braid incorporates the abilities of Operational Transform and CRDTs.
These are approaches to solving *synchronization*.
Synchronization is a problem that occurs whenever two or more
computers or threads access the same state. Synchronization code is
tricky to write, and can result in clobbers, corruptions, or race
conditions.
A number of extensions to the HTTP standard touch on synchronization,
such as e-tags, cache control, PATCH, JSON-diff, and SSE. However,
they do not solve the problem completely, and programmers still write
non-standard state synchronization code.
Luckily, a set of maturing synchronization technologies (such as
Operational Transform and CRDTs) can now automate and encapsulate
synchronization within a library. They can synchronize arbitrary JSON
data structures across an arbitrary set of computers that make
arbitrary mutations, and consistently merge their edits into a valid
result, without a central server, in the face of arbitrary network
delays and dropouts. In other words, it is now possible to interact
with state stored anywhere on a network as if it is a local variable,
and program as if it is already downloaded and always up-to-date.
Unfortunately, each synchronizer implements a different protocol, with
a different set of features and tradeoffs. Braid proposes a common
language for synchronizers, so that they can interoperate, and
implements it as an extension to HTTP.
This lets multiple synchronizers interoperate, if they agree on a way
to consistently resolve ambiguities -- a *merge type*. We have run
tests that succesfully interoperate a CRDT and OT system over the
common Braid protocol.
When applying synchronization to the web, we see the power of
synchronization manifest in these concrete ways:
- Caches update automatically and instantly, because servers promise
to push changes to their subscribers. This obsoletes the
`cache-control` and `refresh` headers, and the `max-age`
heuristic. Users never need to force-clear their cache.
- Updates go over the network as diffs, which can be much smaller
than the resources they modify, significantly reducing network
usage.
- Web apps get an offline mode for free. Edits from multiple
clients merge automatically once they come online. Network
failures recover transparently.
- *Reload* buttons in browsers become unnecessary, and can be
removed for braid sites. Browsers automatically discover and
display the most recent version on their own.
- Web apps require roughly 70% less code to build (in our
experiments), because programmers do not need web frameworks or
custom logic to wire together a stack of server-state and
client-state. This work is automated by the protocol.
- Every <textarea> can become a collaborative editor (like Google
Docs) for free.
- Servers become optional. Many apps can function without a server,
because peers can synchronize with one another directly over the
protocol.
- In standardizing synchronization, we implicitly create a standard
for state. This allows state to be shared between different sites
without the need for an extra API.
- Standardizing the representation of *state* allows us to separate
the representation of UI and state. Most HTTP websites *inject*
the state that they receive into templates representing UI
components. Braid sites can instead understand UI components as
lenses through which to view state. This improves the semantics
of UI rendering, allows state to be inspected by clients directly,
and makes it easier to build multiple alternative UIs for a single
site.
Standardized state and synchronization allows the topology of content
on the web to be less centralized.
Closed Networks
- - - - Before the web, people used
/ \ / \ closed networks like America
| x---x | | x--x | Online. Content was
| \ / | | \ | encapsulated behind
\ x / \ x / proprietary protocols.
- - - -
Aol Compuserve
HTTP Websites
- o--------------o - The web lets any site define
/ o--------o \ *pages* at URLs. A site can
| x---x o------o x--x | *link* to another site's pages,
| \ / o------o \ o adding value to both sites.
\ x o o x /
- o--------------o -
Facebook NY Times
Braid Websites
o--o _---------o o The braid lets any site define
|/ o'-------o | | *states* at URLs. A state can
o---o---o---------o---o--o---o be a *function* of other states.
/ \ / \ o------o \ \ When a state changes, the others
o o---o \__. o o .o automatically synchronize with it,
o--o `-----o----' like a spreadsheet.
My Stuff Your Stuff
3. Deployment and Upgrade Plan
Braid makes fundamental changes to HTTP and REST, which creates an
opportunity to unify a number of disparate features (SSE, E-tags,
Cache-control, PATCH, JSON-Diff) within a simple integrated design.
Rather than shoe-horn these changes into the existing HTTP semantics,
we propose a new simpler layer, with a backwards-compatible mapping to
HTTP's existing semantics. This allows existing applications to
interoperate, but new applications can opt-in to a simpler web API
that provides more synchronization features.
We can deploy these semantics in two phases:
1. The first phase requires no changes to existing web browsers,
making it easy for users to experiment with the protocol's
semantics in existing websites.
In this phase, browsers fetch the initial HTML page over the
existing HTTP protocol, which includes Javascript code that
initiates a WebSocket connection that runs the Braid protocol.
This WebSocket version of the Braid protocol provides the full
synchronization functionality, but is less performant --
requiring an extra round-trip to initiate.
2. If and when the WebSocket protocol stabilizes and achieves
real-world adoption, we can add the Braid semantics into HTTP
itself, in a new layer via an HTTP Upgrade header [RFC 2616,
section 14.42].
Both versions of the protocol can maintain backwards-compatibility
with existing HTTP clients and servers. Any client accessing a Braid
server via HTTP 1, 2, or 3 will be able to GET, PUT, and POST Braid
state, but without full synchronization capabilities. Likewise, Braid
clients can access state on HTTP servers, but have to poll the server
for updates.
4. Proposed Changes to HTTP
Braid is composed of a set of opt-in changes that any browser or
server can implement.
First, whereas HTTP is explicitly client/server, Braid is capable of
running peer-to-peer. To do this, it generalizes the explicit
request/response pattern of HTTP into a set of common messages, opened
over a persistent two-way connection.
Additionally, Braid specifies a new content-type for a resource:
Linked JSON. This provides a standard format for dynamic state, akin
to how HTML specifies a standard for the presented content of a
webpage.
This section first describes Linked JSON, and then the changes to HTTP
networking methods, and finally the versioning features that ensure a
peer-to-peer network of edits converge to the same version.
4.1. Linked JSON
Whereas HTML defines a common format for the presented content of web
pages, braid defines a common format for their internal data, or
state: Linked JSON. This extends standard JSON with two additional
datatypes:
- A *link*, which lets one piece of JSON, at one URL, to link to
another piece of JSON at another URL
- A *binary blob*, which lets one encode a binary file (such as an
image) as a value.
We encode links within JSON like:
{
"foo": 3,
"bar": 5,
"something else": {"link": "braid://foo.com/something"}
}
Any object with a field named "link" is special, and interpreted as a
link. To encode an actual field named link, you prefix it with an
underscore, like:
{"_link": "this is not a link"}
To encode an underscore, you use two underscores, like "__", and so
on.
Links allow programmers to combine data across multiple services, even
on multiple websites, and to represent non-tree data as JSON, such as
circular graphs and relational tables. Foreign keys can be specified
as links to other queries. Cycles can be specified as a link back to
the root of an object.
Binary data is encoded similarly, as:
{"binary": "<base64-encoded string>", "content-type": "<type>"}
The content-type is optional.
4.2. Generalized request/response
In HTTP, a client sends a *request* to the server, and that request is
met with a *response*. By contrast, a Braid connection is two-way, so
messages can be initiated by either party. Rather than giving a
response to a message, a Braid server sends a separate message that
acts as the response. It turns out that a GET response message has
the same effect on a peer as a SET request message-- both set the
state on the recipient.
--------------------------------------------------------------
| HTTP | Braid | Meaning |
| ------------ | ----------- | ----------------------------- |
| Get Request | Get message | "I want this" |
| Get Response | Set message | "This is the current version" |
| Put Request | Set message | "This is the current version" |
| Put Response | Ack message | "I accept this version" |
--------------------------------------------------------------
4.3. Subscriptions
In the Braid model, whenever a client requests some state, it also
subscribes to new versions of that state. This requires only minor
changes to the semantics of HTTP.
In the Braid protocol, a GET message not only returns the current
value of state, but also *subscribes* to future updates. The
subscription continues until the client sends a FORGET. Finally,
Braid unifies the PUT, POST, and PATCH methods in to a single
SET method, which is able to both create state and change state.
---------------------------------------------------------------------
| HTTP method | Braid method | What's new |
| -------------- | ------------ | --------------------------------- |
| Get | Get | Also subscribes to future updates |
| - n/a - | Forget | Ends a "Get" subscription |
| Put/Post/Patch | Set | Also updates all subscribers |
| Delete | Delete | Also updates all subscribers |
---------------------------------------------------------------------
The traditional distinction between PUT and POST is that PUT requests
are idempotent, allowing them to be cached and retried, whereas POST
is often not. However, the Braid protocol allows idempotence to be
distinguished by re-using a version on Set -- if two messages set a
state to the same version, they are idempotent, and equivalent to a
PUT.
In their simplest forms, these messages are otherwise semantically
identical to their corresponding HTTP methods. When robust
synchronization is required, these messages will include optional
*versioning* features.
4.4. Versioning
Even though there are many synchronizers, it is possible for them to
communicate in a common language. Different synchronizers use
different data structures internally, and have different network
messages-- however, the *information* they send can all be represented
with a common set of objects:
- VERSIONS define points in time, irrespective of space
- LOCATIONS define points of space, irrespective of time
- PATCHES replace regions of space, across spans of time
These three objects are enough to represent any type of change to a
JSON data structure. We have verified this experimentally, by
implementing a translation algorithm that converts the network
messages of ShareDB (an Operational Transform synchronizer) and
Automerge (a CRDT synchronizer) into these objects, and back again,
and verifying that the synchronizers still work in fuzz testing.
However, synchronizers also differ in how they resolve conflicting
changes to the same region of state. We can generalize the behavior
of these resolvers by defining *merge types*:
- MERGE TYPES define how edits to the same location resolve
If a synchronizer expresses state changes using versions, locations,
and patches, and specifies its merge types, then it can synchronize
with any other braid synchronizer implementing the same merge types,
no matter their internal implementation.
Finally, synchronizers also broadcast *acknowledgements* of the
versions they have received, in order to tell their peers that they
have moved forward in time, and will no longer refer to old history
when sending patches. This allows their peers to prune their history
logs, and free up unused memory:
- ACKNOWLEDGEMENTS of versions allow peers to prune historical memory
The rest of this section explains how these concepts work together.
4.4.1. VERSIONS
Time on a network is ambiguous as a result of latency. If multiple
peers edit the same state at the same time, we cannot say that one
happened before the other, and time forks. When they communicate
their changes over the network, they merge their edits, and time
merges.
(O) All peers are aware of version (O).
/ \
/ \
(A) (B) Two peers make simultaneous edits creating versions (A)
\ / and (B) respectively, and time forks.
\ /
(M) Once a peer sees both of the edits, time merges again.
Until a peer makes an edit with (A) and (B) as parents,
the merge is only implicit-- there is no need for to
assign an ID to it.
Thus the shape of time is not a line but a Directed Acyclic Graph-- a
DAG. Every change to state creates a new version. This version has
*parents*: all recent (leaf) versions that the client had seen when it
made its edit. The edit becomes the *child* of its parents. We can
say that one version came before another only if the first version is
an *ancestor* of the second.
Every version is identified by a unique ID. There is no requirement
on the format of the ID, only that it be a unique string.
When a peer makes an edit, it broadcasts the edit's version ID, its
parents version IDs, and a patch from its parents state to its state.
4.4.2. Patches
When a peer changes some state, it encodes that change as a patch. A
SET message includes 'patches' as an array of patches. All patches
are *replace* operations, that replace one region of space with a new
value. The region being replaced is specified as a start and end
index of the previous state, which is computed by merging all the
parents of the version using its merge type.
Insertions are implemented as replacing a zero-length region with a
non-zero-length region, and deletes replace a non-zero length region
with a zero-length one.
Here are some example patches targeting object 'obj'
(ie, {set: 'obj', patches: [...]} )
.foo[0].bar = null # Replace obj.foo[0].bar with null
[3:3] = "asdf" # Insert the string 'asdf' at index 3 of
string obj. Illegal if array.
[3] = "a" # Set char 3 of string obj to 'a'
or element 3 of array obj to 'a'
[3] = "asdf" # Illegal if string.
If array, set obj[3] to 'asdf'
[3:4] = [1, 3, 5] # Splice [1,3,5] into array obj, replacing
element 3. Illegal if string.
[4:4] = [{msg: "hi"}] # Insert an object at the end of array obj
[3:10] = "" # Delete characters 3-10 in string obj
= false # Set the entire object obj to false
.foo[0].bar = undefined # Delete obj.foo[0].bar
4.4.3. Merge Types
Different applications want to resolve conflicts in different ways.
For instance, strings in a collaborative text editor will want to
merge clobbering edits by inserting everything typed, and deleting
everything deleted, and breaking ordering ties arbitrarily; but if two
debits to a bank account balance occur in parallel, we will want to
merge the debits by adding the differences together.
A "merge type" specifies how any two edits made in parallel are merged
together. If two synchronizers implement the same merge type for some
state, they will converge to a consistent result after arbitrary
merges. Merge types are specified by unique strings, such as
"sync9-string" or "sharedb-rich-text".
LWW(vid) # Last-write-wins, sorted by version ID
text(vid) # Merges text edits like Google Docs
counter # Merges additions and subtractions by summing
All peers synchronizing with a piece of state will need to implement
the same merge types. We envision a handful of merge types will
likely cover most situations on the web. Each field in a JSON object
can merge using a different merge type. One way to specify merge
types of JSON objects is with a schema:
{
id: <string> : LWW(vid)
body: <string> : text(vid)
authors: <array> : text(vid) [
author_id: <string> : LWW(vid)
]
likes: <int> : counter
}
However, we have not yet implemented configurable merge types in our
prototype, or settled on a way to communicate them in the protocol.
Thus, we do not specify merge types in the network examples given
later.
4.4.4. Acknowledgements
In order merge two versions, a synchronizer generally needs enough
history to trace a path of time back from both versions through a
common "fork point." Thus, in order to synchronize perfectly, peers
need to store historical versions in time back to any fork point from
which they expect another peer to send an edit.
To allow other peers to prune history, any peer thus needs to inform
them that it no longer intends to base edits onto versions from the
past. A general way to do this is for peers to agree to always make
edits to the most recent versions they have. Then, a peer will be
able to prune old history as long as it knows which versions of
history all other peers have seen. Once all peers have seen a more
recent version, a peer can know that they will not base an edit on one
of its ancestors.
In the Braid protocol, peers can communicate which versions they have
seen using ACK messages. Each ACK specifies the URL and version of
the state that the peer has seen. When a peer sends an ACK, it means
"everyone who I have sent this version to has also acknowledged its
receipt." Then, once the original sender has received all
acknowledgements from all peers, it sends out a final "ack-complete"
message, which communicates "everyone in the entire network has
acknowledged receipt of this version." This is enough information for
any peer to then know that no peer will be sending an edit based on a
prior ancestor.
However, this spec does not yet handle the case where a peer goes on
and offline in a peer-to-peer network. We are currently working on
implementing a solution to this and will update this draft when the
spec has been finished and tested.
5. Network Messages
We present some examples of the Braid protocol, from the perspective
of a client communicating with a server.
Basic session with no versioning:
Send: {get: "text"} [1]
Recv: {set: "text", val: "Hello"} [2]
Send: {set: "text", val: "Hello, World!"} [3]
Send: {forget: "text"} [4]
[1]: The client requests the most recent version of "text"
[2]: The server sends the client the value of "text"
[3]: The client changes the value to "Hello, World!"
[4]: The client unsubscribes from edits to "text"
Basic session with versioning:
Send: {get: "text"} [1]
Recv: {set: "text", val: "Hello", version: "v1"} [2]
Send: {set: "text", version: "v2", [3]
patches: ['[5:5] = ", World!"'],
parents: ["v1"]}
Send: {forget: "text"} [4]
[1]: The client requests the most recent version of "text"
[2]: The server sends the client the value of "text"
[3]: The client adds ", World!" on to the end of "text"
[4]: The client unsubscribes from edits to "text"
JSON locations and more complex versioning:
Send: {get: "user/fred", parents: ['62347']} [1]
Recv: {set: "user/fred", [2]
patches: ['.name[0] = "F"'],
version: '2h38a',
parents: ['62347']}
Send: {ack: "user/fred", version: "2h38a"} [3]
Send: {set: "user/fred", [4]
patches: [".name[4:4] = \" Wilson\""],
version: "36x02",
parents: ["2h38a"]}
Recv: {ack: "user/fred", version: "36x02"} [5]
Send: {forget: "user/fred"} [6]
[1]: The client requests the current version of "/current_user",
as a patch based on version 62347, which it has in cache.
[2]: The server responds with a SET containing a patch.
[3]: The client acknowledges receipt of the new version.
This enables the server to prune its history of old versions.
[4]: The client updates the current user's name to "Fred Wilson".
[5]: The server acknowledges receipt of the new version.
This enables the client to prune its history.
[6]: The client is done with current_user, and unsubscribes.
GET semantics:
Send: {get: "val"} [1a]
Recv: {set: "val", val: ..., version: "vX"} [1b]
...
Send: {get: "val", version: "vX"} [2a]
Recv: {set: "val", version: "vX", val: ...} [2b]
...
Send: {get: "val", parents: ["vPA", "vPB"]} [3a]
Send: {get: "val", parents: ["vPA", "vPB"], [3b]
version: "vX", patches: ...}
...
Send: {get: "val", version: "vX", [4a]
parents: ["vPA", "vPB"]}
Send: {get: "val", version: "vX", [4b]
parents: ["vPA", "vPB"], patches: ...}
[1a]: The client requests the document "val".
[1b]: The server sends the client the most recent version, giving
the explicit value of the document as well as the ID of the
most recent version. The server also subscribes the client
to new updates.
[2a]: The client requests version "vX" of document "val".
[1b]: The server sends the client version "vX", giving the explicit
value of the document at version "vX" as well as the ID "vX".
The server does NOT subscribe the client to new updates.
[3a]: The client requests the document "val" as a patch based on
parent versions "vPA" and "vPB".
[3b]: The server sends the client the most recent version, giving
its value as a patch against the implicit merge of the given
parents "vPA" and "vPB", even if these are not the original
parents of version "vX". The server also subscribes the
client to new updates.
[4a]: The client requests version "vX" of document "val" as a patch
based on parent versions "vPA" and "vPB".
[3b]: The server sends the client version "vX", giving its value as
a patch against the implicit merge of the given parents "vPA"
and "vPB", even if these are not the original parents of
version "vX". The server does NOT subscribe the client to new
updates.
6. Security Considerations
Although this protocol enables and encourages web programmers to make
more internal available and shared, it has the same fundamental
security model as HTTP. State at any URL can have access control
controlling who can access it.
However, additional work will be needed to analyze the security
concerns of specific uses of the protocol.
7. IANA Considerations
This document has no actions for IANA.
8. Copyright Notice
Copyright (c) 2019 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of the
Trust Legal Provisions and are provided without warranty as described
in the Simplified BSD License.
9. Author's Address
Michael Toomim
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
Email: [email protected]
Web: https://invisible.college/@toomim
Rafie Walker
Invisible College, Berkeley
2053 Berkeley Way
Berkeley, CA 94704
Email: [email protected]