Am 23.04.2011 00:10, schrieb Matthew Chan:
Hi Everyone,

(This is a long email. Sorry!)

I've been taking a look at how to implement the read-only layers + ownership transfer idea over XMPP today and I would like to continue laying out this plan on the mailing list. Please comment on this as much as possible so we can have a good plan before implementing. There's probably some assumptions that I am making from a lack of knowledge about xournal implementation details

--
Alex: one quick note about how I think about layer sharing that is different from yours. I think that sharing every page in a document would be simpler. Also, all layers would be shared. I don't know whether that would be a loss of useful functionality. I would welcome any feedback on this.

The situation that I think this alternate system solves is the possibility of user A sharing page 63, layer 5 and user B receiving it on page 1, layer 1. I could see this being pretty confusing when users communicate.
I agree with you.

Also if we implement ownership transfer, it saves users the hassle of managing ownership of each layers independently.
Notice: We should search for a new word for shared layer, even if it's technical only a layer, I would show on the sidebar all users which are connected to you, so you can see who is connected to you and may disconnect or do something else, but this is only an implementation detail and don't really matter.


In the notes following, I am assuming we're using a 'share everything, single layer' model. If we decide not to go with it, we can add the necessary details afterwards.

--

XMPP challenges

In the read-only layer implementation implemented over XMPP (without ownership transfer for now), we need to copy strokes from one client to another (No server if we use XMPP).
I don't know the details about XMPP, can you send binary or only XML?

Anyway, Xournal++ supports serialising of all contents (Stroke, Image, Text, everything) to a binary array, but because it's C++ you can overwrite the handler which stores this and let the new handler create an XML file, so you don't have to think about this, this is all implemented.

The challenge with XMPP is showing that regardless of (a) missing commands or  (b) reordered commands, our implementation won't have issues. Since we don't have a server we might need to issue IDs per client to work around the reordered commands (i.e. command from client=2, id=4)

(a) To show we can handle dropped transmissions, we can define our messaging 'protocol' as follows (implemented on top of XMPP). For every command sent (i.e. client A: create ITEM_STROKE id=4), follow with a confirmation (i.e. client B: OK id=4). If client A doesn't get the confirmation, resend a request for confirmation (i.e. client A: confirm create ITEM_STROKE id=4). Note the whole command is in the confirmation request. If client B has already created the item id=4, then just send OK. If not, then create the item and send OK. Client A keeps resending the confirmation request until it gets a response from client B or until there's a timeout. This handles the possibility that there's a dropped message in the command or in the confirmation.
Don't send it multiple times, because XMPP is based on TCP (http://de.wikipedia.org/wiki/Extensible_Messaging_and_Presence_Protocol) no package can be lost, TCP ensures all data will get correctly to the server.

If there is a problem, e.g. with the bandwidth and you're sending it again and again the problem will not be solved, it will be make worse.



(b) To work around the reordering of commands, we should check to see whether the current command from the client has an ID which is incrementally bigger (to see if it is next in the series or if it was reordered). If it was reordered, wait for it to arrive, and store the current command.

TCP ensures you get all data in the right order, before you implement something like this find out if XMPP does this also, then it's not necessary to think about this. (but check it and print an error message to stderr, because theory and practise are not always the same;-))


Layer ownership transfer challenges

If we further try to implement the layer ownership model I described earlier, any layer would only have 1 editor at a time. This is kind of like a lock. Since we're using potentially flaky connections, we can run into problems with abandoned locked etc. The situations we need to avoid are (a) orphaned ownership and (b) dual ownership.

(a) The possibility of orphaned ownership arises when a user disconnects while in possession of someone else's lock. The simple solution would be to have the original owner implement a timeout and reclaim ownership after that period of time. However, the issue is that if the temporary owner continues editing and reconnects at a later time, both are in possession of the layer

Somebody is the client and somebody is the server, If somebody connection to MY DOCUMENT I'm the server, if I'm connecting to another document I'm the client.

