diff --git a/resources/transbeam.asy b/resources/transbeam.asy new file mode 100644 index 0000000..8e0b935 --- /dev/null +++ b/resources/transbeam.asy @@ -0,0 +1,43 @@ +real triangleRadius = 100; +real borderInset = 6; + +real circleRadius = 12; +real bigBeamRadius = 36; +real smallBeamRadius = 25; +real beamCount = 12; +real beamAngle = 7; +real starterBeamAngle = 16; + +pen transBlue = rgb("55cdfc"); +pen transPink = rgb("f7a8b8"); + +pen bigBeamColor = transPink; +pen smallBeamColor = transBlue; + +path borderTriangle = dir(90)--dir(210)--dir(330)--cycle; +path outerBorder = scale(triangleRadius)*borderTriangle; +fill(outerBorder, white); + +path beam(real angle, real innerRadius, real outerRadius) { + return arc((0,0), outerRadius, angle/2, -angle/2)--arc((0,0), innerRadius, -angle/2, angle/2)--cycle; +} + +path bigBeam = beam(beamAngle, circleRadius, bigBeamRadius); +path smallBeam = beam(beamAngle, circleRadius, smallBeamRadius); + +for (int i = 0; i < beamCount; ++i) { + if (i > 0) { + fill(rotate(360*i/beamCount)*bigBeam, bigBeamColor); + } + fill(rotate(360*(i+0.5)/beamCount)*smallBeam, smallBeamColor); +} + +pair starterBeamTrianglePoint(real angle) { + pair circlePoint = circleRadius*dir(angle); + return intersectionpoint(circlePoint--(circlePoint+(triangleRadius,0)), outerBorder); +} + +fill(starterBeamTrianglePoint(-starterBeamAngle/2)--arc((0,0), circleRadius, -starterBeamAngle/2, starterBeamAngle/2)--starterBeamTrianglePoint(starterBeamAngle/2)--cycle, bigBeamColor); + +draw(outerBorder, transPink+(2*borderInset)); +draw(scale(triangleRadius-borderInset)*borderTriangle, transBlue+borderInset); diff --git a/src/zip.rs b/src/zip.rs index a686a75..714ed53 100644 --- a/src/zip.rs +++ b/src/zip.rs @@ -136,24 +136,13 @@ impl UploadedFile { fn central_directory_header(&self, local_header_offset: usize, hash: u32) -> Vec { let mut header = vec![ - // Central directory file header signature - 0x50, 0x4b, 0x01, 0x02, - // Made by a "DOS" system supporting version 4.5 - if we - // say it's made by a Unix system, then unzip will expect - // it to have embedded Unix permission information, and - // will set all the files to mode 000 when that's not - // present :/ - 45, 0, + 0x50, 0x4b, 0x01, 0x02, // Central directory file header signature + 45, 3, // Made by a Unix system supporting version 4.5 ]; header.append(&mut self.shared_header_fields(Some(hash))); - header.append(&mut vec![ - 0, 0, // File comment length: 0 - 0, 0, // Disk number where file starts: 0 - 0, 0, // Internal file attributes: nothing - 0, 0, 0, 0, // External file attributes: nothing - 0xff, 0xff, 0xff, - 0xff, // Relative offset of local file header: placeholder, see ZIP64 data - ]); + append_0(&mut header, 8); // Comment length, disk number, internal attributes, DOS external attributes + append_value(&mut header, 0o100644, 2); // Unix external file attributes: -rw-r--r-- + append_ff(&mut header, 4); // Relative offset of local file header: placeholder, see ZIP64 data header.append(&mut self.name.clone().into_bytes()); header.append(&mut self.extra_field(local_header_offset)); header @@ -179,7 +168,7 @@ fn end_of_central_directory(files: &[UploadedFile]) -> Vec { ]; append_0(&mut eocd, 7); // pad out the rest of the size field eocd.append(&mut vec![ - 45, 0, // Made by a "DOS" system supporting version 4.5, see above + 45, 3, // Made by a Unix system supporting version 4.5 45, 0, // Minimum version 4.5 to extract ]); append_0(&mut eocd, 8); // Two 4-byte disk numbers, both 0 diff --git a/static/index.html b/static/index.html index 735628d..1640e13 100644 --- a/static/index.html +++ b/static/index.html @@ -17,6 +17,8 @@

Files selected:

+ +
diff --git a/static/transbeam.css b/static/transbeam.css index 29dfbbb..5f9b129 100644 --- a/static/transbeam.css +++ b/static/transbeam.css @@ -17,7 +17,7 @@ button:hover, .fake_button:hover { background-color: #aaa; } -button:disabled, button:disabled:hover { +button:disabled, button:disabled:hover, .fake_button:disabled, .fake_button:disabled:hover { color: #aaa; background-color: #eee; border-color: #ddd; diff --git a/static/transbeam.svg b/static/transbeam.svg new file mode 100644 index 0000000..59d517c --- /dev/null +++ b/static/transbeam.svg @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/upload.js b/static/upload.js index 3cb582c..95c7a94 100644 --- a/static/upload.js +++ b/static/upload.js @@ -3,6 +3,8 @@ let files = []; let socket = null; let fileIndex = 0; let byteIndex = 0; +let bytesSent = 0; +let totalBytes = 0; function sendMetadata() { const metadata = files.map((file) => ({ @@ -25,6 +27,7 @@ function finishSending() { function sendData() { if (fileIndex >= files.length) { finishSending(); + return; } const currentFile = files[fileIndex]; if (byteIndex < currentFile.size) { @@ -32,6 +35,8 @@ function sendData() { const data = currentFile.slice(byteIndex, endpoint); socket.send(data); byteIndex = endpoint; + bytesSent += data.size; + progress.textContent = `${Math.floor(bytesSent * 100 / totalBytes)}%`; } else { fileIndex += 1; byteIndex = 0; @@ -43,6 +48,8 @@ const fileInput = document.getElementById('file_input'); const fileInputMessage = document.getElementById('file_input_message'); const fileList = document.getElementById('file_list'); const uploadButton = document.getElementById('upload'); +const downloadLink = document.getElementById('download_link'); +const progress = document.getElementById('progress'); function updateButtons() { if (files.length === 0) { @@ -95,10 +102,15 @@ uploadButton.addEventListener('click', (e) => { button.disabled = true; } - socket = new WebSocket('ws://localhost:3000/upload'); + totalBytes = files.reduce((acc, file) => acc + file.size, 0); + + socket = new WebSocket(`ws://${window.location.host}/upload`); socket.addEventListener('open', sendMetadata); socket.addEventListener('message', (msg) => { - if (msg.data === 'ack') { + if (bytesSent === 0 && msg.data.match(/^[A-Za-z0-9]+$/)) { + downloadLink.textContent = msg.data; + sendData(); + } else if (msg.data === 'ack') { sendData(); } });