peer-connection/helpers/data-channel/createDataChannel.js

import Skylink from '../../../index';
import logger from '../../../logger';
import { DATA_CHANNEL_TYPE, PEER_CONNECTION_STATE, DATA_CHANNEL_STATE } from '../../../constants';
import callbacks from './callbacks/index';
import { onDataChannelStateChanged } from '../../../skylink-events/datachannel-events';
import PeerConnection from '../..';
import { dispatchEvent } from '../../../utils/skylinkEventManager';
import HandleDataChannelStats from '../../../skylink-stats/handleDataChannelStats';

/* eslint-disable prefer-const */
/**
 * @param params
 * @returns {null}
 * @memberOf PeerConnection.PeerConnectionHelpers
 * @fires onDataChannelStateChanged
 */
const createDataChannel = (params) => {
  let {
    peerId,
    dataChannel,
    bufferThreshold,
    createAsMessagingChannel,
    roomState,
  } = params;
  const state = Skylink.getSkylinkState(roomState.room.id);
  const { user, peerConnections, dataChannels } = state;
  const peerConnection = peerConnections[peerId];
  let channelName = `-_${peerId}`;
  let channelType = createAsMessagingChannel === true ? DATA_CHANNEL_TYPE.MESSAGING : DATA_CHANNEL_TYPE.DATA;
  let channelProp = channelType === DATA_CHANNEL_TYPE.MESSAGING ? 'main' : channelName;
  if (user && user.sid) {
    channelName = `${user.sid}_${peerId}`;
  } else {
    logger.log.ERROR([peerId, 'RTCDataChannel', channelProp, 'Aborting of creating or initializing DataChannel as User does not have Room session']);
    return null;
  }

  if (!(peerConnection && peerConnection.signalingState !== PEER_CONNECTION_STATE.CLOSED)) {
    logger.log.ERROR([peerId, 'RTCDataChannel', channelProp, 'Aborting of creating or initializing Datachannel as Peer connection does not exists']);
    return null;
  }

  if (dataChannel && typeof dataChannel === 'object') {
    channelName = dataChannel.label;
  } else if (typeof dataChannel === 'string') {
    channelName = dataChannel;
    dataChannel = null;
  }

  if (!dataChannels[peerId]) {
    channelProp = 'main';
    channelType = DATA_CHANNEL_TYPE.MESSAGING;
    dataChannels[peerId] = {};
    logger.log.DEBUG([peerId, 'RTCDataChannel', channelProp, 'initializing main DataChannel']);
  } else if (dataChannels[peerId].main && dataChannels[peerId].main.channel.label === channelName) {
    channelProp = 'main';
    channelType = DATA_CHANNEL_TYPE.MESSAGING;
  }

  if (!dataChannel) {
    try {
      dataChannel = peerConnection.createDataChannel(channelName, {
        reliable: true,
        ordered: true,
      });
    } catch (error) {
      logger.log.ERROR([peerId, 'RTCDataChannel', channelProp, 'Failed creating Datachannel ->'], error);

      const handleDataChannelStats = new HandleDataChannelStats();
      const { room } = roomState;

      handleDataChannelStats.send(room.id, DATA_CHANNEL_STATE.ERROR, peerId, { label: channelName }, channelProp, error);
      dispatchEvent(onDataChannelStateChanged({
        state: DATA_CHANNEL_STATE.CREATE_ERROR,
        peerId,
        error,
        channelName,
        channelType,
        buferAmount: PeerConnection.getDataChannelBuffer(dataChannel),
      }));
      return null;
    }
  }

  const callbackExtraParams = {
    dataChannel,
    peerId,
    channelName,
    channelProp,
    channelType,
    roomState,
    bufferThreshold,
  };

  dataChannel.onopen = callbacks.onopen.bind(dataChannel, callbackExtraParams);
  dataChannel.onmessage = callbacks.onmessage.bind(dataChannel, callbackExtraParams);
  dataChannel.onerror = callbacks.onerror.bind(dataChannel, callbackExtraParams);
  dataChannel.onbufferedamountlow = callbacks.onbufferedamountlow.bind(dataChannel, callbackExtraParams);
  dataChannel.onclose = callbacks.onclose.bind(dataChannel, callbackExtraParams);

  const channel = channelType === DATA_CHANNEL_TYPE.MESSAGING ? 'main' : channelName;
  state.dataChannels[peerId][channel] = {
    channelName,
    channelType,
    transferId: null,
    streamId: null,
    channel: dataChannel,
  };

  Skylink.setSkylinkState(state, roomState.room.id);

  return null;
};

export default createDataChannel;