Handle WebSocket errors

This commit is contained in:
Luc Didry 2015-10-10 00:42:30 +02:00 committed by Luc Didry
parent 100e62cc5e
commit a594b9111c
6 changed files with 168 additions and 83 deletions

View File

@ -82,27 +82,33 @@ sub upload {
);
$f->write;
}
# Create directory
my $dir = catdir('files', $f->short);
mkdir($dir, 0700) unless (-d $dir);
# Create slice file
my $file = catfile($dir, $json->{part}.'.part');
my $s = Lufi::Slice->new(
short => $f->short,
j => $json->{part},
path => $file
);
spurt $text, $file;
push @{$f->slices}, $s;
# If we already have a part, it's a resend because the websocket has been broken
# In this case, we don't need to rewrite the file
unless ($f->slices->grep(sub { $_->j == $json->{part} })->size) {
# Create directory
my $dir = catdir('files', $f->short);
mkdir($dir, 0700) unless (-d $dir);
if (($json->{part} + 1) == $json->{total}) {
$f->complete(1);
$f->created_at(time);
$c->provisioning;
# Create slice file
my $file = catfile($dir, $json->{part}.'.part');
my $s = Lufi::Slice->new(
short => $f->short,
j => $json->{part},
path => $file
);
spurt $text, $file;
push @{$f->slices}, $s;
if (($json->{part} + 1) == $json->{total}) {
$f->complete(1);
$f->created_at(time);
}
$f->write;
}
$f->write;
$c->provisioning;
$ws->send(sprintf('{"success": true, "i": %d, "j": %d, "parts": %d, "short": "%s", "name": "%s", "size": %d, "del_at_first_view": %s, "created_at": %d, "delay": %d, "token": "%s", "sent_delay": %d}', $json->{i}, $json->{part}, $json->{total}, $f->short, $f->filename, $f->filesize, (($f->delete_at_first_view) ? 'true' : 'false'), $f->created_at, $f->delete_at_day, $f->mod_token, $json->{delay}));
}

View File

@ -65,11 +65,11 @@ msgstr ""
msgid "Copy to clipboard"
msgstr ""
#: lib/Lufi/Controller/Files.pm:284
#: lib/Lufi/Controller/Files.pm:288
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr ""
#: lib/Lufi/Controller/Files.pm:212
#: lib/Lufi/Controller/Files.pm:216
msgid "Could not find the file. Are you sure of the URL?"
msgstr ""
@ -117,19 +117,23 @@ msgstr ""
msgid "Emails"
msgstr ""
#: lib/Lufi/Controller/Files.pm:148
#: themes/default/templates/index.html.ep:87
msgid "Encrypting part XX1 of XX2"
msgstr ""
#: lib/Lufi/Controller/Files.pm:152
msgid "Error: the file existed but has been deleted."
msgstr ""
#: lib/Lufi/Controller/Files.pm:189
#: lib/Lufi/Controller/Files.pm:193
msgid "Error: the file has not been send entirely."
msgstr ""
#: lib/Lufi/Controller/Files.pm:194
#: lib/Lufi/Controller/Files.pm:198
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr ""
#: themes/default/templates/index.html.ep:87
#: themes/default/templates/index.html.ep:88
msgid "Expiration:"
msgstr ""
@ -141,7 +145,7 @@ msgstr ""
msgid "Export localStorage data"
msgstr ""
#: lib/Lufi/Controller/Files.pm:268
#: lib/Lufi/Controller/Files.pm:272
msgid "File deleted"
msgstr ""
@ -161,11 +165,11 @@ msgstr ""
msgid "Here's some files"
msgstr ""
#: themes/default/templates/index.html.ep:89
#: themes/default/templates/index.html.ep:90
msgid "Hit Enter, then Ctrl+C to copy all the download links"
msgstr ""
#: themes/default/templates/index.html.ep:88
#: themes/default/templates/index.html.ep:89
msgid "Hit Enter, then Ctrl+C to copy the download link"
msgstr ""
@ -218,11 +222,11 @@ msgid "My files"
msgstr ""
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:47
#: lib/Lufi/Controller/Files.pm:45
msgid "No enough space available on the server for this file (size: %1)."
msgstr ""
#: themes/default/templates/files.html.ep:41 themes/default/templates/index.html.ep:91
#: themes/default/templates/files.html.ep:41 themes/default/templates/index.html.ep:92
msgid "No expiration delay"
msgstr ""
@ -251,7 +255,7 @@ msgstr ""
msgid "Rows in red means that the file has expired and is no longer available."
msgstr ""
#: themes/default/templates/index.html.ep:90
#: themes/default/templates/index.html.ep:91
msgid "Send all links by email"
msgstr ""
@ -263,6 +267,10 @@ msgstr ""
msgid "Send with your own mail software"
msgstr ""
#: themes/default/templates/index.html.ep:93
msgid "Sending part XX1 of XX2"
msgstr ""
#. (url_for('/')
#: themes/default/templates/mail.html.ep:75
msgid "Share your files in total privacy on %1"
@ -272,7 +280,7 @@ msgstr ""
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr ""
#: lib/Lufi/Controller/Files.pm:35
#: lib/Lufi/Controller/Files.pm:33
msgid "Sorry, uploading is disabled."
msgstr ""
@ -292,7 +300,7 @@ msgstr ""
msgid "The email subject can't be empty."
msgstr ""
#: lib/Lufi/Controller/Files.pm:265
#: lib/Lufi/Controller/Files.pm:269
msgid "The file has already been deleted"
msgstr ""
@ -319,12 +327,12 @@ msgid "This server sets limitations according to the file size. The expiration d
msgstr ""
#. ($short)
#: lib/Lufi/Controller/Files.pm:249
#: lib/Lufi/Controller/Files.pm:253
msgid "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage."
msgstr ""
#. ($short)
#: lib/Lufi/Controller/Files.pm:239
#: lib/Lufi/Controller/Files.pm:243
msgid "Unable to get counter for %1. The token is unvalid."
msgstr ""
@ -373,7 +381,7 @@ msgid "You must give email addresses."
msgstr ""
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:41
#: lib/Lufi/Controller/Files.pm:39
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr ""

