pull/152/head
Alex Kern 5 years ago
parent 2b1c473e45
commit 981bd31253
No known key found for this signature in database
GPG Key ID: F3141D5EDF48F89F

@ -1,4 +1,4 @@
<a href="https://xkcd.com/949/"><img src="http://imgs.xkcd.com/comics/file_transfer.png" alt="XKCD 949" width="30%" align="right" /></a> <img src="src/static/images/wordmark.png" alt="FilePizza wordmark" width="50%" /> <h3>Peer-to-peer file transfers in your browser</h3>
<a href="https://xkcd.com/949/"><img src="http://imgs.xkcd.com/comics/file_transfer.png" alt="XKCD 949" width="30%" align="right" /></a> <img src="public/images/wordmark.png" alt="FilePizza wordmark" width="50%" /> <h3>Peer-to-peer file transfers in your browser</h3>
*Cooked up by [Alex Kern](https://kern.io) & [Neeraj Baid](http://neeraj.io) while eating Sliver @ UC Berkeley.*

@ -2,7 +2,6 @@
"name": "filepizza",
"version": "1.1.0",
"description": "Free peer-to-peer file transfers in your browser.",
"bin": "./dist/index.js",
"author": "Alex Kern <alex@kern.io> (http://kern.io)",
"license": "BSD-3-Clause",
"homepage": "https://github.com/kern/filepizza",

@ -1,25 +0,0 @@
import 'babel-polyfill'
import './index.styl'
import React from 'react'
import ReactRouter from 'react-router'
import webrtcSupport from 'webrtcsupport'
import routes from './routes'
import alt from './alt'
import SupportActions from './actions/SupportActions'
const bootstrap = document.getElementById('bootstrap').innerHTML
alt.bootstrap(bootstrap)
window.FilePizza = () => {
ReactRouter.run(routes, ReactRouter.HistoryLocation, Handler => {
React.render(<Handler data={bootstrap} />, document)
})
if (!webrtcSupport.support) {
SupportActions.noSupport()
}
const isChrome = navigator.userAgent.toLowerCase().includes('chrome')
if (isChrome) {
SupportActions.isChrome()
}
}

@ -1,50 +0,0 @@
import xkcdPassword from "xkcd-password";
import toppings from "./toppings";
const TOKEN_OPTIONS = {
numWords: 4,
minLength: 3,
maxLength: 20,
}
const SHORT_TOKEN_OPTIONS = {
length: 8,
chars: '0123456789abcdefghijklmnopqrstuvwxyz',
}
const tokens = {}
const shortTokens = {}
const tokenGenerator = new xkcdPassword()
tokenGenerator.initWithWordList(toppings)
function generateShortToken() {
let result = '';
for (let i = SHORT_TOKEN_OPTIONS.length; i > 0; --i) {
{ result += SHORT_TOKEN_OPTIONS.chars[Math.floor(Math.random() * SHORT_TOKEN_OPTIONS.chars.length)]}
return result;
}
export function create(socket) {
return tokenGenerator.generate(TOKEN_OPTIONS).then((parts) => {
const token = parts.join('/')
;const shortToken = generateShortToken()
const result = {
token,
shortToken,
socket,
}
tokens[token] = result
shortTokens[shortToken] = result
return result
});
}
export function find(token) {
return tokens[token]
}
export function findShort(shortToken) {
return shortTokens[shortToken.toLowerCase()]
}

@ -1,419 +0,0 @@
@import "nib";
beige = #F9F2E7
dark-gray = #333
gray = #777
green = #3F6B29
light-blue = #40C0CB
light-gray = #EEE
light-green = #4BB74C
light-red = #E23430
light-yellow = #FFE476
red = #B11C17
yellow = #DEAC11
@keyframes rotate {
from { transform: rotate(0deg) }
to { transform: rotate(360deg) }
}
global-reset()
* { box-sizing: border-box }
html, body { height: 100% }
h1 {
color: red;
font: bold 56px/64px "Lobster Two", sans-serif;
text-align: center;
margin: 0 0 10px;
}
a {
color: gray
}
strong {
font-weight: bold
}
p {
color: gray;
font: 18px/22px "Quicksand", sans-serif;
text-align: center;
margin: 0;
&.notice {
margin: 10px 0;
}
}
small {
color: gray;
font: 12px/22px "Quicksand", sans-serif;
text-align: center;
margin: 0;
&.notice {
margin: 0 0 10px;
}
}
.footer {
width: 100%
text-align: center
color: gray
padding: 10px 0 10px
position: fixed
bottom: 0
border-radius: 5px 5px 0 0
background white
box-shadow 0 -2px 4px light-gray
iframe {
display: inline-block;
vertical-align: bottom;
margin-right: 10px;
}
p {
font: 12px/20px "Quicksand", sans-serif;
@media (max-width: 600px) {
font-size 14px
}
}
form p {
display: inline;
}
.byline {
padding: 0 10px;
}
@media (max-width: 600px) {
position: relative
}
}
.page {
display: flex
flex-direction: column;
justify-content: center;
height: 100%;
min-height: 640px;
padding: 40px 0 80px;
}
.drop-zone {
.drop-zone-overlay {
position: fixed
top: 0
left: 0
width: 100%
height: 100%
background: rgba(0, 0, 0, 0.5)
text-align: center
&:after {
color: white
content: 'DROP TO UPLOAD'
display: block
font: 24px/40px "Quicksand", sans-serif
margin-top: -20px
position: relative
text-shadow: 0 1px dark-gray
top: 50%
}
}
}
.spinner {
width: 300px
min-height: 300px
margin: 0 auto 20px
display: flex
flex-direction: column
align-items: center
align-content: center
justify-content: center
@media (max-width: 600px) {
width: 150px
min-height: 150px
}
&:before {
background: url(/images/pizza.png) center center / 300px 300px no-repeat
content: ""
position: absolute
width: 300px
height: 300px
transition: transform 1s
z-index: -1
@media (max-width: 600px) {
width: 150px
height: 150px
background-size: 150px 150px
}
}
&.spinner-animated:before {
animation: rotate 5s infinite linear
}
.spinner-image {
display: block;
width: 40%;
}
.spinner-name {
font: bold 18px/20px "Quicksand", sans-serif
text-align: center
color: white
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
margin-top: 10px
text-shadow: 0 0 3px #333
}
.spinner-size {
font: italic 12px/20px "Quicksand", sans-serif
text-align: center
color: white
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
text-shadow: 0 0 3px #333
}
}
.tempalink {
display: flex
width: calc(100vw - 40px)
max-width: 1024px
margin 20px auto
.long-url input {
background: beige
color: dark-gray
border: 0
margin: 0
font: 18px/1 monospace
height: 60px
padding: 20px
text-align: center
width: 100%
border-radius: 4px 4px 0 0
}
.short-url {
background: light-gray
color: dark-gray
height: 40px
padding: 10px 20px
text-align: center
width: 100%
font: 14px/1 "Quicksand", sans-serif;
border-radius: 0 0 4px 4px
span {
font: 14px/1 monospace
}
}
.qr {
flex: none
padding-right: 40px
}
.urls {
flex: auto
}
img {
height: 100px
width: 100px
display: block
}
}
@media screen and (max-width: 850px) {
.tempalink {
display: flex
flex-direction: column;
width: calc(100vw - 40px)
max-width: 1024px
margin 20px auto
.qr {
margin: auto;
justify-content: center
padding: 20px
}
.short-url {
display: flex
flex-direction: column
height: 70px
span {
word-break: break-all
padding: 2px
}
}
.long-url input {
rows: auto
}
}
}
@media screen and (max-height: 360px) {
.container {
margin-bottom: 60px
}
}
.data {
color: gray
font: 14px/20px "Quicksand", sans-serif
text-align: center
overflow: hidden
.datum {
float: left
width: 50%
}
}
.download-button {
display: block
box-shadow: inset 0 1px 1px green
padding: 20px
background: light-green
border: none
color: white
width: calc(100vw - 40px)
max-width: 800px
margin: 0 auto
border-radius: 4px
font: bold 18px/20px "Quicksand", sans-serif
transition: 0.25s
cursor: pointer
text-transform: uppercase
&:hover, &:focus {
box-shadow: inset 0 1px 1px lighten(green, 10%)
background: lighten(light-green, 10%)
}
&:active {
background: light-green
}
}
.progress-bar {
height: 60px
overflow: hidden
background: light-green
transition: all 1s ease
width: calc(100vw - 40px)
max-width: 800px
margin: 0 auto
border-radius: 4px
.progress-bar-inner {
float: left
height: 100%
background: light-green
box-shadow: inset 0 1px 1px green
overflow: hidden
border-radius: 4px
}
.progress-bar-text {
font: 14px/60px "Quicksand", sans-serif
color: white
text-align: center
text-transform: uppercase
}
&.progress-bar-failed {
background: red
box-shadow: inset 0 1px 1px light-red
.progress-bar-text {
text-align: center
}
}
&.progress-bar-in-progress {
background: beige
.progress-bar-inner {
background: #FFCC00
box-shadow: inset 0 1px 1px light-yellow
}
.progress-bar-text {
color: black
float: right
margin-right: 5px
}
}
&.progress-bar-small {
height: 30px
width: 50%
margin: 8px auto
border-radius: 5px
.progress-bar-text {
line-height: 30px
}
}
}
.select-file-label {
border: 2px solid gray
border-radius: 4px
padding: 2px 5px
margin-top: 10px
background: light-gray
display: inline-block
cursor: pointer
transition: all 0.25s ease
&:hover, &:active {
border-color: yellow
background: white
color: red
}
input[type="file"] {
position: fixed
top: -1000px
}
}
.donate-button {
border: 2px solid green
border-radius: 4px
padding: 2px 5px
margin-right: 10px
background: light-green
display: inline-block
cursor: pointer
transition: all 0.25s ease
font: 12px/1 "Quicksand", sans-serif
color: white
text-decoration: none
&:hover, &:active {
border-color: light-green
color: white
}
}

@ -1,24 +0,0 @@
#! /usr/bin/env node
try {
require('../newrelic')
require('newrelic')
} catch (ex) {
// Don't load New Relic if the configuration file doesn't exist.
}
process.on('unhandledRejection', (reason, p) => {
p.catch(err => {
console.error('Exiting due to unhandled rejection!')
console.error(err)
process.exit(1)
})
})
process.on('uncaughtException', err => {
console.error('Exiting due to uncaught exception!')
console.error(err.stack)
process.exit(1)
})
module.exports = require('./server')

@ -1,82 +0,0 @@
import socket from 'filepizza-socket'
import DownloadActions from '../actions/DownloadActions'
import alt from '../alt'
import { getClient } from '../wt'
const SPEED_REFRESH_TIME = 2000
function downloadBlobURL(name, blobURL) {
const a = document.createElement('a')
document.body.appendChild(a)
a.download = name
a.href = blobURL
a.click()
}
export default alt.createStore(
class DownloadStore {
constructor() {
this.bindActions(DownloadActions)
this.fileName = ''
this.fileSize = 0
this.fileType = ''
this.infoHash = null
this.peers = 0
this.progress = 0
this.speedDown = 0
this.speedUp = 0
this.status = 'uninitialized'
this.token = null
}
onRequestDownload() {
if (this.status !== 'ready') {
return
}
this.status = 'requesting'
getClient().then(client => {
client.add(
this.infoHash,
{ announce: client.tracker.announce },
(torrent) => {
this.setState({ status: 'downloading' })
const updateSpeed = () => {
this.setState({
speedUp: torrent.uploadSpeed,
speedDown: torrent.downloadSpeed,
peers: torrent.numPeers,
})
}
torrent.on('upload', updateSpeed)
torrent.on('download', updateSpeed)
setInterval(updateSpeed, SPEED_REFRESH_TIME)
const file = torrent.files[0]
const stream = file.createReadStream()
stream.on('data', (chunk) => {
if (this.status !== 'downloading') {
return
}
if (torrent.progress === 1) {
this.setState({ status: 'done', progress: 1 })
file.getBlobURL((err, blobURL) => {
if (err) {
throw err
}
downloadBlobURL(this.fileName, blobURL)
})
} else {
this.setState({ progress: torrent.progress })
}
})
},
)
})
}
},
'DownloadStore',
)

@ -1,21 +0,0 @@
import SupportActions from '../actions/SupportActions'
import alt from '../alt'
export default alt.createStore(
class ErrorStore {
constructor() {
this.bindActions(SupportActions)
this.status = 404
this.message = 'Not Found'
this.stack = null
}
onNoSupport() {
this.status = 400
this.message = 'No WebRTC Support. Please use Chrome or Firefox.'
this.stack = null
}
},
'ErrorStore',
)

@ -1,21 +0,0 @@
import SupportActions from '../actions/SupportActions'
import alt from '../alt'
export default alt.createStore(
class SupportStore {
constructor() {
this.bindActions(SupportActions)
this.isSupported = true
this.isChrome = false
}
onNoSupport() {
this.isSupported = false
}
onIsChrome() {
this.isChrome = true
}
},
'SupportStore',
)

@ -1,68 +0,0 @@
import socket from 'filepizza-socket'
import UploadActions from '../actions/UploadActions'
import alt from '../alt'
import { getClient } from '../wt'
const SPEED_REFRESH_TIME = 2000
export default alt.createStore(
class UploadStore {
constructor() {
this.bindActions(UploadActions)
this.fileName = ''
this.fileSize = 0
this.fileType = ''
this.infoHash = null
this.peers = 0
this.speedUp = 0
this.status = 'ready'
this.token = null
this.shortToken = null
}
onUploadFile(file) {
if (this.status !== 'ready') {
return
}
this.status = 'processing'
getClient().then(client => {
client.seed(file, { announce: client.tracker.announce }, torrent => {
const updateSpeed = () => {
this.setState({
speedUp: torrent.uploadSpeed,
peers: torrent.numPeers,
})
}
torrent.on('upload', updateSpeed)
torrent.on('download', updateSpeed)
setInterval(updateSpeed, SPEED_REFRESH_TIME)
socket.emit(
'upload',
{
fileName: file.name,
fileSize: file.size,
fileType: file.type,
infoHash: torrent.magnetURI,
},
(res) => {
this.setState({
status: 'uploading',
token: res.token,
shortToken: res.shortToken,
fileName: file.name,
fileSize: file.size,
fileType: file.type,
infoHash: torrent.magnetURI,
})
},
)
})
})
}
},
'UploadStore',
)

@ -1,7 +1,3 @@
import xkcdPassword from 'xkcd-password'
import toppings from './toppings'
import config from './config'
// Borrowed from StackOverflow
// http://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript
export const formatSize = (bytes: number): string => {

Loading…
Cancel
Save