Files
flood/server/models/Torrent.js
2016-03-26 23:23:31 -07:00

246 lines
6.5 KiB
JavaScript

'use strict';
let _ = require('lodash');
let regEx = require('../../shared/util/regEx');
let stringUtil = require('../../shared/util/stringUtil');
const CALCULATED_DATA = [
'eta',
'percentComplete',
'status',
'trackers',
'totalPeers',
'totalSeeds'
];
const REQUESTED_DATA = [
// Torrent List data
'hash',
'added',
'bytesDone',
'downloadRate',
'downloadTotal',
'eta',
'name',
'percentComplete',
'ratio',
'sizeBytes',
'status',
'totalPeers',
'totalSeeds',
'uploadTotal',
'uploadRate',
'priority',
'trackers',
// Torrent Details data
'creationDate',
'freeDiskSpace',
'connectedPeers',
'connectedSeeds',
'message',
'basePath',
'ignoreScheduler',
'comment',
'isPrivate',
'directory',
'filename',
'isMultiFile'
];
class Torrent {
constructor(clientData, opts) {
if (!clientData) {
return;
}
opts = opts || {};
this._lastUpdated = opts.currentTime || Date.now();
this._torrentData = this.getCalculatedClientData(clientData, opts);
}
get data() {
// TODO: Only return the properties that are different than the last time
// get was called. Perhaps identify the last time it was called by ID so
// different consumers can use it. And/or allow users to get everything.
return Object.assign({}, this._torrentData);
}
get status() {
return this._torrentData.status || [];
}
get trackers() {
return this._torrentData.trackers || [];
}
getCalculatedClientData(clientData, opts) {
let keysToProcess = CALCULATED_DATA;
let requestedData = REQUESTED_DATA;
let torrentData = {};
if (opts.requestedData && _.isArray(opts.requestedData)) {
keysToProcess = opts.requestedData;
} else if (opts.requestedData) {
console.warn('Torrent: requestedData mut be an array, using defaults.');
}
keysToProcess = keysToProcess.concat(requestedData);
keysToProcess.forEach((key) => {
let getCalculatedFnName = `getCalculated${stringUtil.capitalize(key)}`;
if (typeof this[getCalculatedFnName] === 'function') {
torrentData[key] = this[getCalculatedFnName](clientData);
} else {
torrentData[key] = clientData[key];
}
});
return torrentData;
}
getPeerCount(string) {
var markerPosition = string.indexOf('@!@');
return string.substr(0, markerPosition);
}
getCalculatedEta(clientData) {
let rate = clientData.downloadRate;
let completed = clientData.bytesDone;
let total = clientData.sizeBytes;
if (rate > 0) {
let cumSeconds = (total - completed) / rate;
let years = Math.floor(cumSeconds / 31536000);
let weeks = Math.floor((cumSeconds % 31536000) / 604800);
let days = Math.floor(((cumSeconds % 31536000) % 604800) / 86400);
let hours = Math.floor((((cumSeconds % 31536000) % 604800) % 86400) / 3600);
let minutes = Math.floor(((((cumSeconds % 31536000) % 604800) % 86400) % 3600) / 60);
let seconds = Math.floor(cumSeconds - (minutes * 60));
let timeRemaining = {};
if (years > 0) {
timeRemaining = {years, weeks, cumSeconds};
} else if (weeks > 0) {
timeRemaining = {weeks, days, cumSeconds};
} else if (days > 0) {
timeRemaining = {days, hours, cumSeconds};
} else if (hours > 0) {
timeRemaining = {hours, minutes, cumSeconds};
} else if (minutes > 0) {
timeRemaining = {minutes, seconds, cumSeconds};
} else {
timeRemaining = {cumSeconds};
}
return timeRemaining;
} else {
return 'Infinity';
}
}
getCalculatedPercentComplete(clientData) {
let percentComplete = clientData.bytesDone / clientData.sizeBytes * 100;
if (percentComplete > 0 && percentComplete < 10) {
return percentComplete.toFixed(2);
} else if (percentComplete > 10 && percentComplete < 100) {
return percentComplete.toFixed(1);
} else {
return percentComplete;
}
}
getCalculatedStatus(clientData) {
let isHashChecking = clientData.isHashChecking;
let isComplete = clientData.isComplete;
let isOpen = clientData.isOpen;
let uploadRate = clientData.uploadRate;
let downloadRate = clientData.downloadRate;
let state = clientData.state;
let message = clientData.message;
let torrentStatus = [];
if (isHashChecking === '1') {
torrentStatus.push('ch'); // checking
} else if (isComplete === '1' && isOpen === '1' && state === '1') {
torrentStatus.push('sd'); // seeding
} else if (isComplete === '1' && isOpen === '1' && state === '0') {
torrentStatus.push('p'); // paused
} else if (isComplete === '1' && isOpen === '0') {
torrentStatus.push('s'); // stopped
torrentStatus.push('c'); // complete
} else if (isComplete === '0' && isOpen === '1' && state === '1') {
torrentStatus.push('d'); // downloading
} else if (isComplete === '0' && isOpen === '1' && state === '0') {
torrentStatus.push('p'); // paused
} else if (isComplete === '0' && isOpen === '0') {
torrentStatus.push('s'); // stopped
}
if (message.length) {
torrentStatus.push('e'); // error
}
if (uploadRate === '0' && downloadRate === '0') {
torrentStatus.push('i');
} else {
torrentStatus.push('a');
}
return torrentStatus;
}
getCalculatedTotalPeers(clientData) {
return this.getPeerCount(clientData.totalPeers);
}
getCalculatedTotalSeeds(clientData) {
return this.getPeerCount(clientData.totalSeeds);
}
getCalculatedTrackers(clientData) {
let trackers = clientData.trackers.split('@!@');
let trackerDomains = [];
trackers.forEach((tracker) => {
let domain = regEx.domainName.exec(tracker);
if (domain && domain[1]) {
domain = domain[1];
let domainSubsets = domain.split('.');
let desiredSubsets = 2;
let subsetMinLength = 3;
if (domainSubsets.length > desiredSubsets) {
let lastDesiredSubset = domainSubsets[domainSubsets.length - desiredSubsets];
if (lastDesiredSubset.length <= 3) {
desiredSubsets++;
}
}
domain = domainSubsets.slice(desiredSubsets * -1).join('.');
trackerDomains.push(domain);
}
});
return trackerDomains;
}
updateData(clientData, opts) {
// TODO somehow communicate that only some props were updated
this._lastUpdated = opts.currentTime || Date.now();
this._torrentData = this.getCalculatedClientData(clientData, opts);
}
}
module.exports = Torrent;