If a client loses her connection I get again the owner, if I was writing before I own now two layer, but I'm still writing on my layer (as before) and the other layer is not used, if the other connects again he can have it as long as I'm not writing on it. Else it is handled as a normal connect (I don't know how a normal connect would work).


(b) In addition to the timeout/reconnect possibility, dual ownership can also arise from a dropped message. We need to make sure ownership transfers implement the 'protocol' as well. As Alex suggested, perhaps the best way to resolve these types of conflict are to let the users decide whose changes to keep. We'll need to implement a way of deleting the unimportant changes.

If you're implementation is good enough dual ownership cannot happen. We can talk later about this problem.

(ps. are you a developer? If not: this is a typical "multi-user-problem", we have to possibility to handle this: possible loss of data, or possible loss of time;-))




Commands

As Denis said in an earlier message, there are several commands we need to implement to communicate between xournal clients. However if we use a read-only layer implementation, we do not need to implement every command in the same way. I've taken the liberty of splitting them according to whether they interact with a specific layer.

==layer dependent interaction==

don't number them now...

#define ITEM_STROKE
#define ITEM_TEXT
->
#define ITEM_IMAGE

#define ITEM_ERASURE 2
->
#define ITEM_DELETE?

#define ITEM_TEMP_TEXT 19
#define ITEM_TEXT_EDIT 20

#define ITEM_PASTE 5

#define ITEM_MOVESEL 4
#define ITEM_REPAINTSEL 15
why repaintsel?

->
#define ITEM_TEXT_ATTRIB 21
why? No:
#define ITEM_COLOR_CHANGED
#define ITEM_FONT_CHANGED



#define ITEM_RESIZESEL 22
#define ITEM_NEW_LAYER 6
#define ITEM_DELETE_LAYER 7




==layer independent interaction==

 #define ITEM_NEW_BG_ONE 8

  #define ITEM_NEW_BG_RESIZE 9
 #define ITEM_PAPER_RESIZE 10
Difference between 9 and 10?

 #define ITEM_NEW_DEFAULT_BG 11
This don't matter?
 #define ITEM_NEW_PAGE 13
 #define ITEM_DELETE_PAGE 14

We also have some commands that do not need to be implemented as a network command because they don't interact with the journal directly (as far as I understand)

==local commands==
#define ITEM_RECOGNIZER 23

Finally, we will need to add a few more commands to allow for ownership transfer of layers
And there are some commands missing, I don't add them now, you will see it when you start to implement this.


==new commands==
- Request layer ownership
- Ownership request response
- Assuming layer ownership
- Most recent command seen

- Join/leave commands
- client version commands

Returning layer ownership can be implemented as an ownership request with an automatic accept (i.e. check to see if layer id was originally owned by me, if yes: auto accept) so there's no need for that command to be implemented

The 'most recent command seen' command could be used to sync users who join a collaboration mid-session. (i.e. new client sends last command seen, and other clients send every command with ID greater than that one)



Implementing commands

Each class of commands can be handled differently.
1. Sending layer dependent interactions need to be locked when there is no ownership of the layer.
2. Receiving layer dependent commands with a layer ID should invoke an action on the read-only layer with matching layer ID
3. Layer independent interactions should only be issued by an 'admin' user, with exception of ITEM_NEW_PAGE.



XMPP library

I'm thinking of using gloox as the XMPP lib in question. It's a pretty stable multi-platform (win/nix/osx/symbian) library which implements all of XMPP core, and also most of the XMPP IM features. It's GPL licensed, and included in the repos for Ubuntu, Fedora, Suse, and Gentoo. Has anyone heard of this, or used it before?

http://camaya.net/gloox/features

I'm not sure what kind of XMPP features are useful to us yet. Multi-user chat seems promising, but I think we would want to encode our strokes to hex first before sending.
  • File transfer
So we can send PDF backgrounds etc;-)

Another great feature is the offline message retrieval. We can probably use that to take care of reconnecting users.

That's it for now. Please let me know what you think.

Matt

------------------------------------------------------------------------------
Fulfilling the Lean Software Promise
Lean software platforms are now widely adopted and the benefits have been 
demonstrated beyond question. Learn why your peers are replacing JEE 
containers with lightweight application servers - and what you can gain 
from the move. http://p.sf.net/sfu/vmware-sfemails
_______________________________________________
Xournal-devel mailing list
Xournal-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/xournal-devel

Reply via email to