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 React from 'react';
|
||||
import Actions from './Actions';
|
||||
|
||||
if (window.WebDrop) Actions.setDownloadInfo(window.WebDrop);
|
||||
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';
|
||||
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