I have a file sharing app (Client1 sends large file to Client2) implemented with Electron. Client1 open a large file and stream it to Client2 in data chunk with fs.createReadStream. The problem I have is that the Client2 data channel does not received any chunk until all chunks are finished sending by Client1.
BTW, it cause WebRTC connection to drop as well depending on file size , such as 200MB(and PC memory possibly, such 16GB). For smaller file, everything works.
What I suspect is that fs.createReadStream on(‘data’…) handler is a loop, and PeerJS webrtc send() function is blocked, until all chunks are sent.
Here is the main pseudo code:
- Electron main process open file, and File is opened with fs.createReadStream
icpMain_process.js
// Handler to process ipcRederer UI file open. It store file handle in main process.
ipcMain.handle(READ_FILE_CHUNK_OPEN, async (event, fullFileName) => {
let fileSize = 4 x 1024;
// Default format is uint8array, not utf8.
this.readStream = fs.createReadStream(fullFileName, {highWaterMark: chunkSize})
// icpRederer process makes RPC call to ipcMain process to trigger chunk read flowing from main to UI process.
ipcMain.on(handlerName.READ_FILE_CHUNK_NEXT, (event, arg) => {
this.readStream.on('data', (chunk) => {
this.win.webContents.send(READ_FILE_CHUNK_NEXT_RESP, chunk});
- This is Renderer process.
icpRederer_process.js
// Process file chunks from main process.
// All chunks are streamed here to peerjs_send_data in peeerjs_data.js, such as 10000 chunks.
ipcRenderer.on(READ_FILE_CHUNK_NEXT_RESP, (event, fileChunk) => {
// Is there a loop in fs.createReadStream? If it’s a loop, it will block webrtc data channel?
peerjs_send_chunk(fileChunk);
- PeerJS code.
// peerjs_dataconnection is PeerJS data channel.
// Sender
peerjs_send_chunk(fileChunk) {
let packet = (fileChunk converts to packet)
peerjs_send_data(packet);
}
peerjs_send_data(packet) {
peerjs_dataconnection.send(packet);
}
// Receiver handler
// Problem: packet is not received until all 10000 chunks are sent from sender.
peerjs_dataconnection.on('data', (packet) => {
dispatchpacket(packet);
});
dispatchpacket(packet) {
}
I tried to use “recursive scheme” and setTimeout() to make peerjs webrtc send() to be executed in a recursive call triggered by setTimeout(), but I am not convinced it can solve it (result is uncertain).
Tried this unblocking without luck, it's still blocked.
peerjs_send_data(packet) {
unblockTask(peerjs_dataconnection, peerjs_dataconnection.send, packet);
}
function unblockTask(context, fn, param) {
let index = 0;
function doChunk() {
if (index == 1) {
let ret = fn.call(context, param);
}
index += 1;
setTimeout(doChunk, 1);
}
doChunk();
}
If open a large file in main process with fs.readFileSync() and send all file content to renderer process, and use a similar technique used unblockTask() function to break it apart as chunks, loop through the chunks to send to Client2, all works. But, it's limited by file size depending on PC memory.
What’s the reason of blocking: Client2 does not receive any packet until all chunks are sent by Client1? How to solve it?