View File

@ -71,11 +71,11 @@ msgstr "Copier tous les liens dans le presse-papier"
msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier"
#: lib/Lufi/Controller/Files.pm:284
#: lib/Lufi/Controller/Files.pm:288
msgid "Could not find the file. Are you sure of the URL and the token?"
msgstr "Impossible de retrouver le fichier. Êtes-vous sûr(e) que lURL et le jeton sont les bons ?"
#: lib/Lufi/Controller/Files.pm:212
#: lib/Lufi/Controller/Files.pm:216
msgid "Could not find the file. Are you sure of the URL?"
msgstr "Impossible de retrouver le fichier. Êtes-vous sûr(e) que lURL est la bonne ?"
@ -123,19 +123,23 @@ msgstr "Sujet du mail"
msgid "Emails"
msgstr "Mails"
#: lib/Lufi/Controller/Files.pm:148
#: themes/default/templates/index.html.ep:87
msgid "Encrypting part XX1 of XX2"
msgstr "Chiffrement du fragment XX1 sur XX2"
#: lib/Lufi/Controller/Files.pm:152
msgid "Error: the file existed but has been deleted."
msgstr "Erreur : le fichier existait mais a été supprimé"
#: lib/Lufi/Controller/Files.pm:189
#: lib/Lufi/Controller/Files.pm:193
msgid "Error: the file has not been send entirely."
msgstr "Erreur : le fichier na pas été envoyé dans son intégralité"
#: lib/Lufi/Controller/Files.pm:194
#: lib/Lufi/Controller/Files.pm:198
msgid "Error: unable to find the file. Are you sure of your URL?"
msgstr "Erreur : impossible de retrouver le fichier. Êtes-vous sûr(e) de lURL ?"
#: themes/default/templates/index.html.ep:87
#: themes/default/templates/index.html.ep:88
msgid "Expiration:"
msgstr "Expiration :"
@ -147,7 +151,7 @@ msgstr "Expire le"
msgid "Export localStorage data"
msgstr "Exporter les données localStorage"
#: lib/Lufi/Controller/Files.pm:268
#: lib/Lufi/Controller/Files.pm:272
msgid "File deleted"
msgstr "Fichier supprimé"
@ -167,11 +171,11 @@ msgstr "Bonjour,\\n\\nVoici quelques fichiers que je souhaite partager avec toi
msgid "Here's some files"
msgstr "Voici quelques fichiers"
#: themes/default/templates/index.html.ep:89
#: themes/default/templates/index.html.ep:90
msgid "Hit Enter, then Ctrl+C to copy all the download links"
msgstr "Appuyez sur la touche Entrée puis faites Ctrl+C pour copier tous les liens de téléchargement"
#: themes/default/templates/index.html.ep:88
#: themes/default/templates/index.html.ep:89
msgid "Hit Enter, then Ctrl+C to copy the download link"
msgstr "Appuyez sur la touche Entrée puis faites Ctrl+C pour copier le lien de téléchargement"
@ -224,11 +228,11 @@ msgid "My files"
msgstr "Mes fichiers"
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:47
#: lib/Lufi/Controller/Files.pm:45
msgid "No enough space available on the server for this file (size: %1)."
msgstr "Espace disque insuffisant sur le serveur pour ce fichier (taille du fichier: %1)."
#: themes/default/templates/files.html.ep:41 themes/default/templates/index.html.ep:91
#: themes/default/templates/files.html.ep:41 themes/default/templates/index.html.ep:92
msgid "No expiration delay"
msgstr "Pas de délai dexpiration"
@ -261,7 +265,7 @@ msgstr "Supprimer du localStorage les fichiers expirés"
msgid "Rows in red means that the file has expired and is no longer available."
msgstr "Les lignes en rouge indiquent que le fichier a expiré et nest plus disponible."
#: themes/default/templates/index.html.ep:90
#: themes/default/templates/index.html.ep:91
msgid "Send all links by email"
msgstr "Envoyer tous les liens par mail"
@ -273,6 +277,10 @@ msgstr "Envoyer avec ce serveur"
msgid "Send with your own mail software"
msgstr "Envoyer avec votre propre logiciel de mail"
#: themes/default/templates/index.html.ep:93
msgid "Sending part XX1 of XX2"
msgstr "Envoi du fragment XX1 sur XX2"
#. (url_for('/')
#: themes/default/templates/mail.html.ep:75
msgid "Share your files in total privacy on %1"
@ -282,7 +290,7 @@ msgstr "Partagez vos fichiers en toute confidentialité sur %1"
msgid "Sorry, the uploading is currently disabled. Please try again later."
msgstr "Désolé, lenvoi de fichier est actuellement désactivé. Veuillez réessayer plus tard."
#: lib/Lufi/Controller/Files.pm:35
#: lib/Lufi/Controller/Files.pm:33
msgid "Sorry, uploading is disabled."
msgstr "Désolé, lenvoi de fichier est désactivé."
@ -302,7 +310,7 @@ msgstr "Le corps du mail ne peut être vide."
msgid "The email subject can't be empty."
msgstr "Le sujet du mail ne peut être vide."
#: lib/Lufi/Controller/Files.pm:265
#: lib/Lufi/Controller/Files.pm:269
msgid "The file has already been deleted"
msgstr "Le fichier a déjà été supprimé"
@ -333,12 +341,12 @@ msgid "Unable to get counter for %1. The file does not exists."
msgstr "Impossible de récupérer le compteur de %1. Le fichier nexiste pas."
#. ($short)
#: lib/Lufi/Controller/Files.pm:249
#: lib/Lufi/Controller/Files.pm:253
msgid "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage."
msgstr "Impossible de récupérer le compteur pour %1. Le fichier nexiste pas. Il va être supprimé de votre localStorage."
#. ($short)
#: lib/Lufi/Controller/Files.pm:239
#: lib/Lufi/Controller/Files.pm:243
msgid "Unable to get counter for %1. The token is unvalid."
msgstr "Impossible de récupérer le compteur pour %1. Le jeton est invalide."
@ -387,7 +395,7 @@ msgid "You must give email addresses."
msgstr "Vous devez envoyer des adresses mail."
#. (format_bytes($json->{size})
#: lib/Lufi/Controller/Files.pm:41
#: lib/Lufi/Controller/Files.pm:39
msgid "Your file is too big: %1 (maximum size allowed: %2)"
msgstr "Votre fichier est trop volumineux : %1 (la taille maximum autorisée est %2)"

