This commit is contained in:
Klemek
2025-03-19 15:29:55 +01:00
parent 25975deab4
commit 93f2287c13
4 changed files with 64 additions and 92 deletions
+5 -4
View File
@@ -11,9 +11,10 @@
* [x] Multiple peers * [x] Multiple peers
* [x] Get peer data * [x] Get peer data
* [x] See download speed * [x] See download speed
* [ ] Fix turn server settings to work on all servers
* [ ] Fix edge cases
* [x] DaisyUI redesign * [x] DaisyUI redesign
* [x] QRCode * [x] QRCode
* [ ] More cleaning * [x] Fix turn server settings to work on all servers
* [ ] Multiple files * [x] More cleaning
* [ ] Fix edge cases
* [ ] Cancel download
-5
View File
@@ -21,15 +21,10 @@ export default [
rules: { rules: {
"no-magic-numbers": "off", "no-magic-numbers": "off",
"sort-keys": "off", "sort-keys": "off",
"no-warning-comments": "off",
"no-inline-comments": "off", // TODO remove
"no-ternary": "off", "no-ternary": "off",
"one-var": "off", "one-var": "off",
"max-statements": ["warn", 200], // TODO remove
"max-lines-per-function": ["warn", 200], // TODO remove
"max-params": ["warn", 5], "max-params": ["warn", 5],
"max-lines": "off", "max-lines": "off",
"no-console": "off", // TODO remove
}, },
}, },
{ {
+9 -10
View File
@@ -52,8 +52,7 @@
<div :class="`status status-${statusColor(status)} status-lg`"></div> <div :class="`status status-${statusColor(status)} status-lg`"></div>
</div> {{ status }} </div> {{ status }}
</div> </div>
<div v-if="error" class="mt-2 text-error"> <div v-if="error" class="mt-2 text-error" v-html="error">
{{ error }}
</div> </div>
<div v-if="fileName" class="mt-2 w-full"> <div v-if="fileName" class="mt-2 w-full">
<code>{{ prettyFileSize }} - {{ fileName }}</code> <code>{{ prettyFileSize }} - {{ fileName }}</code>
@@ -66,7 +65,7 @@
<div ref="qrcode" id="qrcode" :class="serverIsReady ? '' : 'hidden'" class="w-full mt-2"> <div ref="qrcode" id="qrcode" :class="serverIsReady ? '' : 'hidden'" class="w-full mt-2">
</div> </div>
<div v-if="serverIsReady" @click="onShare" class="mt-2 w-full btn btn-primary"> <div v-if="serverIsReady" @click="onShare" class="mt-2 w-full btn btn-primary">
<i icon="share-2"></i> {{ shareText }} <i icon="share-2"></i> {{ serverShareText }}
</div> </div>
<ul v-if="serverIsReady && server.clients.length" <ul v-if="serverIsReady && server.clients.length"
class="mt-2 list bg-base-100 rounded-box shadow-md text-left"> class="mt-2 list bg-base-100 rounded-box shadow-md text-left">
@@ -77,20 +76,20 @@
<div> <div>
<div :class="`status status-${statusColor(client.status)}`"></div> {{ client.status }} <div :class="`status status-${statusColor(client.status)}`"></div> {{ client.status }}
</div> </div>
<progress :value="client.sent" :max="downloadTotal" aria-busy="!client.connected" class="progress" <progress :value="client.sent" :max="fileSize" aria-busy="!client.connected" class="progress"
:class="client.sent >=downloadTotal ? 'progress-success' : 'progress-primary'"></progress> :class="client.sent >= fileSize ? 'progress-success' : 'progress-primary'"></progress>
</div> </div>
</li> </li>
</ul> </ul>
</template> </template>
<template v-else> <template v-else>
<div @click="onDownload" :class="readyToDownload ? 'btn-primary' : 'btn-disabled'" class="mt-2 w-full btn"> <div @click="onDownload" :class="clientIsReady ? 'btn-primary' : 'btn-disabled'" class="mt-2 w-full btn">
<i icon="file-down"></i> Download <i icon="file-down"></i> Download
</div> </div>
<div v-if="downloading || client.downloadEnd" class="w-full"> <div v-if="clientDownloading || clientFinished" class="w-full">
<progress :class="client.downloadEnd ? 'progress-success' : 'progress-primary'" :value="downloadProgress" <progress :class="clientFinished ? 'progress-success' : 'progress-primary'"
:max="downloadTotal" class="progress w-full"></progress> :value="clientDownloadProgress" :max="fileSize" class="progress w-full"></progress>
<label>{{ prettyDownloadSpeed }}<span v-if="!client.downloadEnd"> - {{ prettyRemainingTime <label>{{ prettyDownloadSpeed }}<span v-if="clientDownloading"> - {{ prettyRemainingTime
}}</span></label> }}</span></label>
</div> </div>
</template> </template>
+49 -72
View File
@@ -113,7 +113,7 @@ const STATUS_COLOR = {
[STATUS.ClientDisconnected]: "neutral", [STATUS.ClientDisconnected]: "neutral",
}; };
const MAX_CHUNK_SIZE = 12 * 1024; // 12 KB const MAX_CHUNK_SIZE = 12 * 1024;
const app = createApp({ const app = createApp({
data() { data() {
@@ -128,7 +128,7 @@ const app = createApp({
server: { server: {
clients: [], clients: [],
url: null, url: null,
data: null, // TODO multiple files data: null,
copied: false, copied: false,
}, },
client: { client: {
@@ -138,7 +138,7 @@ const app = createApp({
downloadStart: null, downloadStart: null,
downloadEnd: null, downloadEnd: null,
received: [], received: [],
buffer: null, // TODO multiple files buffer: null,
}, },
}; };
}, },
@@ -146,28 +146,12 @@ const app = createApp({
canConnect() { canConnect() {
return this.peer !== null && this.localId !== null; return this.peer !== null && this.localId !== null;
}, },
readyToDownload() {
return (
this.client.connection !== null &&
this.client.buffer !== null &&
this.client.downloadStart === null
);
},
serverIsReady() { serverIsReady() {
return this.canConnect && this.server.data !== null;
},
downloading() {
return ( return (
this.client.downloadStart !== null && this.client.downloadEnd === null this.error !== null && this.canConnect && this.server.data !== null
); );
}, },
downloadProgress() { serverShareText() {
return this.client.received.length * MAX_CHUNK_SIZE;
},
downloadTotal() {
return this.fileSize ?? 0;
},
shareText() {
if (navigator.canShare && navigator.canShare()) { if (navigator.canShare && navigator.canShare()) {
return "Share link"; return "Share link";
} }
@@ -176,34 +160,41 @@ const app = createApp({
} }
return "Copy link"; return "Copy link";
}, },
clientIsReady() {
return (
this.error !== null &&
this.canConnect &&
this.client.connection !== null &&
this.client.buffer !== null &&
this.client.downloadStart === null
);
},
clientDownloading() {
return (
this.client.downloadStart !== null && this.client.downloadEnd === null
);
},
clientDownloadProgress() {
return this.client.received.length * MAX_CHUNK_SIZE;
},
clientFinished() {
return this.client.downloadEnd !== null;
},
status() { status() {
if (this.error) { if (this.error) return STATUS.Error;
return STATUS.Error; if (!this.canConnect) return STATUS.Connecting;
} return this.isServer ? this.serverStatus : this.clientStatus;
if (!this.canConnect) { },
return STATUS.Connecting; serverStatus() {
} if (!this.server.data) return STATUS.ServerNoFile;
if (this.isServer) {
if (!this.server.data) {
return STATUS.ServerNoFile;
}
return STATUS.ServerReady; return STATUS.ServerReady;
} },
if (!this.client.connected) { clientStatus() {
return STATUS.ClientConnecting; if (!this.client.connected) return STATUS.ClientConnecting;
} if (!this.client.connection) return STATUS.ClientDisconnected;
if (!this.client.connection) { if (this.client.downloadEnd) return STATUS.ClientDownloaded;
return STATUS.ClientDisconnected; if (this.clientIsReady) return STATUS.ClientReady;
} if (!this.clientDownloading) return STATUS.ClientWaiting;
if (this.client.downloadEnd) {
return STATUS.ClientDownloaded;
}
if (this.readyToDownload) {
return STATUS.ClientReady;
}
if (!this.downloading) {
return STATUS.ClientWaiting;
}
return STATUS.ClientDownloading; return STATUS.ClientDownloading;
}, },
prettyFileSize() { prettyFileSize() {
@@ -215,7 +206,7 @@ const app = createApp({
} }
const time = const time =
(this.client.downloadEnd ?? new Date()) - this.client.downloadStart; (this.client.downloadEnd ?? new Date()) - this.client.downloadStart;
const speed = (1000 * this.downloadProgress) / time; const speed = (1000 * this.clientDownloadProgress) / time;
return `${utils.prettyBytes(speed)}/s`; return `${utils.prettyBytes(speed)}/s`;
}, },
prettyRemainingTime() { prettyRemainingTime() {
@@ -224,13 +215,12 @@ const app = createApp({
} }
const time = const time =
(this.client.downloadEnd ?? new Date()) - this.client.downloadStart; (this.client.downloadEnd ?? new Date()) - this.client.downloadStart;
const speed = this.downloadProgress / time; const speed = this.clientDownloadProgress / time;
const remainingBytes = this.downloadTotal - this.downloadProgress; const remainingBytes = this.fileSize - this.clientDownloadProgress;
const remainingTime = remainingBytes / speed; const remainingTime = remainingBytes / speed;
return `${utils.prettyTime(remainingTime)}`; return `${utils.prettyTime(remainingTime)}`;
}, },
}, },
watch: {},
updated() { updated() {
utils.updateIcons(); utils.updateIcons();
}, },
@@ -261,7 +251,7 @@ const app = createApp({
}, },
initPeer() { initPeer() {
this.peer = new Peer({ this.peer = new Peer({
debug: 3, debug: window.location.href.includes("localhost") ? 3 : 0,
host: "peer.klemek.fr", host: "peer.klemek.fr",
port: "443", port: "443",
secure: true, secure: true,
@@ -346,7 +336,6 @@ const app = createApp({
}, },
// PEER EVENTS // PEER EVENTS
onPeerOpen(id) { onPeerOpen(id) {
console.log("onPeerOpen", id);
this.localId = id; this.localId = id;
this.error = null; this.error = null;
if (this.isServer) { if (this.isServer) {
@@ -357,34 +346,28 @@ const app = createApp({
} }
}, },
onPeerConnection(conn) { onPeerConnection(conn) {
console.log("onPeerConnection", conn);
if (this.isServer) { if (this.isServer) {
this.initServerConnection(conn); this.initServerConnection(conn);
} }
}, },
onPeerClose() { onPeerClose() {
console.log("onPeerClose");
this.peer = null; this.peer = null;
}, },
onPeerDisconnected() { onPeerDisconnected() {
console.log("onPeerDisconnected");
this.peer.reconnect(); this.peer.reconnect();
}, },
onPeerError(err) { onPeerError(err) {
console.log("onPeerError", err); this.error = `${err.type}.<br>Reconnecting...`;
this.error = `Error connecting: ${err.type}. Reconnecting...`;
this.peer = null; this.peer = null;
setTimeout(this.initPeer, 1000); setTimeout(this.initPeer, 1000);
}, },
// SERVER CONNECTION EVENTS // SERVER CONNECTION EVENTS
onServerConnectionOpen(index) { onServerConnectionOpen(index) {
console.log("onServerConnectionOpen", index);
this.server.clients[index].connected = true; this.server.clients[index].connected = true;
this.server.clients[index].status = STATUS.ClientReady; this.server.clients[index].status = STATUS.ClientReady;
this.sendServerInfo(index); this.sendServerInfo(index);
}, },
onServerConnectionData(index, data) { onServerConnectionData(index, data) {
console.log("onServerConnectionData", index, data.type);
switch (data.type) { switch (data.type) {
case MESSAGE_TYPE.ClientInfo: case MESSAGE_TYPE.ClientInfo:
this.handleClientInfo(index, data); this.handleClientInfo(index, data);
@@ -396,26 +379,22 @@ const app = createApp({
this.handleClientDone(index, data); this.handleClientDone(index, data);
break; break;
default: default:
console.error("Invalid message type"); this.server.clients[index].status = STATUS.Error;
break; break;
} }
}, },
onServerConnectionClose(index) { onServerConnectionClose(index) {
console.log("onServerConnectionClose", index);
this.server.clients[index].status = STATUS.ClientDisconnected; this.server.clients[index].status = STATUS.ClientDisconnected;
}, },
onServerConnectionError(index, err) { onServerConnectionError(index) {
console.log("onServerConnectionError", index, err);
this.server.clients[index].status = STATUS.Error; this.server.clients[index].status = STATUS.Error;
}, },
// CLIENT CONNECTION EVENTS // CLIENT CONNECTION EVENTS
onClientConnectionOpen() { onClientConnectionOpen() {
console.log("onClientConnectionOpen");
this.client.connected = true; this.client.connected = true;
this.sendClientInfo(); this.sendClientInfo();
}, },
onClientConnectionData(data) { onClientConnectionData(data) {
console.log("onClientConnectionData", data.type);
switch (data.type) { switch (data.type) {
case MESSAGE_TYPE.ServerInfo: case MESSAGE_TYPE.ServerInfo:
this.handleServerInfo(data); this.handleServerInfo(data);
@@ -427,17 +406,15 @@ const app = createApp({
this.handleServerDone(data); this.handleServerDone(data);
break; break;
default: default:
console.error("Invalid message type"); this.error = "Invalid message received";
break; break;
} }
}, },
onClientConnectionClose() { onClientConnectionClose() {
console.log("onClientConnectionClose");
this.client.connection = null; this.client.connection = null;
}, },
onClientConnectionError(err) { onClientConnectionError(err) {
console.log("onClientConnectionError", err); this.error = `${err.type}.<br>Reconnecting...`;
this.error = `Connection failed: ${err.type}. Reconnecting...`;
setTimeout(this.clientOpenConnection, 1000); setTimeout(this.clientOpenConnection, 1000);
}, },
// EXCHANGES // EXCHANGES
@@ -532,7 +509,7 @@ const app = createApp({
}, },
// UI EVENTS // UI EVENTS
onFileChange(event) { onFileChange(event) {
const [file] = event.target.files; // TODO multiple files const [file] = event.target.files;
if (!file) { if (!file) {
return; return;
} }
@@ -549,7 +526,7 @@ const app = createApp({
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
}, },
onDownload() { onDownload() {
if (!this.readyToDownload) { if (!this.clientIsReady) {
return; return;
} }
this.client.downloadStart = new Date(); this.client.downloadStart = new Date();