diff options
Diffstat (limited to 'public/js/main.js')
| -rw-r--r-- | public/js/main.js | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/public/js/main.js b/public/js/main.js new file mode 100644 index 0000000..fcaa512 --- /dev/null +++ b/public/js/main.js @@ -0,0 +1,353 @@ +import { AppSocket } from './lib.js'; + +const CHUNK_SIZE = 4 * 1024 * 1024; // 4MB chunks +const FILESIZE_THRESHOLD = 16 * 1024 * 1024; // 16MB // how big before use chunked upload +const MAXFILESIZE = 2048 * 1024 * 1024; // 2GB +const color_bg = "#dedede"; +//TODO change color based on time + +var ctx = null; //canvas context +var cnv = null; //canvas +var env = { + 'WS_URL': 'wss://belthelziquor.com:9002' +}; //environment variables from server. dev=true by default because if env not passed in not public/published instance +var W = 800; +var H = 600; +var socket = null; //client's websocket +var myID; + +var elemNumConnected; + +//each connected client. same format as server's model +var friends = { + +}; + +//todo move in appmodel +var me = [0,0]; //my cursor position +var myNickname = ''; + +var domElems = {}; + +function prepareFileInput(){ + var file_input = domElems.inputFile; + var files = file_input.files; + for (f in files) { + console.log(f); + } + //TODO validation + domElems.buttonFileUpload.enabled = true; +} + +//APP START HERE +$(document).ready(async function() { + + //the core loop of the client application + // 1. setup relationship with DOM and grab references to its elements + log('init DOM'); + await initDOM(); + + log('getting env vars'); + await getServerEnvVars(); + + log('connect ws'); + connectWebSocket(); + + //setup canvas stuff + if (cnv != null) { + ctx = cnv.getContext("2d"); + W = window.outerWidth; + H = window.outerHeight; + cnv.width = W; + cnv.height = H; + ctx.fillStyle = color_bg; + ctx.fillRect(0,0,W,H); + + if (wsConnected()){ + setInterval(() => { + socket.emit('update_pos', {pos: me, nick: myNickname}); + }, 100); + } + + document.onmousemove = (e) => handleMouseMove(e); + setInterval(() => { + draw(); + }, 20); + + } else { + console.error('Canvas element not found'); + } + + window.addEventListener('resize', resizeCanvas); + + //background color + /*setInterval(() => { + let now = new Date(); + let h = now.getHours(); + let m = now.getMinutes(); + let s = now.getSeconds(); + let ms = now.getMilliseconds(); + + let timeS = h * 3600 + m * 60 + s; + let timeMs = (timeS) * 1000 + ms; + + let hue = 10; // + let saturation = 0; // + let lightness = 94+2*Math.sin(timeMs) + Math.random(); // + let color = `hsl(${hue}, ${saturation}%, ${lightness}%)`; + domElems.body.style.backgroundColor = color; + log(`Background color: ${color}`, 0); + }, 100);*/ +}); + +async function getServerEnvVars(){ + await axios.get('/env').then((res)=>{ + env = res.data; + log(env); + }).catch((err)=>{ + log(err); + }); +} + +//initial setup such as hiding/showing certain things +function initDOM(){ + // temp disabled $('#fileupload')[0].hidden = false; + domElems.numConnected = $('#numFriendsConnected')[0]; + domElems.inputFile = $('#f')[0]; + domElems.debugInfo = $('#infolog')[0]; + domElems.debugInfo.style.display = env.MODE == 'local' ? 'block' : 'none'; + domElems.fileUploadResult = $('#fileupload_result')[0]; + domElems.inputFile.onchange = prepareFileInput; + domElems.buttonFileUpload = $('#button_fileupload')[0]; + domElems.body = $('body')[0]; + domElems.cnv = $('#bg')[0]; + cnv = domElems.cnv; //for convenience + //domElems.buttonFileUpload.enabled = false; + domElems.buttonFileUpload.onclick = uploadFile; + domElems.inputWho = $('#input_who')[0]; + domElems.inputWho.onchange = ()=> { myNickname = domElems.inputWho.value; }; + +} + +function resizeCanvas() { + W = window.outerWidth; + H = window.outerHeight; + domElems.cnv.width = W; + domElems.cnv.height = H; +} + +//todo move the old code from file stuff etc to other file so that this file can be just for the canvas+graphics+networkedgame part of the client app +async function uploadFile() { + var files = domElems.inputFile.files; + domElems.buttonFileUpload.enabled = false; + let formData = new FormData(); + console.log(files); + for (let i = 0; i < files.length; i++) { + formData.append('f[]', files[i], files[i].name); + } + + axios.post('/f', formData, {headers: {'Content-Type': 'multipart/form-data'}}) + .then((res)=>{ + console.log(res); + domElems.fileUploadResult.innerHTML = 'File uploaded successfully<br>'; + res.data.files.forEach((f)=>{ + domElems.fileUploadResult.innerHTML += `<a href = "f/${f.filename}">${f.filename}</a><br>`; + }); + domElems.inputFile.value = null; + domElems.buttonFileUpload.enabled = true; + }) + .catch((err)=>{ + console.log(err); + domElems.fileUploadResult.innerHTML = 'Error uploading file'; + domElems.buttonFileUpload.enabled = true; + }); +} + +async function uploadFileChunked(f){ + const totalChunks = Math.ceil(file.size / CHUNK_SIZE); + const filename = file.name; + + for (let chunkNumber = 0; chunkNumber < totalChunks; chunkNumber++) { + const chunk = file.slice(chunkNumber * CHUNK_SIZE, (chunkNumber + 1) * CHUNK_SIZE); + const formData = new FormData(); + formData.append('file', chunk); + formData.append('filename', filename); + formData.append('chunkNumber', chunkNumber); + formData.append('totalChunks', totalChunks); + + try { + const response = await fetch(`${API_URL}/uploadfiles`, { + method: 'POST', + body: formData + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + updateProgress(chunkNumber + 1, totalChunks); + + } catch (error) { + console.error('Error uploading chunk:', error); + alert('Error uploading file. Please try again.'); + return; + } + } +} + +async function uploadFileSingle(f){ + const formData = new FormData(); + formData.append('f', f); + const res = await fetch(`${API_URL}/uploadfiles`, { + method: 'POST', + body: formData, + credentials: 'include' + }); + console.log(res); +} + +function updateProgress(currentChunk, totalChunks) { + const progressPercentage = Math.round((currentChunk / totalChunks) * 100); + document.getElementById('progress').textContent = `${progressPercentage}% uploaded`; +} + + +function wsConnected(){ + return (socket != null && socket.connected); +} + +function connectWebSocket(){ + try { + socket = new AppSocket(env['WS_URL']); + log(socket); + /*socket = io(env['WS_URL'], { + + secure: true, + rejectUnauthorized: false + });*/ + socket.on('connect_error', (err) => { + console.log('connection error'); + console.log(err); + //TODO $('').textContent = err; + }); + socket.on('connect_failed', (err) => { + console.log('conn failed'); + console.log(err); + //TODO $('').textContent = err; + }); + socket.on('disconnect', (err) => { + console.log('disconnected'); + console.log(err); + //TODO $('').textContent = err; + }); + socket.on('connect', (err) => { + log('connected'); + if (err) console.log(err); + //TODO $('').textContent = 'Connected'; + socket.pingTimeout = 1000; + socket.pingInterval = 500; + }); + socket.on('open', (event) => { + log('connected'); + log(event); + //TODO $('').textContent = 'Connected'; + socket.pingTimeout = 1000; + socket.pingInterval = 500; + }); + + socket.on('syncCanvas', (data) => { + //TODO appShapes = data.shapes; + //TODO ClearBake(); + //TODO DrawCanvas(); + //TODO $('').textContent = 'Synced'; + }); + socket.on('init', (id) => { + myID = id; + }); + + //sync data from server. this is the data from server that should be replicated on each client + socket.on('sync_data', (data) => { + //data is a map of client id to client payload data (currently just the screen position) + friends = {}; + for (const cid in data){ + if (cid == myID){ + continue; + } + friends[cid] = data[cid]; + } + domElems.numConnected.innerHTML = Object.keys(friends).length + 1; + }); + return true; + } catch (err) { + console.log(`failed to connec WS ${env['WS_URL']}`) + console.error(err); + return false; + } +} + + +function draw() { + //draw background + ctx.fillStyle = color_bg; + ctx.fillRect(0,0,W,H); + + //draw me + ctx.fillStyle = "#000000"; + ctx.fillRect(me[0], me[1], 4, 4); + if (myNickname != ''){ + ctx.fillText(myNickname, me[0], me[1]); + } + + //draw friends + Object.keys(friends).forEach((fid)=>{ + ctx.fillStyle = "#050505"; + let x = friends[fid].pos[0]; + let y =friends[fid].pos[1]; + ctx.fillRect(x, y, 6, 6); + if (friends[fid].nick != ''){ + ctx.fillText(friends[fid].nick, x, y); + } + }); + + //drawScene(ctx); + +} + +function getMousePos(canvas, evt) { + var rect = canvas.getBoundingClientRect(); + /*return { + x: evt.clientX - rect.left, + y: evt.clientY - rect.top + };*/ + return [evt.clientX - rect.left, evt.clientY - rect.top]; +} + + +function handleMouseMove(e) { + var eDoc, doc, body; + e = e || window.event; // IE-ism + // If pageX/Y aren't available and clientX/Y are, + // calculate pageX/Y - logic taken from jQuery. + // (This is to support old IE) + if (e.pageX == null && e.clientX != null) { + eventDoc = (e.target && e.target.ownerDocument) || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + e.pageX = e.clientX + + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - + (doc && doc.clientLeft || body && body.clientLeft || 0); + e.pageY = e.clientY + + (doc && doc.scrollTop || body && body.scrollTop || 0) - + (doc && doc.clientTop || body && body.clientTop || 0 ); + } + me = getMousePos(cnv, e); +} + + +function log(msg, lvl=1){ + if (domElems.debugInfo){ + domElems.debugInfo.innerHTML = msg; //TODO running log + timestamp + } + console.log(msg); +}
\ No newline at end of file |
