I am attempting to create a chat app using socket.io on nodeJS and I want to add image transmission using the method outlined here
I'm running into an issue where if the image file is any larger than ~1MB, it seems to reset the connection and the io connection event is raised again (as the chat log gets re-sent).
Here is my code: CLIENTSIDE
<html>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 5rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#subBtn {background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; margin-bottom:5.3rem;bottom: 0; left: 200; right: 0; display: flex; height: 2rem; box-sizing: border-box; backdrop-filter: blur(10px);}
#img {background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; margin-bottom:5.3rem;bottom: 0; left: 200; right: 0; display: flex; height: 2rem; box-sizing: border-box; backdrop-filter: blur(10px);}
#nametag {background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed;margin-top:-0.05rem;top: 0; left: 0; right: 0; display: flex; height: 2rem; box-sizing: border-box; backdrop-filter: blur(10px);}
#messages { list-style-type: none; margin-bottom: 2rem; padding: 0; }
#messages > li { padding: 1rem 1rem; font-size:30px; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<div id="loginPrompt" style="position:fixed; margin:0;margin-top:-1rem; background-color:blue;width:100%;height:100%;z-index:2;">
<h2 style="color:white;margin-left:0.2rem;">Enter your name: </h2>
<form id="formName" style="margin-left:0.2rem;">
<input id="inputName"><button>Submit</button>
</form>
</div>
<div id="imageDiv" style="position:absolute; margin-bottom:5rem; z-index:2;"></div>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" placeholder="Enter your message..."/><button>Send</button>
</form>
<input type="file" id="img" onchange="setImgSrc(this)" accept="image/*"/>
<input type="submit" id="subBtn" onclick="submitImg()"/>
<script src="/socket.io/socket.io.js"></script>
<p id="nametag"></p>
<script>
var socket = io.connect()
var src
var setImgSrc = (elm) => {
var fr = new FileReader()
fr.onload = () => (src = fr.result)
fr.readAsArrayBuffer(elm.files[0])
}
var submitImg = () => socket.emit('submitImg',src)
socket.on('sentImg', (src) => {
// Create Img...
var img = document.createElement('img')
img.src = (window.URL || window.webkitURL).createObjectURL(
new Blob([src], {
type: 'image/png'
})
)
img.width = 300
img.height = 300
//sleep(5000)
var theDiv = document.createElement('div')
theDiv.append(img)
document.getElementById('messages').append(theDiv)
//var usern = document.getElementById('nametag')
//socket.emit('chat message', "(Photo from " + usern.innerHTML + ")")
})
var username = ""; //prompt("Please enter a username: ", "");
var messages = document.getElementById('messages');
var form = document.getElementById('form');
var input = document.getElementById('input');
var formName = document.getElementById('formName');
var inputName = document.getElementById('inputName');
formName.addEventListener('submit', function (k) {
k.preventDefault();
if (inputName.value)
{
username = inputName.value;
nametag.innerHTML = username;
$('#loginPrompt').hide();
$('#form').attr('style', '');
//form.width = "100%";
socket.emit('chat message', username + ' has joined!');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', username + ': ' + input.value);
input.value = "";
$('#input').attr('placeholder', 'Enter your message...');
}
if (inputName.value != "Enter your name..."){
name = inputName.value;
}
});
//return false;
}
});
socket.on('chat message', function(msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
</body>
</html>
SERVERSIDE JS:
const http = require('http').Server(app);
const io = require('socket.io')(http);
const port = process.env.PORT || 3001;
var chatlog = [];
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store')
next()
})
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
for (i = 0; i < chatlog.length; i++){
io.emit('chat message', chatlog[i]);
}
socket.on('chat message', msg => {
chatlog.push(msg);
io.emit('chat message', msg);
});
socket.on('submitImg', (src) => {
console.log('Client sent image')
//Client submit an image
io.emit('sentImg', src) //the server send the image src to all clients
});
});
http.listen(port, () => {
console.log(`Socket.IO server running at http://localhost:${port}/`);
});
When I try to append the image to any element, if the file is small enough it'll work, if not, it'll just re-send the chat log as though a complete reconnect occurred.
I'm assuming the issue is that the data stream upload for the photo is not happening fast enough, and other code is executing prematurely. I employed a wait function and threw a whopping 5s delay in, but I still had the same issue. What's worse is the wait would only actually fire on the filesizes that would've worked anyway.
Any help would be greatly appreciated!!