Move download-specific parts to it's own file

Functions used by downloads component for
This commit is contained in:
rottencandy 2019-06-10 17:16:50 +05:30
parent b6e1517c19
commit 05addcf859
3 changed files with 147 additions and 195 deletions

View File

@ -1,5 +1,53 @@
var m = require('mithril');
var rs = require('rswebui');
let m = require('mithril');
let rs = require('rswebui');
// These constants are the onces listed in retroshare/rsfiles.h. I would like to
// make them "members" of Downloads but I dont know how to do this.
const RS_FILE_CTRL_PAUSE = 0x00000100;
const RS_FILE_CTRL_START = 0x00000200;
const RS_FILE_CTRL_FORCE_CHECK = 0x00000400;
const FT_STATE_FAILED = 0x0000;
const FT_STATE_OKAY = 0x0001;
const FT_STATE_WAITING = 0x0002;
const FT_STATE_DOWNLOADING = 0x0003;
const FT_STATE_COMPLETE = 0x0004;
const FT_STATE_QUEUED = 0x0005;
const FT_STATE_PAUSED = 0x0006;
const FT_STATE_CHECKING_HASH = 0x0007;
let Downloads = {
statusMap: new Map(),
hashes: [],
loadHashes() {
rs.rsJsonApiRequest(
'/rsFiles/FileDownloads',
{},
function(d) {
Downloads.hashes = d.hashs;
},
);
},
loadStatus() {
Downloads.loadHashes();
if(Downloads.hashes.length !== Downloads.statusMap.size)
Downloads.statusMap.clear();
for (let hash of Downloads.hashes) {
let json_params = {
hash,
hintflags: 16,//RS_FILE_HINTS_DOWNLOAD
};
rs.rsJsonApiRequest(
'/rsFiles/FileDetails',
json_params,
function(fileStat) {
Downloads.statusMap.set(hash, fileStat.info);
},
);
}
},
};
function makeFriendlyUnit(bytes) {
if (bytes < 1e3) return bytes.toFixed(1) + 'B';
@ -9,106 +57,101 @@ function makeFriendlyUnit(bytes) {
return (bytes / 1e12).toFixed(1) + 'TB';
}
function progressBar(file) {
return m(
'div[style=border:5px solid lime;' +
'border-radius:3mm;' +
'padding:2mm;' +
'height:5mm' +
']',
[m('div[style=' +
'background-color:lime;' +
'height:100%;' +
'width:' + (file.transfered / file.size * 100) + '%' +
']',
'')]);
function progressBar(rate) {
return m('.progressbar[]',
{style: {content: rate+'%'}},
m('span.progress-status',
{style: {width: rate+'%'}},
rate + '%')
);
};
function cntrlBtn(file, act) {
return m(
'div.btn', {
onclick: function() {
console.log(
'Control button pushed. Action on file ' + file.hash +
' is ' + act);
function fileAction(hash, action) {
let action_header = '';
let json_params = {hash, flags: 0};
switch(action) {
case 'cancel':
req_action = '/rsFiles/FileCancel';
break;
rs.Downloads.control(file.hash, act);
}
},
act);
}
case 'pause':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_PAUSE;
break;
module.exports = {
oninit:
rs.Downloads.load, // means we re-load the list everytime we render
onload:
rs.Downloads.load, // means we re-load the list everytime we render
case 'resume':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_START;
break;
case 'force_check':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_FORCE_CHECK;
break;
default:
console.log('Unknown action in Downloads.control()');
return;
};
rs.rsJsonApiRequest(action_header, json_params, ()=>{});//false
};
function actionButton(file, action) {
return m('button',
{onclick: function() {
fileAction(file.hash, action);
}},
action);
};
component = {
// means we re-load the list everytime we render
oninit: Downloads.loadStatus,
onload: Downloads.loadStatus,
view: function() {
var filestreamer_url = '/fstream/';
var paths =
rs.Downloads
.list; // after that, paths is a list of FileInfo structures
if (paths === undefined) {
return m('div', 'Downloads ... please wait ...');
}
console.log('List size=' + rs.Downloads.list.length + '\n');
console.log('List [0]=' + rs.Downloads.list[0] + '\n');
return m('div', [
m('h2', 'Downloads (' + paths.length + ')'),
m('div.btn2', {
onclick: function() {
m.route('/downloads/add');
},
},
'add retrohare downloads'),
return m('div.frame', [
m('h3', 'Downloads (' + Downloads.statusMap.size + ')'),
m('hr'),
m('table',
[
m('tr',
[
m('th', 'name'), m('th', 'size'), m('th', 'progress'),
m('th', 'transfer rate'), m('th', 'status'),
m('th', 'progress'), m('th', 'action')
m('th', 'Name'),
m('th', 'Size'),
m('th', 'Progress'),
m('th', 'Transfer rate'),
m('th', 'Status'),
m('th', 'Progress'),
m('th', 'Action'),
]),
paths.map(function(fileInfo) {
var ctrlBtn = m('div', '');
var progress = fileInfo.transfered / fileInfo.size * 100;
Array.from(Downloads.statusMap, function(fileStatus) {
let info = fileStatus[1];
let progress = info.transfered / info.size * 100;
// Using hash of file as vnode key
return m('tr', {key: fileStatus[0]},
[
m('td', info.name),
m('td', makeFriendlyUnit(info.size)),
m('td', progress.toPrecision(3) + '%'),
m('td', makeFriendlyUnit(info.tfRate * 1024) + '/s'),
m('td', info.download_status),
m('td', progressBar(progress)),
m('td',
[
actionButton(info,
info.downloadStatus === FT_STATE_PAUSED?
'resume' : 'pause'),
console.log(
'dl status=' + fileInfo.downloadStatus +
' paused_state=' + rs.FT_STATE_PAUSED);
return m('tr', [
m('td', [m('a.filelink', {
target: 'blank',
href: filestreamer_url + fileInfo.hash + '/' +
encodeURIComponent(fileInfo.fname)
},
fileInfo.fname)]),
m('td', makeFriendlyUnit(fileInfo.size)),
m('td', progress.toPrecision(3) + '%'),
m('td',
makeFriendlyUnit(fileInfo.tfRate * 1024) + '/s'),
m('td', fileInfo.download_status),
m('td', progressBar(fileInfo)),
m('td',
[
cntrlBtn(
fileInfo,
fileInfo.downloadStatus ===
rs.FT_STATE_PAUSED ?
'resume' :
'pause'),
cntrlBtn(fileInfo, 'cancel')
])
])
actionButton(info, 'cancel'),
]
),
]);
})
])
]);
},
};
module.exports = {
component,
};

View File

@ -3,7 +3,7 @@
var m = require('mithril');
const API_URL = 'http://127.0.0.1:9092';
var loginKey = {
let loginKey = {
username: '',
passwd: '',
isVerified: false,
@ -40,9 +40,6 @@ function rsJsonApiRequest(path, data, callback, async = true, headers = {}) {
data: data,
})
.then((result) => {
// console.log("request success:", path, "callback", result.status,
// result.body.replace(/\s+/g, " ").substr(0,
// 60).replace(/\r?\n|\r/g," ") );
if (typeof(callback) === 'function') {
if (result.status === 200) {
callback(result.body, true);
@ -58,96 +55,6 @@ function rsJsonApiRequest(path, data, callback, async = true, headers = {}) {
});
}
// These constants are the onces listed in retroshare/rsfiles.h. I would like to
// make them "members" of Downloads but I dont know how to do this.
var RS_FILE_CTRL_PAUSE = 0x00000100;
var RS_FILE_CTRL_START = 0x00000200;
var RS_FILE_CTRL_FORCE_CHECK = 0x00000400;
var FT_STATE_FAILED = 0x0000;
var FT_STATE_OKAY = 0x0001;
var FT_STATE_WAITING = 0x0002;
var FT_STATE_DOWNLOADING = 0x0003;
var FT_STATE_COMPLETE = 0x0004;
var FT_STATE_QUEUED = 0x0005;
var FT_STATE_PAUSED = 0x0006;
var FT_STATE_CHECKING_HASH = 0x0007;
var Downloads = {
list: [],
// Load function for files. Populates the "list" array with Objects of type
// corresponding to rsfiles.h:FileInfo
load: function() {
function addDLInfo(p) {
var jsonData = p;
if (jsonData.retval === 'false')
console.warning('Cannot retrieve info!!');
console.log(
'adding ' + jsonData.info.hash +
': size=' + jsonData.info.size +
': progress=' + jsonData.info.avail + '\n');
Downloads.list.push(jsonData.info);
}
function requestDLData(hash) {
var json_params = {
hash: hash,
hintflags: 16 // = RS_FILE_HINTS_DOWNLOAD
};
console.log('requesting DL data for hash: ' + hash);
rsJsonApiRequest(
'/rsFiles/FileDetails', json_params, addDLInfo, false);
}
function handleHashesList(p) {
var jsonData = p;
// now for each hash, request the current progress
jsonData.hashs.forEach(requestDLData);
}
Downloads.list = [];
console.log('requesting downloads...');
rsJsonApiRequest('/rsFiles/FileDownloads', {}, handleHashesList, false);
},
// Control function for files. Hash is the file hash and control_action is
// the action to perform to be chosen as { "cancel", "pause", "resume" }
control: function(hash, control_action) {
var req_action = ''; // action requested to jsonapi
var json_params = {hash: hash, flags: 0}; // params for that action
switch (control_action) {
case 'cancel':
req_action = '/rsFiles/FileCancel';
break;
case 'pause':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_PAUSE;
break;
case 'resume':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_START;
break;
case 'force_check':
req_action = '/rsFiles/FileControl';
json_params.flags = RS_FILE_CTRL_FORCE_CHECK;
break;
default:
console.log('Unknown action in Downloads.control()');
return;
};
rsJsonApiRequest(req_action, json_params, null, false);
},
};
module.exports = {
requestCertificate: function(callback) {
@ -160,20 +67,6 @@ module.exports = {
},
rsJsonApiRequest,
Downloads,
setKeys,
RS_FILE_CTRL_PAUSE,
RS_FILE_CTRL_START,
RS_FILE_CTRL_FORCE_CHECK,
FT_STATE_FAILED,
FT_STATE_OKAY,
FT_STATE_WAITING,
FT_STATE_DOWNLOADING,
FT_STATE_COMPLETE,
FT_STATE_QUEUED,
FT_STATE_PAUSED,
FT_STATE_CHECKING_HASH,
};

View File

@ -37,6 +37,22 @@ button {
color: red;
}
.progressbar {
width: 100%;
background-color: grey;
position: relative;
}.progressbar:before{
position: absolute;
text-align: center;
left: 0;
right: 0;
}.progress-status {
display: inline-block;
height: 100%;
background-color: #3ba4d7;
text-align: center;
}
.tab-container {
padding: 1em 1em;
background-color: #333;