mirror of https://github.com/kern/filepizza
Use PeerJS for peer-to-peer transfers.
parent
7532673a88
commit
1870e26e13
@ -0,0 +1,16 @@
|
|||||||
|
import alt from './alt';
|
||||||
|
|
||||||
|
export default alt.createActions(class Actions {
|
||||||
|
constructor() {
|
||||||
|
this.generateActions(
|
||||||
|
'download',
|
||||||
|
'receiveData',
|
||||||
|
'requestDownload',
|
||||||
|
'setDownloadInfo',
|
||||||
|
'sendToDownloader',
|
||||||
|
'updatePeerID',
|
||||||
|
'updateToken',
|
||||||
|
'upload'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
export default class ChunkedBlob {
|
||||||
|
|
||||||
|
constructor(n) {
|
||||||
|
this.n = n;
|
||||||
|
this.count = n;
|
||||||
|
this.chunks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
setChunk(i, b) {
|
||||||
|
if (i < 0 || i >= this.n)
|
||||||
|
throw new Error('Chunk out of range');
|
||||||
|
|
||||||
|
if (this.chunks[i])
|
||||||
|
throw new Error('Chunk already set');
|
||||||
|
|
||||||
|
this.count--;
|
||||||
|
this.chunks[i] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
ready() {
|
||||||
|
return this.count === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
toBlob() {
|
||||||
|
if (!this.ready())
|
||||||
|
throw new Error('Incomplete blob');
|
||||||
|
|
||||||
|
return new Blob(this.chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
import Actions from './Actions';
|
||||||
|
import alt from './alt';
|
||||||
|
import peer from './peer';
|
||||||
|
import socket from './socket';
|
||||||
|
import ChunkedBlob from './ChunkedBlob';
|
||||||
|
|
||||||
|
const chunkSize = 1024;
|
||||||
|
|
||||||
|
function downloadFile(name, blob) {
|
||||||
|
let url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
let a = document.createElement('a');
|
||||||
|
a.download = name;
|
||||||
|
a.href = url;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default alt.createStore(class Store {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.bindActions(Actions);
|
||||||
|
|
||||||
|
this.peerID = null;
|
||||||
|
|
||||||
|
this.token = null;
|
||||||
|
this.file = null;
|
||||||
|
this.readyToUpload = false;
|
||||||
|
|
||||||
|
this.downloadToken = null;
|
||||||
|
this.downloadMetadata = null;
|
||||||
|
this.downloadChunks = null;
|
||||||
|
this.readyToDownload = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateReadyStatus() {
|
||||||
|
this.readyToUpload = !!this.peerID && !!this.token && !!this.file;
|
||||||
|
this.readyToDownload = !!this.peerID && !!this.downloadToken && !!this.downloadMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdatePeerID(id) {
|
||||||
|
this.peerID = id;
|
||||||
|
this.updateReadyStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdateToken(token) {
|
||||||
|
this.token = token;
|
||||||
|
this.updateReadyStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpload(file) {
|
||||||
|
this.file = file;
|
||||||
|
this.updateReadyStatus();
|
||||||
|
|
||||||
|
socket.emit('upload', {
|
||||||
|
name: file.name,
|
||||||
|
size: file.size,
|
||||||
|
type: file.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSetDownloadInfo(info) {
|
||||||
|
this.downloadToken = info.token;
|
||||||
|
this.downloadMetadata = info.metadata;
|
||||||
|
this.updateReadyStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
onRequestDownload() {
|
||||||
|
if (!this.readyToDownload) return;
|
||||||
|
|
||||||
|
socket.emit('download', {
|
||||||
|
peerID: this.peerID,
|
||||||
|
token: this.downloadToken
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSendToDownloader(peerID) {
|
||||||
|
if (!this.readyToUpload) return;
|
||||||
|
|
||||||
|
let file = this.file;
|
||||||
|
let conn = peer.connect(peerID);
|
||||||
|
conn.on('open', function () {
|
||||||
|
let chunks = Math.ceil(file.size / chunkSize);
|
||||||
|
for (let i = 0; i < chunks; i++) {
|
||||||
|
let start = i * chunkSize;
|
||||||
|
let end = start + chunkSize;
|
||||||
|
let chunk = file.slice(start, end);
|
||||||
|
conn.send({ n: chunks, i: i, b: chunk });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onReceiveData(data) {
|
||||||
|
if (!this.readyToDownload) return;
|
||||||
|
|
||||||
|
if (!this.downloadChunks)
|
||||||
|
this.downloadChunks = new ChunkedBlob(data.n);
|
||||||
|
|
||||||
|
this.downloadChunks.setChunk(data.i, data.b);
|
||||||
|
|
||||||
|
if (this.downloadChunks.ready()) {
|
||||||
|
let blob = this.downloadChunks.toBlob();
|
||||||
|
downloadFile(this.downloadMetadata.name, blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
var Alt = require('alt');
|
||||||
|
module.exports = new Alt();
|
||||||
@ -1,12 +0,0 @@
|
|||||||
export default function(name, blob) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onloadend = function() {
|
|
||||||
var link = document.createElement('a');
|
|
||||||
link.download = name;
|
|
||||||
link.href = reader.result;
|
|
||||||
link.click();
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
}
|
|
||||||
@ -1,3 +1,6 @@
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Actions from './Actions';
|
||||||
|
|
||||||
|
if (window.WebDrop) Actions.setDownloadInfo(window.WebDrop);
|
||||||
React.render(<App />, document.getElementById('app'));
|
React.render(<App />, document.getElementById('app'));
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
import Actions from './Actions';
|
||||||
|
import Peer from 'peerjs';
|
||||||
|
|
||||||
|
var peer = module.exports = new Peer({ key: '8w3x9m637e0o1or' });
|
||||||
|
|
||||||
|
peer.on('open', function () {
|
||||||
|
Actions.updatePeerID(peer.id);
|
||||||
|
if (window.token) Actions.requestDownload(window.token);
|
||||||
|
});
|
||||||
|
|
||||||
|
peer.on('connection', function (conn) {
|
||||||
|
conn.on('data', function (data) {
|
||||||
|
Actions.receiveData(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,2 +1,12 @@
|
|||||||
import io from 'socket.io-client';
|
import io from 'socket.io-client';
|
||||||
export default io.connect('http://localhost:3000');
|
import Actions from './Actions';
|
||||||
|
|
||||||
|
var socket = module.exports = io.connect(window.location.origin);
|
||||||
|
|
||||||
|
socket.on('token', function (token) {
|
||||||
|
Actions.updateToken(token);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on('download', function (peerID) {
|
||||||
|
Actions.sendToDownloader(peerID);
|
||||||
|
});
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
import socket from './socket';
|
|
||||||
|
|
||||||
export default function (file, token) {
|
|
||||||
|
|
||||||
socket.emit('upload', {
|
|
||||||
token: token,
|
|
||||||
blob: file
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue