multiple peers
This commit is contained in:
@@ -13,7 +13,8 @@
|
|||||||
* [x] Clean project
|
* [x] Clean project
|
||||||
* [x] Better data upload by chunks and ensure consistancy
|
* [x] Better data upload by chunks and ensure consistancy
|
||||||
* [x] Link sharing and better workflow
|
* [x] Link sharing and better workflow
|
||||||
* [ ] Multiple peers
|
* [x] Multiple peers
|
||||||
|
* [ ] Get peer data
|
||||||
* [ ] QRCode
|
* [ ] QRCode
|
||||||
* [ ] DaisyUI redesign
|
* [ ] DaisyUI redesign
|
||||||
* [ ] Multiple files
|
* [ ] Multiple files
|
||||||
|
|||||||
+12
-8
@@ -29,8 +29,8 @@
|
|||||||
</h1>
|
</h1>
|
||||||
<br />
|
<br />
|
||||||
<div>
|
<div>
|
||||||
<label>Local ID</label><br>
|
<label>Status</label><br>
|
||||||
<input :value="localId" disabled />
|
<input :value="statusText" disabled />
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
<template v-if="serverIsReady">
|
<template v-if="serverIsReady">
|
||||||
@@ -39,16 +39,19 @@
|
|||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="remoteId">
|
|
||||||
<label>Remote ID</label><br>
|
|
||||||
<input v-model="remoteId" disabled>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
</template>
|
|
||||||
<template v-if="isServer">
|
<template v-if="isServer">
|
||||||
<input type="file" @change="onFileChange" :disabled="server.data" />
|
<input type="file" @change="onFileChange" :disabled="server.data" />
|
||||||
<br>
|
<br>
|
||||||
|
<br>
|
||||||
|
<template v-for="client in server.clients">
|
||||||
|
<label>{{ client.id }} - {{ client.status }}</label><br>
|
||||||
|
<progress :value="client.sent" :max="downloadTotal" aria-busy="!client.connected"></progress>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<label v-if="fileName">{{ prettyFileSize }} - "{{ fileName }}"</label><br>
|
||||||
<template v-if="readyToDownload">
|
<template v-if="readyToDownload">
|
||||||
<input type="submit" @click.prevent="onDownload" value="Download" />
|
<input type="submit" @click.prevent="onDownload" value="Download" />
|
||||||
<br>
|
<br>
|
||||||
@@ -59,6 +62,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
</template>
|
</template>
|
||||||
|
</template>
|
||||||
<template v-if="error">
|
<template v-if="error">
|
||||||
<span class="red">{{error}}</span>
|
<span class="red">{{error}}</span>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -33,17 +33,17 @@ const app = createApp({
|
|||||||
fileSize: null,
|
fileSize: null,
|
||||||
localId: null,
|
localId: null,
|
||||||
|
|
||||||
remoteId: null,
|
|
||||||
connection: null, // TODO multiple connections
|
|
||||||
|
|
||||||
isServer: true,
|
isServer: true,
|
||||||
server: {
|
server: {
|
||||||
|
clients: [],
|
||||||
url: null,
|
url: null,
|
||||||
data: null, // TODO multiple files
|
data: null, // TODO multiple files
|
||||||
copied: false,
|
copied: false,
|
||||||
},
|
},
|
||||||
client: {
|
client: {
|
||||||
remoteId: null,
|
remoteId: null,
|
||||||
|
connection: null,
|
||||||
|
connected: false,
|
||||||
downloadStart: null,
|
downloadStart: null,
|
||||||
received: [],
|
received: [],
|
||||||
buffer: null, // TODO multiple files
|
buffer: null, // TODO multiple files
|
||||||
@@ -55,14 +55,11 @@ const app = createApp({
|
|||||||
canConnect() {
|
canConnect() {
|
||||||
return this.peer !== null && this.localId !== null;
|
return this.peer !== null && this.localId !== null;
|
||||||
},
|
},
|
||||||
isConnected() {
|
|
||||||
return this.connection !== null;
|
|
||||||
},
|
|
||||||
readyToDownload() {
|
readyToDownload() {
|
||||||
return this.client.buffer !== null && !this.client.downloadStart;
|
return this.client.buffer !== null && !this.client.downloadStart;
|
||||||
},
|
},
|
||||||
serverIsReady() {
|
serverIsReady() {
|
||||||
return this.server.data !== null;
|
return this.canConnect && this.server.data !== null;
|
||||||
},
|
},
|
||||||
downloading() {
|
downloading() {
|
||||||
return this.client.downloadStart !== null;
|
return this.client.downloadStart !== null;
|
||||||
@@ -82,6 +79,45 @@ const app = createApp({
|
|||||||
}
|
}
|
||||||
return "Copy link";
|
return "Copy link";
|
||||||
},
|
},
|
||||||
|
statusText() {
|
||||||
|
if (this.error) {
|
||||||
|
return this.error;
|
||||||
|
}
|
||||||
|
if (!this.canConnect) {
|
||||||
|
return 'Acquiring ID...';
|
||||||
|
}
|
||||||
|
if (this.isServer) {
|
||||||
|
if (! this.server.data) {
|
||||||
|
return 'Waiting for file upload';
|
||||||
|
}
|
||||||
|
return 'Ready to send file';
|
||||||
|
}
|
||||||
|
if (! this.client.connected) {
|
||||||
|
return 'Connecting to peer...';
|
||||||
|
}
|
||||||
|
if (this.readyToDownload) {
|
||||||
|
return 'Ready to download';
|
||||||
|
}
|
||||||
|
if (! this.downloading) {
|
||||||
|
return 'Waiting for file info...';
|
||||||
|
}
|
||||||
|
if (this.downloadProgress > this.downloadTotal) {
|
||||||
|
return 'File downloaded';
|
||||||
|
}
|
||||||
|
return 'Downloading...';
|
||||||
|
},
|
||||||
|
prettyFileSize() {
|
||||||
|
let size = this.fileSize / 1000;
|
||||||
|
if (size < 1000) {
|
||||||
|
return `${size.toFixed(2)} KB`;
|
||||||
|
}
|
||||||
|
size /= 1000;
|
||||||
|
if (size < 1000) {
|
||||||
|
return `${size.toFixed(2)} MB`;
|
||||||
|
}
|
||||||
|
size /= 1000;
|
||||||
|
return `${size.toFixed(2)} GB`;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
watch: {},
|
watch: {},
|
||||||
updated() {
|
updated() {
|
||||||
@@ -133,12 +169,27 @@ const app = createApp({
|
|||||||
this.peer.on("disconnected", this.onPeerDisconnected);
|
this.peer.on("disconnected", this.onPeerDisconnected);
|
||||||
this.peer.on("error", this.onPeerError);
|
this.peer.on("error", this.onPeerError);
|
||||||
},
|
},
|
||||||
initConnection(conn) {
|
initServerConnection(conn) {
|
||||||
this.connection = conn;
|
const index = this.server.clients.length;
|
||||||
this.connection.on("open", this.onConnectionOpen);
|
this.server.clients.push({
|
||||||
this.connection.on("close", this.onConnectionClose);
|
connection: conn,
|
||||||
this.connection.on("data", this.onConnectionData);
|
id: conn.peer,
|
||||||
this.connection.on("error", this.onConnectionError);
|
done: false,
|
||||||
|
sent: 0,
|
||||||
|
connected: false,
|
||||||
|
status: 'Connecting...',
|
||||||
|
});
|
||||||
|
conn.on("open", () => this.onServerConnectionOpen(index));
|
||||||
|
conn.on("close", () => this.onServerConnectionClose(index));
|
||||||
|
conn.on("data", (data) => this.onServerConnectionData(index, data));
|
||||||
|
conn.on("error", (err) => this.onServerConnectionError(index, err));
|
||||||
|
},
|
||||||
|
initClientConnection(conn) {
|
||||||
|
this.client.connection = conn;
|
||||||
|
conn.on("open", this.onClientConnectionOpen);
|
||||||
|
conn.on("close", this.onClientConnectionClose);
|
||||||
|
conn.on("data", this.onClientConnectionData);
|
||||||
|
conn.on("error", this.onClientConnectionError);
|
||||||
},
|
},
|
||||||
clientCreateStream() {
|
clientCreateStream() {
|
||||||
try {
|
try {
|
||||||
@@ -156,6 +207,11 @@ const app = createApp({
|
|||||||
link.download = this.fileName;
|
link.download = this.fileName;
|
||||||
link.click();
|
link.click();
|
||||||
},
|
},
|
||||||
|
clientOpenConnection() {
|
||||||
|
this.initClientConnection(
|
||||||
|
this.peer.connect(this.client.remoteId, { reliable: false }),
|
||||||
|
);
|
||||||
|
},
|
||||||
// PEER EVENTS
|
// PEER EVENTS
|
||||||
onPeerOpen(id) {
|
onPeerOpen(id) {
|
||||||
console.log("onPeerOpen", id);
|
console.log("onPeerOpen", id);
|
||||||
@@ -164,17 +220,14 @@ const app = createApp({
|
|||||||
if (this.isServer) {
|
if (this.isServer) {
|
||||||
this.server.url = `${window.location.href}?s=${id}`;
|
this.server.url = `${window.location.href}?s=${id}`;
|
||||||
} else {
|
} else {
|
||||||
this.initConnection(
|
this.clientOpenConnection();
|
||||||
this.peer.connect(this.client.remoteId, { reliable: false }),
|
|
||||||
);
|
|
||||||
this.remoteId = this.client.remoteId;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPeerConnection(conn) {
|
onPeerConnection(conn) {
|
||||||
console.log("onPeerConnection", conn);
|
console.log("onPeerConnection", conn);
|
||||||
// TODO multiple connections for server
|
if (this.isServer) {
|
||||||
this.initConnection(conn);
|
this.initServerConnection(conn);
|
||||||
this.remoteId = conn.peer;
|
}
|
||||||
},
|
},
|
||||||
onPeerClose() {
|
onPeerClose() {
|
||||||
console.log("onPeerClose");
|
console.log("onPeerClose");
|
||||||
@@ -190,15 +243,42 @@ const app = createApp({
|
|||||||
this.peer = null;
|
this.peer = null;
|
||||||
setTimeout(this.initPeer, 1000);
|
setTimeout(this.initPeer, 1000);
|
||||||
},
|
},
|
||||||
// CONNECTION EVENTS
|
// SERVER CONNECTION EVENTS
|
||||||
onConnectionOpen() {
|
onServerConnectionOpen(index) {
|
||||||
console.log("onConnectionOpen");
|
console.log("onServerConnectionOpen", index);
|
||||||
if (this.isServer) {
|
this.server.clients[index].connected = true;
|
||||||
this.sendServerInfo();
|
this.server.clients[index].status = 'Connected';
|
||||||
|
this.sendServerInfo(index);
|
||||||
|
},
|
||||||
|
onServerConnectionData(index, data) {
|
||||||
|
console.log("onServerConnectionData", index, data.type);
|
||||||
|
switch (data.type) {
|
||||||
|
case MESSAGE_TYPE.ClientSeek:
|
||||||
|
this.handleClientSeek(index, data);
|
||||||
|
break;
|
||||||
|
case MESSAGE_TYPE.ClientDone:
|
||||||
|
this.handleClientDone(index, data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.error("Invalid message type");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onConnectionData(data) {
|
onServerConnectionClose(index) {
|
||||||
console.log("onConnectionData", data.type);
|
console.log("onServerConnectionClose", index);
|
||||||
|
this.server.clients[index].status = 'Disconnected';
|
||||||
|
},
|
||||||
|
onServerConnectionError(index, err) {
|
||||||
|
console.log("onServerConnectionError", index, err);
|
||||||
|
this.server.clients[index].status = 'Error';
|
||||||
|
},
|
||||||
|
// CLIENT CONNECTION EVENTS
|
||||||
|
onClientConnectionOpen() {
|
||||||
|
console.log("onClientConnectionOpen");
|
||||||
|
this.client.connected = true;
|
||||||
|
},
|
||||||
|
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);
|
||||||
@@ -209,33 +289,26 @@ const app = createApp({
|
|||||||
case MESSAGE_TYPE.ServerDone:
|
case MESSAGE_TYPE.ServerDone:
|
||||||
this.handleServerDone(data);
|
this.handleServerDone(data);
|
||||||
break;
|
break;
|
||||||
case MESSAGE_TYPE.ClientSeek:
|
|
||||||
this.handleClientSeek(data);
|
|
||||||
break;
|
|
||||||
case MESSAGE_TYPE.ClientDone:
|
|
||||||
this.handleClientDone(data);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
console.error("Invalid message type");
|
console.error("Invalid message type");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onConnectionClose() {
|
onClientConnectionClose() {
|
||||||
console.log("onConnectionClose");
|
console.log("onClientConnectionClose");
|
||||||
this.connection = null;
|
this.client.connection = null;
|
||||||
// TODO handle conn close
|
|
||||||
},
|
},
|
||||||
onConnectionError(err) {
|
onClientConnectionError(err) {
|
||||||
console.log("onConnectionError", err);
|
console.log("onClientConnectionError", err);
|
||||||
// TODO handle error
|
this.error = `Connection failed: ${err.type}. Reconnecting...`
|
||||||
throw err;
|
setTimeout(this.clientOpenConnection, 1000);
|
||||||
},
|
},
|
||||||
// EXCHANGES
|
// EXCHANGES
|
||||||
sendServerInfo() {
|
sendServerInfo(index) {
|
||||||
this.connection.send({
|
this.server.clients[index].connection.send({
|
||||||
type: MESSAGE_TYPE.ServerInfo,
|
type: MESSAGE_TYPE.ServerInfo,
|
||||||
fileName: this.server.data ? this.fileName : null,
|
fileName: this.fileName,
|
||||||
fileSize: this.server.data ? this.fileSize : null,
|
fileSize: this.fileSize,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleServerInfo(data) {
|
handleServerInfo(data) {
|
||||||
@@ -243,12 +316,13 @@ const app = createApp({
|
|||||||
this.fileSize = data.fileSize;
|
this.fileSize = data.fileSize;
|
||||||
this.clientCreateStream();
|
this.clientCreateStream();
|
||||||
},
|
},
|
||||||
sendServerChunk(index) {
|
sendServerChunk(index, chunkIndex) {
|
||||||
this.connection.send({
|
this.server.clients[index].connection.send({
|
||||||
type: MESSAGE_TYPE.ServerChunk,
|
type: MESSAGE_TYPE.ServerChunk,
|
||||||
index,
|
index: chunkIndex,
|
||||||
bytes: this.server.data.slice(index, index + MAX_CHUNK_SIZE),
|
bytes: this.server.data.slice(chunkIndex, chunkIndex + MAX_CHUNK_SIZE),
|
||||||
});
|
});
|
||||||
|
this.server.clients[index].sent += MAX_CHUNK_SIZE;
|
||||||
},
|
},
|
||||||
handleServerChunk(data) {
|
handleServerChunk(data) {
|
||||||
new Uint8Array(this.client.buffer).set(
|
new Uint8Array(this.client.buffer).set(
|
||||||
@@ -257,10 +331,11 @@ const app = createApp({
|
|||||||
);
|
);
|
||||||
this.client.received.push(data.index);
|
this.client.received.push(data.index);
|
||||||
},
|
},
|
||||||
sendServerDone() {
|
sendServerDone(index) {
|
||||||
this.connection.send({
|
this.server.clients[index].connection.send({
|
||||||
type: MESSAGE_TYPE.ServerDone,
|
type: MESSAGE_TYPE.ServerDone,
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
handleServerDone() {
|
handleServerDone() {
|
||||||
const indexes = [];
|
const indexes = [];
|
||||||
@@ -277,30 +352,32 @@ const app = createApp({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
sendClientSeek(indexes = null) {
|
sendClientSeek(indexes = null) {
|
||||||
this.connection.send({
|
this.client.connection.send({
|
||||||
type: MESSAGE_TYPE.ClientSeek,
|
type: MESSAGE_TYPE.ClientSeek,
|
||||||
indexes,
|
indexes,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleClientSeek(data) {
|
handleClientSeek(index, data) {
|
||||||
if (data.indexes) {
|
if (data.indexes) {
|
||||||
data.indexes.forEach((index) => {
|
data.indexes.forEach((chunkIndex) => {
|
||||||
setTimeout(() => this.sendServerChunk(index));
|
setTimeout(() => this.sendServerChunk(index, chunkIndex));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
for (let index = 0; index < this.fileSize; index += MAX_CHUNK_SIZE) {
|
for (let chunkIndex = 0; chunkIndex < this.fileSize; chunkIndex += MAX_CHUNK_SIZE) {
|
||||||
setTimeout(() => this.sendServerChunk(index));
|
setTimeout(() => this.sendServerChunk(index, chunkIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(this.sendServerDone);
|
setTimeout(() => this.sendServerDone(index));
|
||||||
},
|
},
|
||||||
sendClientDone() {
|
sendClientDone() {
|
||||||
this.connection.send({
|
this.client.connection.send({
|
||||||
type: MESSAGE_TYPE.ClientDone,
|
type: MESSAGE_TYPE.ClientDone,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleClientDone() {
|
handleClientDone(index) {
|
||||||
this.connection.close();
|
this.server.clients[index].connection.close();
|
||||||
|
this.server.clients[index].done = true;
|
||||||
|
this.server.clients[index].status = 'Done';
|
||||||
},
|
},
|
||||||
// UI EVENTS
|
// UI EVENTS
|
||||||
onFileChange(event) {
|
onFileChange(event) {
|
||||||
|
|||||||
Reference in New Issue
Block a user