|Version 1 (modified by novalis@…, 8 years ago)|
We synchronise each keystroke to the obby server and back to all the clients. When typing fast, up to 2 kb/s (up+down) are required at the client side, and 2 * amount_of_clients at the server side, I guess (I did not test it, but 50 Bytes per keystroke (+ some TCP overhead) sounds realistic). If you are interested in the whole algorithm about keeping the document in sync while preserving local prediction, here it is:
Each document has a so-called revision number, starting at zero. If someone performes an operation, he tells the server what revision of the document he got when applying the operation. The client applies this operation immediately, but keeps it in a special list of "unsynced changes". The server applies all operations that have a higher revision than the one from the client when sending the operation. Then, he performs this operation to the document. He increases the revision number by one and sends the operation back to all the clients telling them the new revision number. If a client receives an operation, he undoes all the "unsynced changes", applies the incoming operation and redoes its unsynced changes, increasing its revision number by one. Maybe, an example would be appropriate.
TCP itself guarantees that packets arrive in-order.
Lets say, the document contains "OBBY" at revision 6. A first client inserts 'H' at position one, another one insert 'L'. They do not know about the other change, so they perform their operation both on revision 6 of the document. By chance, the server receives the 'H' from Client A before the 'L' from Client B. The operation is destinated for revision 6, the document has revision 6, so nothing has to be done. The server sends "Insert H at 0" to both clients, telling them, that this change results in revision 7. When he gets the insertion of the 'L' from Client B, he applies the insertion of the 'H' from Client A to this packet because this one is revision 7 but the incoming operation is from revision 6. This causes the new operation to turn into "Insert L at 1" because something has been inserted at position 0. This operation is applied to the document and also sent to the clients as revision number 8. We have now "HLOBBY" in the document. Ok. So long for the server side.
When Client A receives the "Insert H at 0", he undoes all its unsynced changes - which is his own 'H'. After that, he recognises that the incoming operation is the one he made already - so the operation is removed from the list of unsynced changes. Then, the operation is applied normally, which restores the 'H'. After that, he receives "Insert L at 1". Because there are no unsynced changes, he just applies this change to the document, resulting in "HLOBBY".
Client B gets "Insert H at 0", too. He undoes his unsynced change - the 'L' - and applies the new record to the document and his unsynced changes, which causes his operation to turn into "Insert L at 1" (because something ('H') has been inserted before). Redoing the unsynced change results in "HLOBBY". Some time later he receives "Insert L at 1". He undoes his unsynced change (L at 1), recognises that this is his own change, removes it from the list of unsynced changes, and re-applies it to the document.
If you are interested in libobby API documentation, you may check out the darcs repository at http://darcs.0x539.de/libobby and run 'make' in the docs/ subdirectory. You will get a Doxygen-generated documentation in docs/html.
There is no public documentation available on the net because libobby currently still is under heavy development which brakes API, ABI and network protocol compatibility.