This is an old dream. I always wanted to create apps that allow all of my users (clients, students, teachers) to work on a same file and exchange realtime information in an efficient way.
Perhaps it is your dream too. If so, keep reading.
The code is a collection of some of my own libraries:
- DIFF library, using Remote Differential Compression for more efficient updates.
- RWMutex and tlock, my own synchronization objects to provide complex locks.
- Some of my own small helpers, including TEVENT and XSOCKET, and
- collab.hpp, the library described here.
The library is a client-server mode. The server listens to an accessible TCP port and the clients connect to the server which keeps all the shared documents locally or in memory. If a client updates the document, the server notifies all other clients with the update data.
The library provides an abstract way to authenticate either the server or the clients, via the
AUTH class. This class' member function
Do() returns a
E_PENDING, the function is called again. On successful authentication the function must return an S_ code, and on failure it must return an E_ code.
The library provides an
ANYAUTH class which simply returns S_OK for testing purposes. You may pass your own authentication mechanism.
Do() function can return
S_FALSE when it is also passed a document's CLSID. In this case the file can only be opened for reading, but client updates to this file will fail.
The library provides an
ANYAUTH class which simply returns S_OK for testing purposes. You may pass your own authorization mechanism.
Each document is identified uniquely by a CLSID. Each server can host unlimited documents, and each client can manipulate any number of documents.
The server also maintains the current signature of all the documents opened by a client, so the serve can know how to update a client when another client has updated a shared file.
The server part
The server part is contained in the class SERVER, which contains a list of all documents and a list of all connected clients. Each client can open any number of documents.
COLLAB::SERVER s(&auth, 8765,true);
SERVER::Start() which returns S_OK on success. The server runs in a background thread. When a client connects, a new thread is created. The client performs requests to the server as follows:
- Create or open a document
- Close a document
- Get a documents current signature
- Update a document
When a document is updated, all other clients that have opened that document are updated via the
You can call also:
void ForceUpdateDocument(GUID c), to force updating a document to all clients.
shared_ptr<DOCUMENT> GetDocument(GUID c), to get a pointer to the document (if you want to lock it and edit it outside the clients).
End the server using
End(). This method shuts down all clients immediately.
The client part
You need first an ON structure, which provides notification when an update is received:
virtual void Update(CLSID cid,const char* d,size_t sz) = 0;
The first parameter is the CLSID of the document being updated. The rest are the new data for the document (a DIFF object)
To reconstruct the entire document we can use this helper in a multithreaded COM environment:
void RecoFromDiff(const char* d, size_t sz, const char* e, size_t sze, vector<char>& o)
DIFFLIB::MemoryRdcFileReader r1(e, sze);
DIFFLIB::MemoryRdcFileReader diffi(d, sz);
diff.Reconstruct(&r1, &diffi, 0, dw);
o = dw.p();
sze are the current byte array and size of our document, and
sz are the diff. The function reconstructs the complete object in the
Each client is represented by the
COLLAB::CLIENT class, containing references to all documents, and a
vector<> of ON notification classes:
If the document exists, the client is immediately updated from the server (note that, if you have your own updated version of the client you must push it to the server after this initial update).
When you want to put updates to the server, you call
HRESULT Put(GUID g, const char* d,size_t sz);
The function requests the documents signature from the server, then only uploads a diff to it, minimizing network usage.
The zip contains:
- A complete collaboration demo solution with prebuild executable and sources.
- diff.h and collab.hpp are all you need to include in your own projects.
- Two prebuild binaries, server.exe and notepad.exe which you can use to create multiple editors of the same file.
20 - 6 - 2017: Updated RWMutex, tlock and the library.
1 - 12 - 2016: First Release.