Flip Reference

DocumentServer Class Reference

Declared in

flip/DocumentServer.h

class DocumentServer;

flip::DocumentServer is a type that represents a flip document on the server side.

Member Functions Synopsys

Constructor

Constructs the DocumentServer

Destructor

Destructs the DocumentServer

listen_connecting

Reacts just before a client join the document

listen_connected

Reacts just after a client join the document

listen_disconnected

Reacts just after a client left the document

send_tx_if

Send a transaction to every client meeting a condition

reply_signal

Replies to a signal sent from one client

send_signal_if

Broadcasts a signal selectively

Manipulating

set_label

Sets the label of the current modifications of the document

set_metadata

Sets the metadata of the current modifications of the document

commit

Commits the current modifications of the document

commit_no_tx

Commits the current modifications of the document

revert

Reverts the current modifications of the document

push

Pushes the transactions to the upstream

pull

Pulls document modifications from the upstream

Transaction

execute_forward

Executes a transaction on a document in forward direction

execute_backward

Executes a transaction on a document in backward direction

execute_correct_forward

Executes and corrects a transaction on a document in forward direction

execute_correct_backward

Executes and corrects a transaction on a document in backward direction

Observing

controller

Returns the current controller source of modification

Input/Ouput

write

Write the current state of the document to an intermediate representation format

read

Read from an intermediate representation format

Accessing Objects

root

Returns the root object

object

Returns an object given its unique flip reference number

object_ptr

Returns an object pointer given its unique flip reference number, or nullptr

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)
};
  1. Returned when called outside of an observer callback
  2. Returned when originated to this document
  3. Returned when originated from an undo operation (History)
  4. Returned when originated from a read operation
  5. Returned when originated from a local change
  6. Returned when originated from a remote change
  7. Returned when the server accepted one of the pushed transaction
  8. 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.