# # @overload createPeerJsConnector peerjs_options, callback # @param {Object} peerjs_options Is the options object that is passed to PeerJs. # @param {Function} callback The callback is called when the connector is initialized. # @overload createPeerJsConnector peerjs_user_id, peerjs_options, callback # @param {String} peerjs_user_id The user_id that is passed to PeerJs as the user_id and should be unique between all (also the unconnected) Peers. # @param {Object} peerjs_options Is the options object that is passed to PeerJs. # @param {Function} callback The callback is called when the connector is initialized. # createPeerJsConnector = ()-> peer = null if arguments.length is 2 peer = new Peer arguments[0] callback = arguments[1] else peer = new Peer arguments[0], arguments[1] peer.on 'error', (err)-> throw new Error "Peerjs connector: #{err}" peer.on 'disconnected', ()-> throw new Error "Peerjs connector disconnected from signalling server. Cannot accept new connections. Not fatal, but not so good either.." callback = arguments[2] # # PeerJs is a Framework that enables you to connect to other peers. You just need the # user-id of the peer (browser/client). And then you can connect to it. # @see http://peerjs.com # class PeerJsConnector # # @param {Engine} engine The transformation engine # @param {HistoryBuffer} HB # @param {Array} execution_listener You must ensure that whenever an operation is executed, every function in this Array is called. # @param {Yatta} yatta The Yatta framework. # constructor: (@engine, @HB, @execution_listener, @yatta)-> @peer = peer @connections = {} @new_connection_listeners = [] @peer.on 'connection', (conn)=> @addConnection conn sync_every_collaborator = ()=> for conn_id, conn of @connections conn.send sync_state_vector: @HB.getOperationCounter() setInterval sync_every_collaborator, 4000 send_ = (o)=> if o.uid.creator is @HB.getUserId() and (typeof o.uid.op_number isnt "string") for conn_id,conn of @connections conn.send op: o @execution_listener.push send_ # # Connect the Framework to another peer. Therefore you have to receive his # user_id. If the other peer is connected to other peers, the PeerJsConnector # will automatically connect to them too. # # Transmitting the user_id is your job. # See [TextEditing](../../examples/TextEditing/) for a nice example # on how to do that with urls. # # @param id {String} Connection id # connectToPeer: (id)-> if not @connections[id]? and id isnt @yatta.getUserId() @addConnection peer.connect id # # Receive the id of every connected peer. # @return {Array} A list of Peer-Ids # getAllConnectionIds: ()-> for conn_id of @connections conn_id onNewConnection: (f)-> @new_connection_listeners.push f # # Adds an existing connection to this connector. # @param conn {PeerJsConnection} # addConnection: (conn)-> # # What this method does: # * Send state vector # * Receive HB -> apply them # * Send connections # * Receive Connections -> Connect to unknow connections @connections[conn.peer] = conn initialized_me = false initialized_him = false conn.on 'data', (data)=> if data is "empty_message" # nop else if data.HB? initialized_me = true @engine.applyOpsCheckDouble data.HB if not data.initialized conn.send conns: @getAllConnectionIds() @new_connection_listeners.map (f)-> f(conn) else if data.op? @engine.applyOp data.op else if data.conns? for conn_id in data.conns @connectToPeer conn_id else if data.sync_state_vector? conn.send HB: @yatta.getHistoryBuffer()._encode(data.sync_state_vector) initialized: true else if data.state_vector? if not initialized_him # make sure, that it is sent only once conn.send HB: @yatta.getHistoryBuffer()._encode(data.state_vector) initialized: false initialized_him = true else throw new Error "Can't parse this operation: #{data}" sendStateVector = ()=> conn.send state_vector: @HB.getOperationCounter() if not initialized_me # Because of a bug in PeerJs, # we never know if state vector was actually sent setTimeout sendStateVector, 100 sendStateVector() peer.on 'open', (id)-> callback PeerJsConnector, id module.exports = createPeerJsConnector if window? if not window.Y? window.Y = {} window.Y.createPeerJsConnector = createPeerJsConnector