DocumentServer Class Reference
Declared in |
|
class DocumentServer; |
flip::DocumentServer is a type that represents a flip document on the server side.
Member Functions Synopsys
Constructs the | |
Destructs the | |
Reacts just before a client join the document | |
Reacts just after a client join the document | |
Reacts just after a client left the document | |
Send a transaction to every client meeting a condition | |
Replies to a signal sent from one client | |
Broadcasts a signal selectively |
Manipulating
Sets the label of the current modifications of the document | |
Sets the metadata of the current modifications of the document | |
Commits the current modifications of the document | |
Commits the current modifications of the document | |
Reverts the current modifications of the document | |
Pushes the transactions to the upstream | |
Pulls document modifications from the upstream |
Transaction
Executes a transaction on a document in forward direction | |
Executes a transaction on a document in backward direction | |
Executes and corrects a transaction on a document in forward direction | |
Executes and corrects a transaction on a document in backward direction |
Observing
Returns the current controller source of modification |
Input/Ouput
Write the current state of the document to an intermediate representation format | |
Read from an intermediate representation format |
Accessing Objects
Returns the root object | |
Returns an object given its unique flip reference number | |
Returns an object pointer given its unique flip reference number, or |
Member Functions
Constructor
DocumentServer (const DataModelBase & data_model, DocumentValidatorBase & validator, uint64_t session_id); |
Constructs the document from a data model and a validator using unique session identifier.
The data model represents the blueprint or template the document is going to rely on. The data model is previously defined and used for the document.
The session identifier represents a unique number accross documents uniquely identifying this document. When the document is changed on the server side, the session identifier is used as a way to identify the server acting as a user.
Example, server side :
#include "flip/contrib/transport_tcp/PortTransportServerTcp.h" |
// Setup a server for session number 1234567890123 |
DocumentValidatorVoid validator; |
DocumentServer document_server (Model::use (), validator, 1234567890123ULL); |
// Setup a socket listening on TCP port 9090 to accept new connections. |
PortTransportServerTcp port (document_server, 9090); |
for (;;) |
{ |
// process incoming connections and transfers |
port.process (); |
} |
Example, client side :
#include "flip/contrib/transport_tcp/CarrierTransportSocketTcp.h" |
Document document (Model::use (), 123456789ULL, 'appl', 'gui '); |
// Setup a socket connecting on TCP port 9090 of server. |
CarrierTransportSocketTcp carrier (document, "flip.myserver.com", 9090); |
for (;;) |
{ |
// process incoming connections and transfers |
carrier.process (); |
} |
Destructor
~DocumentServer (); |
Destructor.
listen_connecting
void listen_connecting (std::function <void (PortBase &)> func); |
Example :
DocumentServer server = ...; |
// listen on connections and create a specific Client class |
// in the root of the document for private data |
server.listen_connecting ([&server](PortBase & port){ |
Root & root = server.root <Root> (); |
if (root._clients.count_if ([&port](Client & client){ |
return client.user () == port.user (); |
}) == 0) |
{ |
root._clients.emplace (port.user ()); |
} |
Transaction tx = server.commit (); |
server.send_tx_if (tx, [](PortBase &){return true;}); |
}); |
listen_connected
void listen_connected (std::function <void (PortBase &)> func); |
Example :
DocumentServer server = ...; |
// hypothetic class representing a monitoring system for administration |
MonitoringSystem monitor = ...; |
server.listen_connected ([&monitor](PortBase & port){ |
monitor.add_user (port.user ()); |
}); |
listen_disconnected
void listen_disconnected (std::function <void (PortBase &)> func); |
Example :
DocumentServer server = ...; |
// hypothetic class representing a monitoring system for administration |
MonitoringSystem monitor = ...; |
listen_disconnected ([&monitor](PortBase & port){ |
monitor.remove_user (port.user ()); |
}); |
send_tx_if
template <class UnaryPredicate> void send_tx_if (const Transaction & tx, UnaryPredicate p); |
Send transaction tx to every client meeting condition using unary function p.
Example :
DocumentServer server = ...; |
// listen on connections and create a specific Client class |
// in the root of the document for private data |
server.listen_connecting ([&server](PortBase & port){ |
Root & root = server.root <Root> (); |
if (root._clients.count_if ([&port](Client & client){ |
return client.user () == port.user (); |
}) == 0) |
{ |
root._clients.emplace (port.user ()); |
} |
Transaction tx = server.commit (); |
server.send_tx_if (tx, [](PortBase &){return true;}); |
}); |
Sends the transaction to all attached clients.
reply_signal
void reply_signal (const SignalData & data); |
Replies to a signal sent from a client, when the signal on the client is configured on the client side to pass through local machine boundaries.
Example :
class Root : public Object |
{ |
enum |
{ |
Signal_SIGN_UPLOAD_REQUEST = 0, |
Signal_SIGN_UPLOAD_SIGNATURE, |
}; |
// from client to server |
Signal <std::string> signal_sign_upload_request; |
// from client to server |
Signal <std::string> signal_sign_upload_signature; |
}; |
The following example demonstrates a client sending a signal to the server to sign a request to upload data on a server.
/* Client side */ |
// don't forget to move cnx so that it is not destroyed |
auto cnx = root.signal_sign_upload_signature.connect ([](std::string signature){ |
// the client receives the reply to its sign request |
}); |
// send the sign request |
root.signal_sign_upload_request ("string to sign"); |
The following example shows how a server is handling the signal and reply to it.
/* Server side */ |
DocumentServer = ...; |
// don't forget to move cnx so that it is not destroyed |
auto cnx = root.signal_sign_upload_request.connect ([&root, &server](std::string str_to_sign){ |
auto signature = sign_request (str_to_sign); |
server.reply_signal ( |
root.signal_sign_upload_signature.make (signature) |
; |
}); |
send_signal_if
template <class UnaryPredicate> |
void send_signal_if (const SignalData & data, UnaryPredicate p); |
Broadcasts a signal selectively to clients.
Example :
The following example shows how a server is handling the previous signal but broadcast the signature to every connected clients.
/* Server side */ |
DocumentServer = ...; |
// don't forget to move cnx so that it is not destroyed |
auto cnx = root.signal_sign_upload_request.connect ([&root, &server](std::string str_to_sign){ |
auto signature = sign_request (str_to_sign); |
server.send_signal_if ( |
root.signal_sign_upload_signature.make (signature), |
[](){return true;} |
; |
}); |
set_label
void set_label (std::string label); |
Sets the label (ie. name) of the current modifications of the document. This metadata will be added to the transaction at commit stage.
This is typically use to display the undo/redo name in the Edit menu of the menubar.
If called multiple times before commit, only the last state of the metadata is taken into account at commit stage.
Example :
Root & root = document.root <Root> (); |
root.notes.emplace <Note> (2.0, 4.0); |
document.set_label ("Add note"); |
Transaction tx = document.commit (); |
// the transaction contains the new note modification in 'root.notes' |
// as well as the metadata label "Add note" |
set_metadata
void set_metadata (std::string key, std::string value); |
Sets the metadata value for key of the current modifications of the document. This metadata will be added to the transaction at commit stage.
If called multiple times before commit, only the last state of the metadata is taken into account at commit stage.
This is a more general version of set_label. Actually, set_label calls this methods with the key "label".
This can be used to present even more textual informations for undo/redo operations, for example detailing the nature of the change.
commit
Transaction commit (); |
Commits the current modifications of the document and returns the resulting transaction. The modifications are validated through the validator if the document has one, and will throw if the document state is invalid.
Once the function returns, the document is valid from a validation point of view and the transaction is put on the push stack for later upstream synchronization.
commit_no_tx
void commit_no_tx (); |
Commits the current modifications of the document without returning a transaction. The modifications are validated through the validator if the document has one, and will throw if the document state is invalid.
Once the function returns, the document is valid from a validation point of view and the transaction is put on the push stack for later upstream synchronization.
In the case where the document is not connected to an upstream, this performs an important optimisation since no transaction is produced and there is no need to store a transaction.
revert
void revert (); |
Reverts the current modifications of the document.
push
void push (); |
Pushes the transactions in the push stack to the upstream and empty the push stack. If no upstream is present then this function will just empty the push stack.
WARNING: Even if not connected to an upstream, it is important to call push regularly to empty the push stack.
pull
void pull (); |
Pulls document modifications from the upstream. If no upstream is present then this function does nothing.
If the document contains modifications, they are temporarily saved and rollbacked, then external modifications are applied, and the local modifications are reapplied. If the local modifications cannot be reapplied, then they are dropped silently.
execute_forward
bool execute_forward (const Transaction & tx, bool undo_mode_flag = false); |
Executes a transaction on a document in forward direction. Returns true if the execution was successful, false otherwise. Executing a transaction does not call the validator nor commits the transaction.
If undo_mode_flag is set to true, then the instructions of the transaction that are marked to be out of undo (through a prior call to disable_in_undo) won't be executed unless the top object disabled in undo has a container parent enabled in undo and the top object was either added or removed. This is the default mode when using flip History class.
execute_backward
bool execute_backward (const Transaction & tx, bool undo_mode_flag = false); |
Executes a transaction on a document in backward direction. Returns true if the execution was successful, false otherwise. Executing a transaction does not call the validator nor commits the transaction.
If undo_mode_flag is set to true, then the instructions of the transaction that are marked to be out of undo (through a prior call to disable_in_undo) won't be executed. This is the default mode when using flip History class.
execute_correct_forward
bool execute_correct_forward (const Transaction & tx, bool undo_mode_flag = false); |
Executes and corrects a transaction on a document in forward direction. Returns true if the execution was successful, false otherwise. Executing a transaction does not call the validator nor commits the transaction.
Correcting allows to force a transaction to execute if possible. Transaction instructions are similar to compare & exchange processor instructions. Only if the old state of the document matches the instruction old value then the new value is applied. In this case correcting allows the virtual machine to force the execution and change the instruction to match virtual machine constraints.
If undo_mode_flag is set to true, then the instructions of the transaction that are marked to be out of undo (through a prior call to disable_in_undo) won't be executed. This is the default mode when using flip History class.
execute_correct_backward
bool execute_correct_forward (const Transaction & tx, bool undo_mode_flag = false); |
Executes and corrects a transaction on a document in backward direction. Returns true if the execution was successful, false otherwise. Executing a transaction does not call the validator nor commits the transaction.
Correcting allows to force a transaction to execute if possible. Transaction instructions are similar to compare & exchange processor instructions. Only if the old state of the document matches the instruction old value then the new value is applied. In this case correcting allows the virtual machine to force the execution and change the instruction to match virtual machine constraints.
If undo_mode_flag is set to true, then the instructions of the transaction that are marked to be out of undo (through a prior call to disable_in_undo) won't be executed. This is the default mode when using flip History class.
controller
Controller controller () const; |
When called from document observer callback, returns the current controller source of modification. If the callback resulted from a pull operation, the returned controller is the last one from the pull queue.
enum class Controller |
{ |
NONE, (1) |
SELF, (2) |
UNDO, (3) |
READ, (4) |
LOCAL, (5) |
EXTERNAL, (6) |
ACKNOWLEDGED, (7) |
DENIED, (8) |
}; |
- Returned when called outside of an observer callback
- Returned when originated to this document
- Returned when originated from an undo operation (
History) - Returned when originated from a read operation
- Returned when originated from a local change
- Returned when originated from a remote change
- Returned when the server accepted one of the pushed transaction
- Returned when the server rejected one of the pushed transaction
write
BackEndIR write (); |
Write the current state of the document (with its potential modifications) to an intermediate representation format backend.
The resulting object can be used with concrete backends format such as BackEndBinary or BackEndMl to store them on a media.
See BackEndMl or BackEndBinary for an example of use of this method.
read
void read (BackEndIR & backend); |
Read from an intermediate representation format backend. Internally this will create a transaction that represents the difference between the new backend and the current state of the document. As such, the document modification are not commited at the end of this operation.
See BackEndMl or BackEndBinary for an example of use of this method.
root
template <class T> T & root (); |
Returns the root object of the document.
object
template <class T> T & object (const Ref & ref); |
Returns an object given its unique flip reference number. The function will throw if the reference number does not exist in the document or if the resulting object cannot be casted to T.
See Ref for more details.
object_ptr
template <class T> T * object_ptr (const Ref & ref); |
Returns an object given its unique flip reference number. The function will return nullptr if the reference number does not exist in the document or if the resulting object cannot be casted to T.
See Ref for more details.