base-node.js
function BaseNode (nodeId, log, connection, options) {
  /**
   * Unique current machine name.
   * @type {string}
   *
   * @example
   * console.log(node.localNodeId + ' is started')
   */
  this.localNodeId = nodeId
  /**
   * Log for synchronization.
   * @type {Log}
   */
  this.log = log
  /**
   * Connection used to communicate to remote node.
   * @type {Connection}
   */
  this.connection = connection
  /**
   * Synchronization options.
   * @type {object}
   */
  this.options = options || { }

  if (this.options.ping && !this.options.timeout) {
    throw new Error('You must set timeout option to use ping')
  }

  /**
   * Is synchronization in process.
   * @type {boolean}
   *
   * @example
   * node.on('disconnect', () => {
   *   node.connected //=> false
   * })
   */
  this.connected = false

  /**
   * Did we finish remote node authentication.
   * @type {boolean}
   */
  this.authenticated = false
  this.unauthenticated = []

  this.timeFix = 0
  this.syncing = 0
  this.received = { }

  /**
   * Latest current log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastSent = 0
  /**
   * Latest remote node’s log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastReceived = 0

  /**
   * Current synchronization state.
   *
   * * `disconnected`: no connection, but no new actions to synchronization.
   * * `connecting`: connection was started and we wait for node answer.
   * * `sending`: new actions was sent, waiting for answer.
   * * `synchronized`: all actions was synchronized and we keep connection.
   *
   * @type {"disconnected"|"connecting"|"sending"|"synchronized"}
   *
   * @example
   * node.on('state', () => {
   *   if (node.state === 'sending') {
   *     console.log('Do not close browser')
   *   }
   * })
   */
  this.state = 'disconnected'

  this.emitter = new NanoEvents()
  this.timeouts = []
  this.throwsError = true

  this.unbind = []
  var node = this
  this.unbind.push(log.on('add', function (action, meta) {
    node.onAdd(action, meta)
  }))
  this.unbind.push(connection.on('connecting', function () {
    node.onConnecting()
  }))
  this.unbind.push(connection.on('connect', function () {
    node.onConnect()
  }))
  this.unbind.push(connection.on('message', function (message) {
    node.onMessage(message)
  }))
  this.unbind.push(connection.on('error', function (error) {
    if (error.message === 'Wrong message format') {
      node.sendError(new LoguxError('wrong-format', error.received))
      node.connection.disconnect('error')
    } else {
      node.error(error)
    }
  }))
  this.unbind.push(connection.on('disconnect', function () {
    node.onDisconnect()
  }))

  this.initialized = false
  this.lastAddedCache = 0
  this.initializing = this.initialize()
}
function BaseNode (nodeId, log, connection, options) {
  /**
   * Unique current machine name.
   * @type {string}
   *
   * @example
   * console.log(node.localNodeId + ' is started')
   */
  this.localNodeId = nodeId
  /**
   * Log for synchronization.
   * @type {Log}
   */
  this.log = log
  /**
   * Connection used to communicate to remote node.
   * @type {Connection}
   */
  this.connection = connection
  /**
   * Synchronization options.
   * @type {object}
   */
  this.options = options || { }

  if (this.options.ping && !this.options.timeout) {
    throw new Error('You must set timeout option to use ping')
  }

  /**
   * Is synchronization in process.
   * @type {boolean}
   *
   * @example
   * node.on('disconnect', () => {
   *   node.connected //=> false
   * })
   */
  this.connected = false

  /**
   * Did we finish remote node authentication.
   * @type {boolean}
   */
  this.authenticated = false
  this.unauthenticated = []

  this.timeFix = 0
  this.syncing = 0
  this.received = { }

  /**
   * Latest current log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastSent = 0
  /**
   * Latest remote node’s log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */
  this.lastReceived = 0

  /**
   * Current synchronization state.
   *
   * * `disconnected`: no connection, but no new actions to synchronization.
   * * `connecting`: connection was started and we wait for node answer.
   * * `sending`: new actions was sent, waiting for answer.
   * * `synchronized`: all actions was synchronized and we keep connection.
   *
   * @type {"disconnected"|"connecting"|"sending"|"synchronized"}
   *
   * @example
   * node.on('state', () => {
   *   if (node.state === 'sending') {
   *     console.log('Do not close browser')
   *   }
   * })
   */
  this.state = 'disconnected'

  this.emitter = new NanoEvents()
  this.timeouts = []
  this.throwsError = true

  this.unbind = []
  var node = this
  this.unbind.push(log.on('add', function (action, meta) {
    node.onAdd(action, meta)
  }))
  this.unbind.push(connection.on('connecting', function () {
    node.onConnecting()
  }))
  this.unbind.push(connection.on('connect', function () {
    node.onConnect()
  }))
  this.unbind.push(connection.on('message', function (message) {
    node.onMessage(message)
  }))
  this.unbind.push(connection.on('error', function (error) {
    if (error.message === 'Wrong message format') {
      node.sendError(new LoguxError('wrong-format', error.received))
      node.connection.disconnect('error')
    } else {
      node.error(error)
    }
  }))
  this.unbind.push(connection.on('disconnect', function () {
    node.onDisconnect()
  }))

  this.initialized = false
  this.lastAddedCache = 0
  this.initializing = this.initialize()
}
function BaseNode ( nodeId , log , connection , options ) { /**
   * Unique current machine name.
   * @type {string}
   *
   * @example
   * console.log(node.localNodeId + ' is started')
   */ this . localNodeId = nodeId /**
   * Log for synchronization.
   * @type {Log}
   */ this . log = log /**
   * Connection used to communicate to remote node.
   * @type {Connection}
   */ this . connection = connection /**
   * Synchronization options.
   * @type {object}
   */ this . options = options || { } if ( this . options . ping && ! this . options . timeout ) { throw new Error ( 'You must set timeout option to use ping' ) } /**
   * Is synchronization in process.
   * @type {boolean}
   *
   * @example
   * node.on('disconnect', () => {
   *   node.connected //=> false
   * })
   */ this . connected = false /**
   * Did we finish remote node authentication.
   * @type {boolean}
   */ this . authenticated = false this . unauthenticated = [ ] this . timeFix = 0 this . syncing = 0 this . received = { } /**
   * Latest current log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */ this . lastSent = 0 /**
   * Latest remote node’s log `added` time, which was successfully synchronized.
   * It will be saves in log store.
   * @type {number}
   */ this . lastReceived = 0 /**
   * Current synchronization state.
   *
   * * `disconnected`: no connection, but no new actions to synchronization.
   * * `connecting`: connection was started and we wait for node answer.
   * * `sending`: new actions was sent, waiting for answer.
   * * `synchronized`: all actions was synchronized and we keep connection.
   *
   * @type {"disconnected"|"connecting"|"sending"|"synchronized"}
   *
   * @example
   * node.on('state', () => {
   *   if (node.state === 'sending') {
   *     console.log('Do not close browser')
   *   }
   * })
   */ this . state = 'disconnected' this . emitter = new NanoEvents ( ) this . timeouts = [ ] this . throwsError = true this . unbind = [ ] var node = this this . unbind . push ( log . on ( 'add' , function ( action , meta ) { node . onAdd ( action , meta ) } ) ) this . unbind . push ( connection . on ( 'connecting' , function ( ) { node . onConnecting ( ) } ) ) this . unbind . push ( connection . on ( 'connect' , function ( ) { node . onConnect ( ) } ) ) this . unbind . push ( connection . on ( 'message' , function ( message ) { node . onMessage ( message ) } ) ) this . unbind . push ( connection . on ( 'error' , function ( error ) { if ( error . message === 'Wrong message format' ) { node . sendError ( new LoguxError ( 'wrong-format' , error . received ) ) node . connection . disconnect ( 'error' ) } else { node . error ( error ) } } ) ) this . unbind . push ( connection . on ( 'disconnect' , function ( ) { node . onDisconnect ( ) } ) ) this . initialized = false this . lastAddedCache = 0 this . initializing = this . initialize ( ) }
Base methods for synchronization nodes. Client and server nodes
are based on this module.

@param {string} nodeId Unique current machine name.
@param {Log} log Logux log instance to be synchronized.
@param {Connection} connection Connection to remote node.
@param {object} [options] Synchronization options.
@param {object} [options.credentials] Client credentials.
For example, access token.
@param {authCallback} [options.auth] Function to check client credentials.
@param {boolean} [options.fixTime=false] Detect difference between client
and server and fix time
in synchronized actions.
@param {number} [options.timeout=0] Timeout in milliseconds to wait answer
before disconnect.
@param {number} [options.ping=0] Milliseconds since last message to test
connection by sending ping.
@param {filter} [options.inFilter] Function to filter actions
from remote node. Best place
for access control.
@param {mapper} [options.inMap] Map function to change remote node’s action
before put it to current log.
@param {filter} [options.outFilter] Filter function to select actions
to synchronization.
@param {mapper} [options.outMap] Map function to change action
before sending it to remote client.
@param {string} [options.subprotocol] Application subprotocol version
in SemVer format.

@abstract
@class
Base methods for synchronization nodes . Client and server nodes are based on this module .