MeshMessenger with file transfers.

Ylian Saint-Hilaire committed Dec 17, 2018 at 15:08 UTC 85acf14a259753578374520d685552e46caa5d22
2 files changed +45 -17
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.4-s",
3 + "version": "0.2.4-t",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/messenger.htm
+44 -16
@@ -8,6 +8,7 @@
8 <link type="text/css" href="styles/style.css" media="screen" rel="stylesheet" title="CSS" />
9 <link type="text/css" href="styles/messenger.css" media="screen" rel="stylesheet" title="CSS" />
10 <script type="text/javascript" src="scripts/common-0.0.1.js"></script>
11 + <script type="text/javascript" src="scripts/filesaver.1.1.20151003.js"></script>
12 </head>
13 <body style="font-family:Arial,Helvetica,sans-serif">
14 <div id="xtop" style="position:absolute;left:0;right:0;top:0;height:38px;background-color:#036;color:#c8c8c8;box-shadow:3px 3px 10px gray">
@@ -36,7 +37,7 @@
37 <div style="position:absolute;right:0;left:0;top:2.5px;text-align:center">Local</div>
38 <video id="localVideoCanvas" autoplay muted style="position:absolute;top:20px;left:0;width:100%;height:calc(100% - 30px);background-color:black"></video>
39 </div>
39 - <input id="uploadFileInput" type="file" style="display:none">
40 + <input id="uploadFileInput" type="file" multiple style="display:none">
41 <script type="text/javascript">
42 var userInputFocus = 0;
43 var args = parseUriArgs();
@@ -86,7 +87,7 @@
87 }
88
89 function onUserInputFocus(x) { userInputFocus = x; }
89 - function displayClear() { QH('xmsg', ''); }
90 + function displayClear() { QH('xmsg', ''); cancelAllFileTransfers(); fileUploads = [], fileDownloads = {}; }
91
92 // Display a control message
93 function displayControl(msg) {
@@ -301,32 +302,47 @@
302 chooser.click();
303 }
304
305 + // User selected one or more files to upload to remote user.
306 function fileSelect() {
307 if (state != 2) return;
308 var x = Q('uploadFileInput');
307 - if (x.files.length != 1) return;
308 - var reader = new FileReader();
309 - reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
310 - reader.xfile = x.files[0];
311 - reader.readAsBinaryString(x.files[0]);
309 + if (x.files.length > 10) {
310 + displayControl('Limit of 10 file uploads at the same time.');
311 + } else {
312 + for (var i = 0; i < x.files.length; i++) {
313 + if (x.files[i].size > 0) {
314 + var reader = new FileReader();
315 + reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
316 + reader.xfile = x.files[i];
317 + reader.readAsBinaryString(x.files[i]);
318 + }
319 + }
320 + }
321 }
322
323 + // User drag & droped one or more files to upload to remote user.
324 function fileDrop(e) {
325 haltEvent(e);
316 - if (state != 2) return;
317 - if (e.dataTransfer == null || e.dataTransfer.files.length != 1) return;
318 - var reader = new FileReader();
319 - reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
320 - reader.xfile = e.dataTransfer.files[0];
321 - reader.readAsBinaryString(e.dataTransfer.files[0]);
326 + if ((state != 2) || (e.dataTransfer == null)) return;
327 + if (e.dataTransfer.files.length > 10) {
328 + displayControl('Limit of 10 file uploads at the same time.');
329 + } else {
330 + for (var i = 0; i < e.dataTransfer.files.length; i++) {
331 + if (e.dataTransfer.files[i].size > 0) {
332 + var reader = new FileReader();
333 + reader.onload = function (e) { this.xfile.data = e.target.result; startFileUpload(this.xfile); };
334 + reader.xfile = e.dataTransfer.files[i];
335 + reader.readAsBinaryString(e.dataTransfer.files[i]);
336 + }
337 + }
338 + }
339 }
340
341 function startFileUpload(file) {
342 if (state != 2) return;
343 file.id = Math.random();
344 fileUploads.push(file);
328 - //console.log('XXX', file);
329 - QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
345 + QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="localBubble" style="width:240px;cursor:pointer" onclick="cancelFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
346 Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
347 send({ action: 'file', size: file.size, id: file.id, type: file.type, name: file.name });
348 if (currentFileUpload == null) continueFileUpload();
@@ -335,7 +351,7 @@
351 function startFileDownload(file) {
352 if (state != 2) return;
353 fileDownloads[file.id] = file;
338 - QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="remoteBubble" style="width:240px;cursor:pointer"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
354 + QA('xmsg', '<div style="clear:both"></div><div id="FILEUP-' + file.id + '" class="remoteBubble" style="width:240px;cursor:pointer" onclick="saveFileTransfer(\'' + file.id + '\')"><div id="FILEUP-ICON-' + file.id + '" class="fileicon" style="float:left;width:32px;height:32px"></div><div><div id="FILEUP-NAME-' + file.id + '" style="height:16px;overflow:hidden;white-space:nowrap;" title="' + file.name + '">' + file.name + '</div><div style="width:200px;background-color:lightgray;margin-left:32px;border-radius:3px;margin-top:3px;height:11px"><div id="FILEUP-PROGRESS-' + file.id + '" style="width:0px;background-color:green;border-radius:3px;height:11px">&nbsp;</div></div></div></div>');
355 Q('xmsg').scrollTop = Q('xmsg').scrollHeight;
356 }
357
@@ -352,6 +368,18 @@
368 if (progressColor) { QS('FILEUP-PROGRESS-' + id)['background-color'] = progressColor; }
369 }
370
371 + // Convert a string into a blob
372 + data2blob = function (data) {
373 + var bytes = new Array(data.length);
374 + for (var i = 0; i < data.length; i++) bytes[i] = data.charCodeAt(i);
375 + return new Blob([new Uint8Array(bytes)]);
376 + };
377 +
378 + function saveFileTransfer(id) {
379 + var f = fileDownloads[id];
380 + if (f && f.done == 1) { saveAs(data2blob(f.data), f.name); }
381 + }
382 +
383 function cancelFileTransfer(id) {
384 if ((currentFileUpload != null) && (currentFileUpload.id == id)) { currentFileUpload = null; }
385 if ((currentFileDownload != null) && (currentFileDownload.id == id)) { currentFileDownload = null; }