[]
Operation (Op) is the core concept of communication between client and server. The client submits Ops to describe modifications to a document, while the server processes, stores, and synchronizes these Ops. This document will introduce:
Definition of Op
Differences of Op between the client and the server
The role of additional fields on the server side
Op is the description of a single modification to the document state. Common operations include:
Inserting or modifying document content: For example, inserting text at a specific position in the document.
Creating a document: Initializing a new document.
Deleting a document: Removing an existing document.
The definition of Op differs between the client and the server:
Client-side Op: Describes the specific content of the operation, such as the position and content of inserted text.
Server-side Op: Enhances the client-side Op by adding additional metadata (such as src
, seq
, and v
), used for uniquely identifying operations, version management, and detecting duplicate submissions in unstable network conditions.
A client-side Op is a direct description of the user's modification to the document, typically containing only the specific content of the operation. Below is an example of an Op:
type=note
The Ops in the following examples are simplified for demonstration purposes. In real-world scenarios, the structure and content of Ops may vary depending on the document type, operation complexity, or implementation.
Example 1: Inserting Text
Inserting text at a specific position in the document:
sharedDoc.submitOp({ pos: 1, text: 'hello' })
pos: 1
: Indicates inserting content at position 1 in the document.
text: 'hello'
: Indicates the inserted text content is "hello."
Example 2: Creating a Document
Initializing a new document:
sharedDoc.create('Hi!', textType.uri);
'Hi!'
: Indicates the initial content of the new document.
textType.uri
: Indicates the OT type of the document (e.g., text type).
Example 3: Deleting a Document
sharedDoc.del();
After the server receives an Op submitted by the client, it enhances Op by adding the following metadata fields:
src: The source identifier of the operation, typically a unique identifier for the client to distinguish different clients.
seq: The sequence number of the operation, indicating the order of operations submitted by this client. The combination of src
and seq
forms a unique identifier for the operation.
v: The version number of the document, indicating the document version at the time the operation is applied, used for version control and conflict resolution.
The roles of these metadata fields include:
Unique Identification: Using src
and seq
, the server can detect duplicate submissions in unstable network conditions, avoiding the repeated application of the same operation.
Version Management: Using v
, the server can ensure operations are applied in the correct order and handle conflicts caused by concurrent modifications.
Below are examples of Ops as received by the server, corresponding to the client-side Ops:
Example 1: Creating a Document (Server-Side)
The client-submitted document creation operation appears on the server as follows:
documentServices.use('submit', async (context, next) => {
console.log(context.request.op);
// Output: { src: '51pX43yjKUiMmSoHAAAB', seq: 1, v: 0, create: { type: 'text-type', data: 'Hi!' } }
await next();
});
create: { type: 'text-type', data: 'Hi!' }
: Indicates the original operation content for creating the document.
src: '51pX43yjKUiMmSoHAAAB'
: The unique identifier of the client.
seq: 1
: The 1st operation of this client.
v: 0
: The document version number when the operation is applied.
Example 2: Inserting Text (Server-Side)
The client-submitted text insertion operation appears on the server as follows:
documentServices.use('submit', async (context, next) => {
console.log(context.request.op);
// Output: { src: '51pX43yjKUiMmSoHAAAB', seq: 2, v: 1, op: { pos: 1, text: 'hello'} }
await next();
});
op: { pos: 1, text: 'hello'}
: The original operation content submitted by the client.
src
, seq
, v
: Same as above, used for identification and version management.
Example 3: Deleting a Document (Server-Side)
The client-submitted document deletion operation appears on the server as follows:
documentServices.use('submit', async (context, next) => {
console.log(context.request.op);
// Output: { src: '51pX43yjKUiMmSoHAAAB', seq: 3, v: 2, del: true }
await next();
});
del: true
: Indicates the original operation content for deleting the document.
src
, seq
, v
: Same as above, used for identification and version management.