Skip to content
Snippets Groups Projects
index.js 4.12 KiB
Newer Older
/* global Y */
"use strict"

import LioWebRTC from "liowebrtc"

function extend(Y) {
  class WebRTC extends Y.AbstractConnector {
    constructor(y, options) {
      if (options === undefined) {
        throw new Error("Options must not be undefined!")
      }

      options.role = "slave"
      super(y, options)
      this.webrtcOptions = options

      if (options.onUserEvent) {
        this.onUserEvent(options.onUserEvent)
      }

      window.addEventListener("unload", () => {
        this.y.destroy()
      })
        url: this.webrtcOptions.url,
        dataOnly: true,
      this.webrtc.on("ready", () => {
        this.webrtc.joinRoom(this.webrtcOptions.room)
      })
      this.webrtc.on("joinedRoom", () => {
        this.checkAndEnsureUser()
      this.webrtc.on("leftRoom", () => {
        console.log("LEFT ROOM")
      })

      this.webrtc.on("channelOpen", (dataChannel, peer) => {
        this.checkAndEnsureUser()

        // Start a handshake to ensure both sides are able to use the channel
        function handshake(peer) {
          const _peer = this.webrtc.getPeerById(peer.id)

          if (!_peer || _peer !== peer) {
            return
          }
          if (this.peers.has(peer.id)) {
            return
          }

          console.log("ping", peer.id)

          // Initial message in the handshake
          this.webrtc.whisper(peer, "tw-ml", "tw")

          setTimeout(handshake.bind(this, peer), 500)
      this.webrtc.on("receivedPeerData", (type, message, peer) => {
        this.checkAndEnsureUser()
        if (message.type !== "update") {
          console.log("receivedData", peer.id, message)
        }

        if (type === "y-js") {
          this.checkAndInsertPeer(peer.id)
          this.receiveMessage(peer.id, message)
        } else if (type === "tw-ml") {
          if (message === "tw") {
            // Response message in the handshake
            this.webrtc.whisper(peer, "tw-ml", "ml")
          } else if (message == "ml") {
            // Handshake completed
            this.checkAndInsertPeer(peer.id)
          }
        }
      this.webrtc.on("channelClose", (dataChannel, peer) => {
        this.checkAndEnsureUser()
        this.checkAndRemovePeer(peer.id)
    // Ensure that y-js is up to date on the user's id
    checkAndEnsureUser() {
      const id = this.webrtc.getMyId()

      if (this.y.db.userId === id) {
        return
      }

Nayeem Rahman's avatar
Nayeem Rahman committed
      for (const f of this.userEventListeners) {
        f({ action: "userID", id: id })
      }

      this.setUserId(id)
    }

    // Ensure that y-js knows that the peer has joined
    checkAndInsertPeer(uid) {
      if (this.peers.has(uid)) {
        return
      }

      this.peers.add(uid)

      console.log("createdPeer", uid)

      this.userJoined(uid, "master")
    }

    // Ensure that y-js knows that the peer has left
    checkAndRemovePeer(uid) {
      if (!this.peers.has(uid)) {
        return
      }

      this.peers.delete(uid)

      console.log("removedPeer", uid)

      this.userLeft(uid)
    }

    connectToPeer(/*uid*/) {
      // currently deprecated
      super.disconnect()
    }

    reconnect() {
      // y-js db transactions can send messages after a peer has disconnected
      if (!this.peers.has(uid) || !this.webrtc.getPeerById(uid)) {
        return
      }

      console.log("send", uid, message)

      this.webrtc.whisper(this.webrtc.getPeerById(uid), "y-js", message)
      if (message.type !== "update") console.log("broadcast", message)

      this.webrtc.shout("y-js", message)

    isDisconnected() {
      return false
    }
  }

  Y.extend("webrtc", WebRTC)
}

Nayeem Rahman's avatar
Nayeem Rahman committed
export default extend
if (typeof Y !== "undefined") {
  extend(Y)
}