implemented three-way sync for master-slave apps
This commit is contained in:
		
							parent
							
								
									aa6edcfd9b
								
							
						
					
					
						commit
						e2ec53be65
					
				@ -1,5 +1,5 @@
 | 
				
			|||||||
import { BinaryEncoder, BinaryDecoder } from './Encoding.js'
 | 
					import { BinaryEncoder, BinaryDecoder } from './Encoding.js'
 | 
				
			||||||
import { computeMessageSyncStep1, computeMessageSyncStep2, computeMessageUpdate } from './MessageHandler.js'
 | 
					import { sendSyncStep1, computeMessageSyncStep1, computeMessageSyncStep2, computeMessageUpdate } from './MessageHandler.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function extendConnector (Y/* :any */) {
 | 
					export default function extendConnector (Y/* :any */) {
 | 
				
			||||||
  class AbstractConnector {
 | 
					  class AbstractConnector {
 | 
				
			||||||
@ -111,7 +111,8 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
        uid: user,
 | 
					        uid: user,
 | 
				
			||||||
        isSynced: false,
 | 
					        isSynced: false,
 | 
				
			||||||
        role: role,
 | 
					        role: role,
 | 
				
			||||||
        processAfterAuth: []
 | 
					        processAfterAuth: [],
 | 
				
			||||||
 | 
					        receivedSyncStep2: false
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      let defer = {}
 | 
					      let defer = {}
 | 
				
			||||||
      defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
 | 
					      defer.promise = new Promise(function (resolve) { defer.resolve = resolve })
 | 
				
			||||||
@ -137,8 +138,8 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    findNextSyncTarget () {
 | 
					    findNextSyncTarget () {
 | 
				
			||||||
      if (this.currentSyncTarget != null) {
 | 
					      if (this.currentSyncTarget != null || this.role === 'slave') {
 | 
				
			||||||
        return // "The current sync has not finished!"
 | 
					        return // "The current sync has not finished or this is controlled by a master!"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      var syncUser = null
 | 
					      var syncUser = null
 | 
				
			||||||
@ -151,17 +152,7 @@ export default function extendConnector (Y/* :any */) {
 | 
				
			|||||||
      var conn = this
 | 
					      var conn = this
 | 
				
			||||||
      if (syncUser != null) {
 | 
					      if (syncUser != null) {
 | 
				
			||||||
        this.currentSyncTarget = syncUser
 | 
					        this.currentSyncTarget = syncUser
 | 
				
			||||||
        this.y.db.requestTransaction(function * () {
 | 
					        sendSyncStep1(this, syncUser)
 | 
				
			||||||
          let encoder = new BinaryEncoder()
 | 
					 | 
				
			||||||
          encoder.writeVarString(conn.opts.room || '')
 | 
					 | 
				
			||||||
          encoder.writeVarString('sync step 1')
 | 
					 | 
				
			||||||
          encoder.writeVarString(conn.authInfo || '')
 | 
					 | 
				
			||||||
          encoder.writeVarUint(conn.protocolVersion)
 | 
					 | 
				
			||||||
          let preferUntransformed = conn.preferUntransformed && this.os.length === 0 // TODO: length may not be defined
 | 
					 | 
				
			||||||
          encoder.writeUint8(preferUntransformed ? 1 : 0)
 | 
					 | 
				
			||||||
          yield * this.writeStateSet(encoder)
 | 
					 | 
				
			||||||
          conn.send(syncUser, encoder.createBuffer())
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        if (!conn.isSynced) {
 | 
					        if (!conn.isSynced) {
 | 
				
			||||||
          this.y.db.requestTransaction(function * () {
 | 
					          this.y.db.requestTransaction(function * () {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import Y from './y.js'
 | 
					import Y from './y.js'
 | 
				
			||||||
import { BinaryDecoder } from './Encoding.js'
 | 
					import { BinaryDecoder, BinaryEncoder } from './Encoding.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function formatYjsMessage (buffer) {
 | 
					export function formatYjsMessage (buffer) {
 | 
				
			||||||
  let decoder = new BinaryDecoder(buffer)
 | 
					  let decoder = new BinaryDecoder(buffer)
 | 
				
			||||||
@ -52,6 +52,20 @@ export async function computeMessageUpdate (decoder, encoder, conn) {
 | 
				
			|||||||
  conn.y.db.applyOperations(decoder)
 | 
					  conn.y.db.applyOperations(decoder)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function sendSyncStep1 (conn, syncUser) {
 | 
				
			||||||
 | 
					  conn.y.db.requestTransaction(function * () {
 | 
				
			||||||
 | 
					    let encoder = new BinaryEncoder()
 | 
				
			||||||
 | 
					    encoder.writeVarString(conn.opts.room || '')
 | 
				
			||||||
 | 
					    encoder.writeVarString('sync step 1')
 | 
				
			||||||
 | 
					    encoder.writeVarString(conn.authInfo || '')
 | 
				
			||||||
 | 
					    encoder.writeVarUint(conn.protocolVersion)
 | 
				
			||||||
 | 
					    let preferUntransformed = conn.preferUntransformed && this.os.length === 0 // TODO: length may not be defined
 | 
				
			||||||
 | 
					    encoder.writeUint8(preferUntransformed ? 1 : 0)
 | 
				
			||||||
 | 
					    yield * this.writeStateSet(encoder)
 | 
				
			||||||
 | 
					    conn.send(syncUser, encoder.createBuffer())
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export function logMessageSyncStep1 (decoder, strBuilder) {
 | 
					export function logMessageSyncStep1 (decoder, strBuilder) {
 | 
				
			||||||
  let auth = decoder.readVarString()
 | 
					  let auth = decoder.readVarString()
 | 
				
			||||||
  let protocolVersion = decoder.readVarUint()
 | 
					  let protocolVersion = decoder.readVarUint()
 | 
				
			||||||
@ -78,13 +92,7 @@ export async function computeMessageSyncStep1 (decoder, encoder, conn, senderCon
 | 
				
			|||||||
    conn.y.destroy()
 | 
					    conn.y.destroy()
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (conn.role === 'slave') {
 | 
					  // send sync step 2
 | 
				
			||||||
    // wait for sync step 2 to complete
 | 
					 | 
				
			||||||
    await Promise.all(Array.from(conn.connections.values())
 | 
					 | 
				
			||||||
      .filter(conn => conn.role === 'master')
 | 
					 | 
				
			||||||
      .map(conn => conn.syncStep2.promise)
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  conn.y.db.requestTransaction(function * () {
 | 
					  conn.y.db.requestTransaction(function * () {
 | 
				
			||||||
    encoder.writeVarString('sync step 2')
 | 
					    encoder.writeVarString('sync step 2')
 | 
				
			||||||
    encoder.writeVarString(conn.authInfo || '')
 | 
					    encoder.writeVarString(conn.authInfo || '')
 | 
				
			||||||
@ -100,7 +108,11 @@ export async function computeMessageSyncStep1 (decoder, encoder, conn, senderCon
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    yield * this.writeDeleteSet(encoder)
 | 
					    yield * this.writeDeleteSet(encoder)
 | 
				
			||||||
    conn.send(senderConn.uid, encoder.createBuffer())
 | 
					    conn.send(senderConn.uid, encoder.createBuffer())
 | 
				
			||||||
 | 
					    senderConn.receivedSyncStep2 = true
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
					  if (conn.role === 'slave') {
 | 
				
			||||||
 | 
					    sendSyncStep1(conn, sender)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  await conn.y.db.whenTransactionsFinished()
 | 
					  await conn.y.db.whenTransactionsFinished()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user