summaryrefslogtreecommitdiff
path: root/public/js/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/js/main.js')
-rw-r--r--public/js/main.js353
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