commit 23e7c0439382a3bb00cd817767cf6a1a82893d4a
parent 10196cdf3351dba0f7fa0598cf7694613389543b
Author: RobinLinus <robinlinus@users.noreply.github.com>
Date: Fri, 21 Sep 2018 19:51:29 +0200
Network fixes
Diffstat:
5 files changed, 46 insertions(+), 56 deletions(-)
diff --git a/README.md b/README.md
@@ -1,9 +1,10 @@
-# Snapdrop
+# Snapdrop
-[Snapdrop](https://snapdrop.net) is a Progressive Web App inspired by Apple's Airdrop.
+[Snapdrop](https://snapdrop.net): local file sharing in your browser - inspired by Apple's Airdrop.
-#### Snapdrop is built with the following awesome technologies:
-* Vanilla HTML / JS / CSS
+#### Snapdrop Version 2 is built with the following awesome technologies:
+* Vanilla HTML5 / ES6 / CSS3
+* Progressive Web App
* [WebRTC](http://webrtc.org/)
* [WebSockets](http://www.websocket.org/) fallback (iDevices don't support WebRTC)
* [NodeJS](https://nodejs.org/en/)
@@ -24,7 +25,6 @@ It uses a P2P connection if WebRTC is supported by the browser. (WebRTC needs a
If WebRTC isn’t supported (Safari, IE) it uses a Web Sockets fallback for the file transfer. The server connects the clients with a stream.
-
##### What about privacy? Will files be saved on third-party-servers?
None of your files are ever saved on any server.
Snapdrop doesn't even use cookies or a database. If you are curious have a look [at the Server](https://github.com/RobinLinus/snapdrop/blob/master/server/ws-server.js).
@@ -45,12 +45,12 @@ ShareDrop uses WebRTC only and isn't compatible with Safari Browsers. Snapdrop u
## Local Development
```
- git clone git@github.com:RobinLinus/secret-snapdrop.git
- cd secret-snapdrop/server
+ git clone git@github.com:RobinLinus/snapdrop.git
+ cd snapdrop/server
npm install
node index.js
cd ../client
- python -m http.server
+ python -m SimpleHTTPServer
```
Now point your browser to http://localhost:8000.
diff --git a/client/scripts/network-v2.js b/client/scripts/network-v2.js
@@ -1,34 +0,0 @@
-class ServerConnection {
-
-}
-
-class Connection {
-
-}
-
-class WSConnection extends Connection {
-
-}
-
-class RTCConnection extends Connection {
-
-}
-
-class Peer {
-
- constructor(serverConnection) {
- this._ws = new WSConnection(serverConnection);
- this._rtc = new RTCConnection(serverConnection);
- this._fileReceiver = new FileReceiver(this);
- this._fileSender = new FileSender(this);
- }
-
- send(message) {
-
- }
-
-}
-
-class Peers {
-
-}
-\ No newline at end of file
diff --git a/client/scripts/network.js b/client/scripts/network.js
@@ -3,12 +3,14 @@ class ServerConnection {
constructor() {
this._connect();
Events.on('beforeunload', e => this._disconnect(), false);
+ Events.on('pagehide', e => this._disconnect(), false);
}
_connect() {
+ if (this._isConnected()) return;
const ws = new WebSocket(this._endpoint());
ws.binaryType = 'arraybuffer';
- ws.onopen = e => console.log('WS: server connection opened');
+ ws.onopen = e => console.log('WS: server connected');
ws.onmessage = e => this._onMessage(e.data);
ws.onclose = e => this._onDisconnect();
ws.onerror = e => console.error(e);
@@ -16,6 +18,10 @@ class ServerConnection {
clearTimeout(this._reconnectTimer);
}
+ _isConnected() {
+ return this._socket && this._socket.readyState === this._socket.OPEN;
+ }
+
_onMessage(msg) {
msg = JSON.parse(msg);
console.log('WS:', msg);
@@ -224,7 +230,7 @@ class RTCPeer extends Peer {
this._peerId = peerId;
this._peer = new RTCPeerConnection(RTCPeer.config);
this._peer.onicecandidate = e => this._onIceCandidate(e);
- this._peer.onconnectionstatechange = e => console.log('RTC: state changed:', this._peer.connectionState);
+ this._peer.onconnectionstatechange = e => this._onConnectionStateChange(e);
}
if (isCaller) {
@@ -237,7 +243,7 @@ class RTCPeer extends Peer {
_createChannel() {
const channel = this._peer.createDataChannel('data-channel', { reliable: true });
channel.binaryType = 'arraybuffer';
- channel.onopen = e => this._onChannelOpened(e)
+ channel.onopen = e => this._onChannelOpened(e);
this._peer.createOffer(d => this._onDescription(d), e => this._onError(e));
}
@@ -282,11 +288,19 @@ class RTCPeer extends Peer {
}
_onChannelClosed() {
- console.log('RTC: channel closed ', this._peerId);
+ console.log('RTC: channel closed', this._peerId);
if (!this.isCaller) return;
this._start(this._peerId, true); // reopen the channel
}
+ _onConnectionStateChange(e) {
+ console.log('RTC: state changed:', this._peer.connectionState);
+ switch (this._peer.connectionState) {
+ case 'disconnected': this._onChannelClosed();
+ break;
+ }
+ }
+
_send(message) {
this._channel.send(message);
}
diff --git a/client/scripts/ui.js b/client/scripts/ui.js
@@ -335,8 +335,8 @@ class Notifications {
constructor() {
// Check if the browser supports notifications
if (!('Notification' in window)) return;
+
// Check whether notification permissions have already been granted
-
if (Notification.permission !== 'granted') {
this.$button = $('notification');
this.$button.removeAttribute('hidden');
@@ -358,12 +358,17 @@ class Notifications {
}
_notify(message, body) {
- var img = '/images/logo_transparent_128x128.png';
- return new Notification(message, {
+ const config = {
body: body,
- icon: img,
+ icon: '/images/logo_transparent_128x128.png',
vibrate: [200, 100, 200, 100, 200, 100, 400],
- });
+ }
+ if (serviceWorker && serviceWorker.showNotification) {
+ // android doesn't support "new Notification" if service worker is installed
+ return serviceWorker.showNotification(message, config);
+ } else {
+ return new Notification(message, config);
+ }
}
_messageNotification(message) {
@@ -434,10 +439,14 @@ document.copy = text => {
return success;
}
-if ('serviceWorker' in navigator && isProductionEnvironment) {
+
+if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/service-worker.js')
- .then(e => console.log("Service Worker Registered"));
+ .then(serviceWorker => {
+ console.log('Service Worker registered');
+ window.serviceWorker = serviceWorker
+ });
}
// Background Animation
diff --git a/server/index.js b/server/index.js
@@ -34,12 +34,14 @@ class SnapdropServer {
switch (message.type) {
case 'disconnect':
this._leaveRoom(sender);
+ break;
case 'pong':
sender.lastBeat = Date.now();
+ break;
}
// relay message to recipient
- if (message.to) {
+ if (message.to && this._rooms[sender.ip]) {
const recipientId = message.to; // TODO: sanitize
const recipient = this._rooms[sender.ip][recipientId];
delete message.to;
@@ -84,7 +86,7 @@ class SnapdropServer {
_leaveRoom(peer) {
// delete the peer
this._cancelKeepAlive(peer);
- if (!this._rooms[peer.ip]) return;
+ if (!this._rooms[peer.ip] || !this._rooms[peer.ip][peer.id]) return;
delete this._rooms[peer.ip][peer.id];