1

I am creating a chat app (in React Native), but for now, I have made some tests in vanilla JavaScript. The server is a NodeJS-server.

It works with sending text messages, but now I have some questions about sending photos/videos/audio files. I'm doing a lot of research online on what's the best method to do this.

I came up with the idea to use the FileReader API and split up the file into chunks, and sending chunk by chunk via the socket.emit()-function.

This is my code so far (simplified):

Please note that I will create a React Native app, but for now (for testing), I've just created a HTML-file with an upload form.

// index.html
// the page where my upload form is

var reader = {};
var file = {};
var sliceSize = 1000 * 1024;
var socket = io('http://localhost:8080');

const startUpload = e => {
    e.preventDefault();
    reader = new FileReader();
    file = $('#file)[0].files[0]
    uploadFile(0)
}

$('#start-upload').on('click', startUpload)

const uploadFile = start => {
    var slice = start + sliceSize + 1;
    var blob = file.slice(start, slice)
    reader.on('loadend', e => {
        if (slice < file.size) {
            socket.emit('message', JSON.stringify({
                fileName: file.name,
                fileType: file.type,
                fileChunk: e.target.result
            })
        } else {
            console.log('Upload completed!')
        }
    })
    reader.readAsDataURl(blob) 
}

// app.js
// my NodeJS server-file

var file;
var files = {};

io.on('connection', socket => {
    console.log('User connected!');

    // when a message is received
    socket.on('message', data => {
        file = JSON.parse(data)
        if (!files[file.fileName]) {
            // this is the first chunk received
            // create a new string
            files[file.fileName] = '';
        }
        // append the binary data
        files[file.fileName] = files[file.fileName] + file.fileChunk;
    })

    // on disconnect
    socket.on('disconnect', () => {
        console.log('User disconnected!');
    })
})

I did not include any checks for file type (I'm not at that point yet), I first want to make sure that this is the right thing to do.

Stuff I need to do:

  • Send a message (like socket.emit('uploaddone', ...)) from the client to the server to notify the server that the upload is done (and the server can emit the complete file to another user).

My questions are:

  • Is it okay to send chunks of binary data (base64) over a socket, or would it take up to much bandwidth?
  • Will I lose some quality (photos/videos/audio files) when splitting them up into chunks?

If there is a better way to do this, please let me know. I'm not asking for working code examples, just some guidance in the good direction.

2 Answers 2

2

You can send raw bytes over WebSocket, base64 has 33% size overhead.

Also you won't have to JSON.stringify all (and maybe large) body and parse it on client-side.

Will I lose some quality

No, underlying protocol (TCP) delivers data in-order and without corruption.

Sign up to request clarification or add additional context in comments.

Comments

0

I realize this answer is a couple of months late, but just for future reference you should look into using the acknowledgment option with socket.io here

  // with acknowledgement
  let message = JSON.stringify({
                fileName: file.name,
                fileType: file.type,
                fileChunk: e.target.result
            })
  socket.emit("message", message, (ack) => {
    // send next chunk...
  });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.