API Docs for:
Show:

File: src/signaling/muc_signaling.coffee

{Deferred} = require('../internal/promise')
{Signaling,SignalingPeer} = require('./signaling')
EventEmitter = require('events').EventEmitter

###*
# @module rtc.signaling
###

###*
# Signaling peer for multi user chats.
#
# For a detailed description of the signaling protocol see `rtc.signaling.MucSignaling`
#
# @extends rtc.signaling.SignalingPeer
# @class rtc.signaling.MucSignalingPeer
#
# @constructor
# @param {rtc.signaling.Channel} channel The channel to the siganling server
# @param {String} peer_id The id of the remote peer
# @param {Object} status The status of the remote peer
# @param {Boolean} first Whether the local peer was in the room before the remote peer
###
class exports.MucSignalingPeer extends SignalingPeer

  ###*
  # The id of the remote peer
  # @property id
  # @type String
  ###

  constructor: (@channel, @id, @status, @first) ->
    recv_msg = (data) =>
      if data.peer != @id
        # message is not for us
        return

      if not data.type?
        # invalid message
        return

      switch data.type
        when 'from'
          if not data.event? or not data.data?
            # invalid message
            return

          @emit(data.event, data.data)

        when 'peer_left'
          @emit('left')
          @channel.removeListener('message', recv_msg)

        when 'peer_status'
          @status = data.status
          @emit('status_changed', @status)

    @channel.on('message', recv_msg)


  send: (event, data={}) ->
    return @channel.send({
      type: 'to'
      peer: @id
      event: event
      data: data
    })


###*
# Signaling for multi user chats
#
# The following messages are sent to the server:
#
#     // join the room. has to be sent before any other message.
#     // response will be 'joined' on success
#     // other peers in the room will get 'peer_joined'
#     {
#       "type": "join",
#       "status": { .. status .. }
#     }
#
#     // leave the room. server will close the connectino.
#     {
#       "type": "leave"
#     }
#
#     // update status object
#     // other peers will get 'peer_status'
#     {
#       "type": "status",
#       "status": { .. status .. }
#     }
#
#     // send message to a peer. will be received as 'from'
#     {
#       "type": "to",
#       "peer": "peer_id",
#       "event": "event_id",
#       "data": { .. custom data .. }
#     }
#
# The following messages are received form the server:
#
#     // joined the room. is the response to 'join'
#     {
#       "type": "joined",
#       "id": "own_id",
#       "peers": {
#         "peer_id": { .. status .. }
#       }
#     }
#
#     // another peer joined the room.
#     {
#       "type": "peer_joined",
#       "peer": "peer_id",
#       "status": { .. status .. }
#     }
#
#     // anosther peer updated its status object using 'status'
#     {
#       "type": "peer_status",
#       "peer": "peer_id",
#       "status": { .. status .. }
#     }
#
#     // another peer left the room
#     {
#       "type": "peer_left",
#       "peer": "peer_id"
#     }
#
#     // message from another peer sent by 'to'
#     {
#       "type": "from",
#       "peer": "peer_id",
#       "event": "event_id",
#       "data": { .. custom data .. }
#     }
#
# The messages transmitted in the `to`/`from` messages are emitted as events in `MucSignalingPeer`
#
# @extends rtc.signaling.Signaling
# @class rtc.signaling.MucSignaling
#
# @constructor
# @param {rtc.signaling.Channel} channel The channel to the signaling server
###
class exports.MucSignaling extends Signaling

  ###*
  # The id of the local peer. Only available after joining.
  # @property id
  # @type String
  ###

  constructor: (@channel) ->
    @status = {}

    join_d = new Deferred()
    @join_p = join_d.promise

    @channel.on 'closed', () =>
      @emit('closed')

    @channel.on 'message', (data) =>
      if not data.type?
        # invalid message
        return

      switch data.type
        when 'joined'
          if not data.peers?
            # invalid ...
            return

          for peer_id, status of data.peers
            peer = new exports.MucSignalingPeer(@channel, peer_id, status, false)
            @emit('peer_joined', peer)

          @id = data.id

          join_d.resolve()

        when 'peer_joined'
          if not data.peer?
            # invalid ...
            return

          peer = new exports.MucSignalingPeer(@channel, data.peer, data.status, true)
          @emit('peer_joined', peer)


  connect: () ->
    if not @connect_p?
      @connect_p = @channel.connect().then () =>
        return @channel.send({
          type: 'join'
          status: @status
        })
      .then () =>
        return @join_d

    return @connect_p


  setStatus: (status) ->
    @status = status

    if @connect_p
      @connect_p.then () =>
        return @channel.send({
          type: 'status'
          status: status
        })


  leave: () ->
    @channel.send({
      type: 'leave'
    }).then () ->
      @channel.close()