To actually send the data after the user chooses a file, the “sendFile” function is called when the user clicks the "Send File" button. It retrieves the selected file from the file input, reads its content as an ArrayBuffer, and converts it to Base64 using the arrayBufferToBase64 function. The file data, user's name, and file type are sent to the server as a JSON message via WebSocket. The file input is cleared after sending the file.
The arrayBufferToBase64 function converts an ArrayBuffer to a Base64-encoded string. It processes the buffer in chunks to avoid stack size issues.
Remember that when the previous function in the previous screenshot line 88 calls the “arrayBufferToBase64.” This is the function. Its main purpose is to convert the arrayBuffer to Base64. This is how it works.
At this point, the file would be sent to the peer but to display it so that it can be downloaded, we need the displayFile() function
The b64toBlob function converts a Base64-encoded string to a Blob object. It processes Base64 data in slices to create a Uint8Array and then constructs a Blob from the byte arrays.
Lastly, we will finish off by making sure that the onmessage function which is very much the same as the texting application with only a few changes.
From the texting application, I have used the same code essentially but this time, I have created an alert so that when a user opens the link and connects, the peer can be alerted that the user is connected. This is seen in line 53.
The whole data.php document should look as shown below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebRTC File Transfer Example</title>
<style>
#chatBox {
width: 300px;
margin: 20px;
}
#fileInput {
margin-top: 10px;
}
</style>
</head>
<body>
<h1>WebRTC File Transfer Example</h1>
<div id="chatBox"></div>
<input type="file" id="fileInput">
<button onclick="sendFile()">Send File</button>
<script>
const chatBox = document.getElementById('chatBox');
const fileInput = document.getElementById('fileInput');
let ws;
let peer;
// Prompt user for name
const userName = prompt('Enter your name:');
if (!userName) {
alert('Please enter a name.');
window.location.reload();
}
function initWebSocket() {
ws = new WebSocket('ws://192.168.43.141:3000');
ws.onopen = () => {
console.log('WebSocket connection opened');
// Send the user's name to the server upon connection
ws.send(JSON.stringify({ "name": userName }));
};
ws.onmessage = async (event) => {
try {
const data = JSON.parse(await event.data.text());
if (data.name) {
peer = data.name;
alert(peer+" has connected");
}
if (data.file && data.name && data.fileType) {
// Handle file-related messages
displayFile(data.file, data.name, data.fileType);
} else {
console.warn('Invalid message format:', data);
}
} catch (error) {
console.error('Error parsing JSON:', error);
}
};
ws.onclose = () => {
console.log('WebSocket connection closed');
};
}
function displayFile(fileData, sender, fileType) {
const blob = b64toBlob(fileData, fileType);
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = `${sender}_file.${fileType.split('/')[1] || 'bin'}`;
downloadLink.textContent = `${sender} sent a file - Click to download`;
chatBox.appendChild(downloadLink);
}
function sendFile() {
const file = fileInput.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
const fileType = file.type || 'application/octet-stream';
const base64Data = arrayBufferToBase64(reader.result);
ws.send(JSON.stringify({ "file": base64Data, "name": userName, "fileType": fileType }));
// Clear the file input after sending the file
fileInput.value = null;
};
reader.readAsArrayBuffer(file);
}
}
function arrayBufferToBase64(buffer) {
const CHUNK_SIZE = 0x8000; // 32 KB chunks
const bytes = new Uint8Array(buffer);
const byteArrays = [];
for (let offset = 0; offset < bytes.length; offset += CHUNK_SIZE) {
const chunk = bytes.subarray(offset, offset + CHUNK_SIZE);
byteArrays.push(String.fromCharCode.apply(null, chunk));
}
return btoa(byteArrays.join(''));
}
function b64toBlob(b64Data, contentType = '', sliceSize = 512) {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, { type: contentType });
return blob;
}
initWebSocket();
</script>
</body>
</html>
You can test it on your local area network or open two browsers and see if you are able to transmit. Remember to run the page from the webserver. If you test on 2 different computers and used a local IP address for the WebSocket connection, then make sure both computers are on the same network.
The file should be able to send after both clients connect and insert their names.