Peerjs sending multiple messages from same connection?

78 Views Asked by At

I am trying to set up a peer to peer file transfer but I want to be able to track download progress so I am sending the file in chunks. It's worth noting that I am able to send the entire file but then I can't keep track of download progress.

I am having issues with the way I am setting up a connection and sending a message. On the Peerjs documentation it says to call send inside of conn.on('open') listener. So I figured I would set up a class to create a Peer and keep track of connections.

I am abstracting away the creation of the Peer instance with a class like so:

export default class PeerInstance {
  instance: Peer | null
  uId: string
  dataListeners: DataListeners
  connections: { [key: string]: DataConnection }

  constructor(uId: string, accessToken: string) {
    this.instance = null
    this.uId = uId
    this.connections = {}

    this.dataListeners = {
      ['message']: new Set(),
      ['file:start']: new Set(),
      ['file:chunk:send']: new Set(),
      ['file:chunk:received']: new Set(),
      ['file:done']: new Set(),
      ['file:downloaded']: new Set(),
      ['file:accept']: new Set(),
      ['file:reject']: new Set(),
      ['status:check']: new Set(),
      ['status:response']: new Set(),
      ['status:disconnected']: new Set(),
    }

    this.init(accessToken)
  }

  async init(accessToken: string) {
    if (this.instance) return

    const { Peer } = await import('peerjs')

    this.instance = new Peer(this.uId, {
      token: accessToken,
      host: config.peerHost,
      port: config.peerPort,
      path: config.peerPath,
    })

    this.instance.on('connection', (conn) => {
      conn.on('data', this.onData)
    })
  }

  destroy = () => {
    if (!this.instance) return
    this.instance.destroy()
  }

  onData = (data: any) => {
    this.fireDataListeners(data.type, data)
  }

  addDataListener = <T>(e: keyof DataListeners, fn: DataListener<T>) => {
    if (this.dataListeners[e]) {
      this.dataListeners[e].add(fn)
    }
  }

  removeDataListener = <T>(e: keyof DataListeners, fn: DataListener<T>) => {
    if (this.dataListeners[e]) {
      this.dataListeners[e].delete(fn)
    }
  }

  fireDataListeners = <T>(e: keyof DataListeners, data: any) => {
    if (this.dataListeners[e]) {
      this.dataListeners[e].forEach((listener: DataListener<T>) => {
        listener(data)
      })
    }
  }

  createConnection = (to: string) => {
    if (!this.instance) return

    const conn = this.instance.connect(to)
    this.connections[to] = conn

    conn.on('error', (err) => {
      console.log(err)
    })

    return conn
  }

  send = (type: string, to: string, payload?: any) => {
    if (!this.instance) return

    if (!this.connections[to]) {
      this.createConnection(to)
    }

    const conn = this.connections[to]

    console.log('isOpen', conn.open)

    conn.on('open', () => {
      conn.send({
        type,
        to,
        from: this.uId,
        payload,
      })
    })
  }
}

I think the main issue may be in my send function.

send = (type: string, to: string, payload?: any) => {
  if (!this.instance) return

  if (!this.connections[to]) {
    this.createConnection(to)
  }

  const conn = this.connections[to]

  console.log('isOpen', conn.open)

  conn.on('open', () => {
    conn.send({
      type,
      to,
      from: this.uId,
      payload,
    })
  })
}

I can only seem to send messages through the conn.on('open') listener. If I remove that wrapping the send() function then I get an error Error: Connection is not open. You should listen for the open event before sending messages.. But if I keep that then I am not able to send more than one message if I handle this with a button.

So how would I go about sending multiple messages? More notably a large amount of messages consecutively. Because I need to send a huge amount of messages at once. If I close the connection after sending then I get an error Failed to construct 'RTCPeerConnection': Cannot create so many PeerConnections. So doing this wont work.

send = (type: string, to: string, payload?: any) => {
  if (!this.instance) return

  const conn = this.instance.connect(to)

  conn.on('open', () => {
    conn.send({
      type,
      to,
      from: this.uId,
      payload,
    })
    conn.close()
  })
}

In my actual code I am trying to send files in ArrayBuffers and then rebuild them on the receiving side. But I want to track the download progress from one side to another. I am sending them in 16kb chunks so you can see how in something like a 1gb or 2gb file there would be a huge number of chunks that I would need to send. Right now I can only get about 20-30 16kb chunks through before I just get nothing.

if anyone has any insight here it would be appreciated because I am at a loss right now.

0

There are 0 best solutions below