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.