fix small bugs - working version with turn server of relay.metered.ca
This commit is contained in:
parent
ecc29b39d7
commit
72f3bb0e7c
4 changed files with 125 additions and 29 deletions
|
@ -8,6 +8,7 @@ class ServerConnection {
|
||||||
Events.on('beforeunload', e => this._disconnect());
|
Events.on('beforeunload', e => this._disconnect());
|
||||||
Events.on('pagehide', e => this._disconnect());
|
Events.on('pagehide', e => this._disconnect());
|
||||||
document.addEventListener('visibilitychange', e => this._onVisibilityChange());
|
document.addEventListener('visibilitychange', e => this._onVisibilityChange());
|
||||||
|
Events.on('online', this._reconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
_connect() {
|
_connect() {
|
||||||
|
@ -15,11 +16,13 @@ class ServerConnection {
|
||||||
if (this._isConnected() || this._isConnecting()) return;
|
if (this._isConnected() || this._isConnecting()) return;
|
||||||
const ws = new WebSocket(this._endpoint());
|
const ws = new WebSocket(this._endpoint());
|
||||||
ws.binaryType = 'arraybuffer';
|
ws.binaryType = 'arraybuffer';
|
||||||
ws.onopen = e => console.log('WS: server connected');
|
ws.onopen = _ => console.log('WS: server connected');
|
||||||
ws.onmessage = e => this._onMessage(e.data);
|
ws.onmessage = e => this._onMessage(e.data);
|
||||||
ws.onclose = e => this._onDisconnect();
|
ws.onclose = _ => this._onDisconnect();
|
||||||
ws.onerror = e => console.error(e);
|
ws.onerror = e => this._onError(e);
|
||||||
this._socket = ws;
|
this._socket = ws;
|
||||||
|
|
||||||
|
Events.on('force-disconnect', this._onForceDisconnect);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessage(msg) {
|
_onMessage(msg) {
|
||||||
|
@ -45,7 +48,7 @@ class ServerConnection {
|
||||||
Events.fire('display-name', msg);
|
Events.fire('display-name', msg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error('WS: unkown message type', msg);
|
console.error('WS: unknown message type', msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,21 +61,28 @@ class ServerConnection {
|
||||||
// hack to detect if deployment or development environment
|
// hack to detect if deployment or development environment
|
||||||
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
const protocol = location.protocol.startsWith('https') ? 'wss' : 'ws';
|
||||||
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
const webrtc = window.isRtcSupported ? '/webrtc' : '/fallback';
|
||||||
const url = protocol + '://' + location.host + location.pathname + 'server' + webrtc;
|
return protocol + '://' + location.host + location.pathname + 'server' + webrtc;
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_disconnect() {
|
_disconnect() {
|
||||||
this.send({ type: 'disconnect' });
|
this.send({ type: 'disconnect' });
|
||||||
this._socket.onclose = null;
|
this._socket.onclose = null;
|
||||||
this._socket.close();
|
this._socket.close();
|
||||||
|
Events.fire('disconnect');
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDisconnect() {
|
_onDisconnect() {
|
||||||
console.log('WS: server disconnected');
|
console.log('WS: server disconnected');
|
||||||
Events.fire('notify-user', 'Connection lost. Retry in 5 seconds...');
|
Events.fire('notify-user', 'Connection lost. Retry in 5 seconds...');
|
||||||
clearTimeout(this._reconnectTimer);
|
clearTimeout(this._reconnectTimer);
|
||||||
this._reconnectTimer = setTimeout(_ => this._connect(), 5000);
|
this._reconnectTimer = setTimeout(this._connect, 5000);
|
||||||
|
Events.fire('disconnect');
|
||||||
|
}
|
||||||
|
|
||||||
|
_onForceDisconnect() {
|
||||||
|
document.cookie = "peerid=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
|
||||||
|
this._disconnect();
|
||||||
|
this._connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onVisibilityChange() {
|
_onVisibilityChange() {
|
||||||
|
@ -87,6 +97,17 @@ class ServerConnection {
|
||||||
_isConnecting() {
|
_isConnecting() {
|
||||||
return this._socket && this._socket.readyState === this._socket.CONNECTING;
|
return this._socket && this._socket.readyState === this._socket.CONNECTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_reconnect() {
|
||||||
|
console.log("reconnect")
|
||||||
|
this._disconnect();
|
||||||
|
this._connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
_onError(e) {
|
||||||
|
console.error(e);
|
||||||
|
this._onForceDisconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Peer {
|
class Peer {
|
||||||
|
@ -189,7 +210,7 @@ class Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChunkReceived(chunk) {
|
_onChunkReceived(chunk) {
|
||||||
if(!chunk.byteLength) return;
|
if(!(chunk.byteLength || chunk.size)) return;
|
||||||
|
|
||||||
this._digester.unchunk(chunk);
|
this._digester.unchunk(chunk);
|
||||||
const progress = this._digester.progress;
|
const progress = this._digester.progress;
|
||||||
|
@ -333,6 +354,7 @@ class RTCPeer extends Peer {
|
||||||
switch (this._conn.iceConnectionState) {
|
switch (this._conn.iceConnectionState) {
|
||||||
case 'failed':
|
case 'failed':
|
||||||
console.error('ICE Gathering failed');
|
console.error('ICE Gathering failed');
|
||||||
|
Events.fire('force-disconnect');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.log('ICE Gathering', this._conn.iceConnectionState);
|
console.log('ICE Gathering', this._conn.iceConnectionState);
|
||||||
|
@ -379,6 +401,7 @@ class PeersManager {
|
||||||
Events.on('files-selected', e => this._onFilesSelected(e.detail));
|
Events.on('files-selected', e => this._onFilesSelected(e.detail));
|
||||||
Events.on('send-text', e => this._onSendText(e.detail));
|
Events.on('send-text', e => this._onSendText(e.detail));
|
||||||
Events.on('peer-left', e => this._onPeerLeft(e.detail));
|
Events.on('peer-left', e => this._onPeerLeft(e.detail));
|
||||||
|
Events.on('disconnect', this._clearPeers);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessage(message) {
|
_onMessage(message) {
|
||||||
|
@ -421,6 +444,11 @@ class PeersManager {
|
||||||
peer._peer.close();
|
peer._peer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_clearPeers() {
|
||||||
|
if (this.peers) {
|
||||||
|
Object.keys(this.peers).forEach(peerId => this._onPeerLeft(peerId));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WSPeer extends Peer {
|
class WSPeer extends Peer {
|
||||||
|
@ -529,10 +557,41 @@ class Events {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RTCPeer.config = {
|
RTCPeer.config = {
|
||||||
'sdpSemantics': 'unified-plan',
|
'sdpSemantics': 'unified-plan',
|
||||||
'iceServers': [{
|
// iceServers: [
|
||||||
urls: 'stun:stun.l.google.com:19302'
|
// {
|
||||||
}]
|
// urls: 'stun:127.0.0.1:3478',
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// urls: 'turn:127.0.0.1:3478',
|
||||||
|
// username: 'snapdrop',
|
||||||
|
// credential: 'ifupvrwelijmoyjxmefcsvfxxmcphvxo'
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
iceServers: [
|
||||||
|
{
|
||||||
|
urls: "stun:relay.metered.ca:80",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
urls: "turn:relay.metered.ca:80",
|
||||||
|
username: "411061cd290de7ca6cc1a753",
|
||||||
|
credential: "CuCIGdVfA9Gias1E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
urls: "turn:relay.metered.ca:443",
|
||||||
|
username: "411061cd290de7ca6cc1a753",
|
||||||
|
credential: "CuCIGdVfA9Gias1E",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// iceServers: [
|
||||||
|
// {
|
||||||
|
// urls: 'stun:stun.l.google.com:19302'
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// urls: 'turn:om.wulingate.com',
|
||||||
|
// username: 'hmzJ0OHZivkod703',
|
||||||
|
// credential: 'KDF04PBYD9xHAp0s'
|
||||||
|
// },
|
||||||
|
// ]
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ class PeersUI {
|
||||||
Events.on('peers', e => this._onPeers(e.detail));
|
Events.on('peers', e => this._onPeers(e.detail));
|
||||||
Events.on('file-progress', e => this._onFileProgress(e.detail));
|
Events.on('file-progress', e => this._onFileProgress(e.detail));
|
||||||
Events.on('paste', e => this._onPaste(e));
|
Events.on('paste', e => this._onPaste(e));
|
||||||
|
Events.on('offline', () => this._clearPeers());
|
||||||
this.peers = {};
|
this.peers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +33,8 @@ class PeersUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPeerConnected(peerId) {
|
_onPeerConnected(peerId) {
|
||||||
new PeerUI(this.peers[peerId]);
|
if(this.peers[peerId])
|
||||||
|
new PeerUI(this.peers[peerId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPeers(peers) {
|
_onPeers(peers) {
|
||||||
|
@ -47,6 +49,7 @@ class PeersUI {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPeerLeft(peerId) {
|
_onPeerLeft(peerId) {
|
||||||
|
this._onPeerDisconnected(peerId);
|
||||||
delete this.peers[peerId];
|
delete this.peers[peerId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +62,7 @@ class PeersUI {
|
||||||
|
|
||||||
_clearPeers() {
|
_clearPeers() {
|
||||||
const $peers = $$('x-peers').innerHTML = '';
|
const $peers = $$('x-peers').innerHTML = '';
|
||||||
Object.keys(this.peers).forEach(key => delete this.peers[key]);
|
Object.keys(this.peers).forEach(peerId => delete this.peers[peerId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPaste(e) {
|
_onPaste(e) {
|
||||||
|
@ -223,8 +226,8 @@ class Dialog {
|
||||||
this.$el = $(id);
|
this.$el = $(id);
|
||||||
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', e => this.hide()))
|
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', e => this.hide()))
|
||||||
this.$el.querySelectorAll('[role="textbox"]').forEach((el) => {
|
this.$el.querySelectorAll('[role="textbox"]').forEach((el) => {
|
||||||
el.addEventListener("keypress", (e) => {
|
el.addEventListener("keydown", (e) => {
|
||||||
if (e.key == "Escape") {
|
if (e.key === "Escape") {
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -511,8 +514,8 @@ class Notifications {
|
||||||
class NetworkStatusUI {
|
class NetworkStatusUI {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
Events.on('offline', e => this._showOfflineMessage());
|
Events.on('offline', this._showOfflineMessage);
|
||||||
Events.on('online', e => this._showOnlineMessage());
|
Events.on('online', this._showOnlineMessage);
|
||||||
if (!navigator.onLine) this._showOfflineMessage();
|
if (!navigator.onLine) this._showOfflineMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./server/:/home/node/app
|
- ./server/:/home/node/app
|
||||||
command: ash -c "npm i && node index.js"
|
command: ash -c "npm i && node index.js"
|
||||||
|
restart: unless-stopped
|
||||||
nginx:
|
nginx:
|
||||||
build:
|
build:
|
||||||
context: ./docker/
|
context: ./docker/
|
||||||
|
@ -23,3 +24,4 @@ services:
|
||||||
env_file: ./docker/fqdn.env
|
env_file: ./docker/fqdn.env
|
||||||
entrypoint: /mnt/openssl/create.sh
|
entrypoint: /mnt/openssl/create.sh
|
||||||
command: ["nginx", "-g", "daemon off;"]
|
command: ["nginx", "-g", "daemon off;"]
|
||||||
|
restart: unless-stopped
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
var process = require('process')
|
var process = require('process')
|
||||||
|
var net = require('net')
|
||||||
// Handle SIGINT
|
// Handle SIGINT
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
console.info("SIGINT Received, exiting...")
|
console.info("SIGINT Received, exiting...")
|
||||||
|
@ -43,10 +44,10 @@ class SnapdropServer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onHeaders(headers, response) {
|
_onHeaders(headers, request) {
|
||||||
if (response.headers.cookie && response.headers.cookie.indexOf('peerid=') > -1) return;
|
if (request.headers.cookie && request.headers.cookie.indexOf('peerid=') > -1) return;
|
||||||
response.peerId = Peer.uuid();
|
request.peerId = Peer.uuid();
|
||||||
headers.push('Set-Cookie: peerid=' + response.peerId + "; SameSite=Strict; Secure");
|
headers.push('Set-Cookie: peerid=' + request.peerId + "; SameSite=Strict; Secure");
|
||||||
}
|
}
|
||||||
|
|
||||||
_onMessage(sender, message) {
|
_onMessage(sender, message) {
|
||||||
|
@ -181,6 +182,7 @@ class Peer {
|
||||||
// for keepalive
|
// for keepalive
|
||||||
this.timerId = 0;
|
this.timerId = 0;
|
||||||
this.lastBeat = Date.now();
|
this.lastBeat = Date.now();
|
||||||
|
console.debug(this.name.displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
_setIP(request) {
|
_setIP(request) {
|
||||||
|
@ -192,18 +194,48 @@ class Peer {
|
||||||
this.ip = request.connection.remoteAddress;
|
this.ip = request.connection.remoteAddress;
|
||||||
}
|
}
|
||||||
// IPv4 and IPv6 use different values to refer to localhost
|
// IPv4 and IPv6 use different values to refer to localhost
|
||||||
if (this.ip === '::1' || this.ip === '::ffff:127.0.0.1') {
|
// put all peers on the same network as the server into the same room as well
|
||||||
this.ip = '127.0.0.1';
|
if (this.ip === '::1' || this.ip === '::ffff:127.0.0.1' || this.ip === '::1' || this.ipIsPrivate(this.ip)) {
|
||||||
}
|
|
||||||
// put all peers on the same network as the server into the same room
|
|
||||||
if (this.ipIsPrivate(this.ip)) {
|
|
||||||
this.ip = '127.0.0.1';
|
this.ip = '127.0.0.1';
|
||||||
}
|
}
|
||||||
|
console.debug(this.ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
ipIsPrivate(ip) {
|
ipIsPrivate(ip) {
|
||||||
// 10.0.0.0 - 10.255.255.255 || 172.16.0.0 - 172.31.255.255 || 192.168.0.0 - 192.168.255.255
|
if (ip.substring(0,7) === "::ffff:")
|
||||||
return /^(10)\.(.*)\.(.*)\.(.*)$/.test(ip) || /^(172)\.(1[6-9]|2[0-9]|3[0-1])\.(.*)\.(.*)$/.test(ip) || /^(192)\.(168)\.(.*)\.(.*)$/.test(ip)
|
ip = ip.substring(7);
|
||||||
|
|
||||||
|
if (net.isIPv4(ip)) {
|
||||||
|
// 10.0.0.0 - 10.255.255.255 || 172.16.0.0 - 172.31.255.255 || 192.168.0.0 - 192.168.255.255
|
||||||
|
return /^(10)\.(.*)\.(.*)\.(.*)$/.test(ip) || /^(172)\.(1[6-9]|2[0-9]|3[0-1])\.(.*)\.(.*)$/.test(ip) || /^(192)\.(168)\.(.*)\.(.*)$/.test(ip)
|
||||||
|
}
|
||||||
|
|
||||||
|
// else: ip is IPv6
|
||||||
|
const firstWord = ip.split(":").find(el => !!el); //get first not empty word
|
||||||
|
|
||||||
|
// The original IPv6 Site Local addresses (fec0::/10) are deprecated. Range: fec0 - feff
|
||||||
|
if (/^fe[c-f][0-f]$/.test(firstWord))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// These days Unique Local Addresses (ULA) are used in place of Site Local.
|
||||||
|
// Range: fc00 - fcff
|
||||||
|
else if (/^fc[0-f]{2}$/.test(firstWord))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Range: fd00 - fcff
|
||||||
|
else if (/^fd[0-f]{2}$/.test(firstWord))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Link local addresses (prefixed with fe80) are not routable
|
||||||
|
else if (firstWord === "fe80")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Discard Prefix
|
||||||
|
else if (firstWord === "100")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Any other IP address is not Unique Local Address (ULA)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setPeerId(request) {
|
_setPeerId(request) {
|
||||||
|
|
Loading…
Reference in a new issue