View File

@ -42,14 +42,20 @@ function addAlert(msg) {
}
// Spawn WebSocket
function spawnWebsocket() {
function spawnWebsocket(pa) {
var ws = new WebSocket(ws_url);
ws.onopen = function() {
console.log('Connection is established!');
ws.send('{"part":0}');
window.ws.send('{"part":'+pa+'}');
};
ws.onclose = function() {
console.log('Connection is closed');
if (!window.completed) {
console.log('Connection closed. Retrying to get slice '+pa+' in 5 seconds');
setTimeout(function() {
window.ws = spawnWebsocket(pa);
}, 5000);
}
}
ws.onmessage = function(e) {
var res = e.data.split('XXMOJOXX');
@ -58,8 +64,10 @@ function spawnWebsocket() {
if (data.msg !== undefined) {
addAlert(data.msg);
console.log(data.msg);
window.onbeforeunload = null;
} else {
console.log('Getting slice '+(data.part + 1)+' of '+data.total);
var slice = JSON.parse(res.shift());
var percent = Math.round(100 * (data.part + 1)/data.total);
var pb = document.getElementById('pb');
@ -68,7 +76,7 @@ function spawnWebsocket() {
document.getElementById('pbt').innerHTML = percent+'%';
try {
var b64 = sjcl.decrypt(window.key, slice);
window.a.push(base64ToArrayBuffer(b64));
window.a[data.part] = base64ToArrayBuffer(b64);
if (data.part + 1 === data.total) {
var blob = new File(a, data.name, {type: data.type});
@ -78,13 +86,30 @@ function spawnWebsocket() {
pbd.setAttribute('class', '');
pbd.innerHTML = '<a href="'+URL.createObjectURL(blob)+'" class="btn btn-primary" download="'+data.name+'">'+i18n.download+'</a>';
ws.send('{"ended":true}');
window.ws.send('{"ended":true}');
window.onbeforeunload = null;
window.completed = true;
} else {
if (ws.readyState === 3) {
ws = spawnWebsocket();
window.ws = spawnWebsocket(data.part + 1);
} else {
window.ws.onclose = function() {
console.log('Connection is closed');
if (!window.completed) {
console.log('Connection closed. Retrying to get slice '+(data.part + 1)+' in 5 seconds');
setTimeout(function() {
window.ws = spawnWebsocket(data.part + 1);
}, 5000);
}
}
window.ws.onerror = function() {
console.log('Error. Retrying to get slice '+(data.part + 1)+' in 5 seconds');
setTimeout(function() {
window.ws = spawnWebsocket(data.part + 1);
}, 5000);
};
window.ws.send('{"part":'+(data.part + 1)+'}');
}
ws.send('{"part":'+(data.part + 1)+'}');
}
} catch(err) {
if (err.message === 'ccm: tag doesn\'t match') {
@ -97,17 +122,22 @@ function spawnWebsocket() {
}
}
ws.onerror = function() {
console.log('error');
console.log('Error. Retrying to get slice '+pa+' in 5 seconds');
setTimeout(function() {
window.ws = spawnWebsocket(pa);
}, 5000);
}
return ws;
}
// When it's ready
document.addEventListener('DOMContentLoaded', function() {
window.a = new Array();
window.key = pageKey();
window.a = new Array();
window.key = pageKey();
window.completed = false;
if (key !== '=') {
// Set websocket
ws = spawnWebsocket();
window.ws = spawnWebsocket(0);
// Prevent exiting page before full download
window.onbeforeunload = confirmExit;

View File

@ -147,7 +147,7 @@ function uploadFile(i, delay, del_at_first_view) {
var r = document.getElementById('ul-results');
var w = document.createElement('li');
w.setAttribute('class', 'list-group-item');
w.innerHTML='<div><a href="#" onclick="destroyBlock(this);"><span class="pull-right icon icon-cancel"></span></a><p id="name-'+window.fc+'">'+file.name+'</p></div><div class="progress"><div id="progress-'+window.fc+'" style="width: 0%;" data-key="'+randomkey+'" data-name="'+file.name+'" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" role="progressbar" class="progress-bar"><span class="sr-only">'+file.name+'0%</span></div></div>';
w.innerHTML='<div><a href="#" onclick="destroyBlock(this);"><span class="pull-right icon icon-cancel"></span></a><p id="name-'+window.fc+'">'+file.name+'</p><p id="parts-'+window.fc+'"></p></div><div class="progress"><div id="progress-'+window.fc+'" style="width: 0%;" data-key="'+randomkey+'" data-name="'+file.name+'" aria-valuemax="100" aria-valuemin="0" aria-valuenow="0" role="progressbar" class="progress-bar"><span class="sr-only">'+file.name+'0%</span></div></div>';
r.appendChild(w);
sliceAndUpload(randomkey, i, parts, 0, delay, del_at_first_view, null);
@ -159,6 +159,8 @@ function sliceAndUpload(randomkey, i, parts, j, delay, del_at_first_view, short)
var slice = file.slice(j * window.sliceLength, (j + 1) * window.sliceLength, file.type);
var fr = new FileReader();
fr.onloadend = function() {
var sl = document.getElementById('parts-'+window.fc);
// Get the binary result
var bin = fr.result;
@ -166,6 +168,7 @@ function sliceAndUpload(randomkey, i, parts, j, delay, del_at_first_view, short)
var b = window.btoa(bin);
// Encrypt it
sl.innerHTML = i18n.encrypting.replace(/XX1(.*)XX2/, (j+1)+'$1'+parts);
var encrypted = sjcl.encrypt(randomkey, b);
// Prepare json
@ -184,12 +187,23 @@ function sliceAndUpload(randomkey, i, parts, j, delay, del_at_first_view, short)
console.log('sending slice '+(j + 1)+'/'+parts+' of file '+file.name);
sl.innerHTML = i18n.sending.replace(/XX1(.*)XX2/, (j+1)+'$1'+parts);
// Verify that we have a websocket and send json
if (window.ws.readyState === 3) {
window.ws = spawnWebsocket(function() {
window.ws = spawnWebsocket(0, function() {
window.ws.send(data+'XXMOJOXX'+JSON.stringify(encrypted));
});
} else {
window.ws.onerror = function() {
console.log('Error on Websocket, waiting 10sec.');
setTimeout(function() {
window.ws = spawnWebsocket(0, function() {
console.log('sending again slice '+(j + 1)+'/'+parts+' of file '+file.name);
window.ws.send(data+'XXMOJOXX'+JSON.stringify(encrypted));
});
}, 10000);
};
window.ws.send(data+'XXMOJOXX'+JSON.stringify(encrypted));
}
}
@ -214,6 +228,7 @@ function updateProgressBar(data) {
var key = dp.getAttribute('data-key');
if (j + 1 === parts) {
document.getElementById('parts-'+window.fc).remove();
var n = document.getElementById('name-'+window.fc);
var d = document.createElement('div');
var url = baseURL+'r/'+short+'#'+key;
@ -289,26 +304,33 @@ function updateProgressBar(data) {
sliceAndUpload(key, i, parts, j, delay, del_at_first_view, short);
}
} else {
var n = document.getElementById('name-'+window.fc);
var p = document.getElementById('progress-'+window.fc);
var d = document.createElement('div');
addAlertOnFile(data.msg, i, delay, del_at_first_view);
}
}
p.parentNode.remove();
d.innerHTML = data.msg;
d.setAttribute('class', 'alert alert-danger');
n.parentNode.appendChild(d);
// Upload next file
window.fc++;
i++;
if (i < window.files.length) {
uploadFile(i, sent_delay, del_at_first_view);
} else {
// We have finished
window.onbeforeunload = null;
document.getElementById('delete-day').removeAttribute('disabled');
document.getElementById('first-view').removeAttribute('disabled');
}
// Write message instead in a file block
function addAlertOnFile(msg, i, sent_delay, del_at_first_view) {
var n = document.getElementById('name-'+window.fc);
var p = document.getElementById('progress-'+window.fc);
var d = document.createElement('div');
p.parentNode.remove();
d.innerHTML = msg;
d.setAttribute('class', 'alert alert-danger');
n.parentNode.appendChild(d);
// Upload next file
window.fc++;
i++;
if (i < window.files.length) {
uploadFile(i, sent_delay, del_at_first_view);
} else {
// We have finished
window.onbeforeunload = null;
document.getElementById('delete-day').removeAttribute('disabled');
document.getElementById('first-view').removeAttribute('disabled');
}
}
@ -327,7 +349,10 @@ function handleDragOver(evt) {
}
// Spawn websocket
function spawnWebsocket(callback) {
function spawnWebsocket(i, callback) {
if (i === undefined || i === null) {
i = 0;
}
var ws = new WebSocket(ws_url);
ws.onopen = function() {
console.log('Connection is established!');
@ -342,6 +367,12 @@ function spawnWebsocket(callback) {
updateProgressBar(JSON.parse(e.data));
}
ws.onerror = function() {
if (i < 5 && callback !== undefined) {
setTimeout(function() {
console.log('Retrying to send file '+i);
window.ws = spawnWebsocket(i + 1, callback);
}, 10000);
}
console.log('error');
}
return ws;
@ -355,7 +386,7 @@ document.addEventListener('DOMContentLoaded', function() {
dropZone.addEventListener('drop', handleDrop, false);
// Set websocket
window.ws = spawnWebsocket();
window.ws = spawnWebsocket(0, function() {return null;});
// Use slice of 10MB
window.sliceLength = 2000000;

View File

@ -84,11 +84,13 @@ var i18n = {
delText: '<%= l('Deletion link') %>',
dlText: '<%= l('Download link') %>',
download: '<%= l('Download') %>',
encrypting: '<%= l('Encrypting part XX1 of XX2') %>',
expiration: '<%= l('Expiration:') %>',
hit: '<%= l('Hit Enter, then Ctrl+C to copy the download link') %>',
hits: '<%= l('Hit Enter, then Ctrl+C to copy all the download links') %>',
mailTo: '<%= l('Send all links by email') %>',
noLimit: '<%= l('No expiration delay') %>',
sending: '<%= l('Sending part XX1 of XX2') %>',
};
% end
%= javascript '/js/sjcl.js'