From ae0b644d8d8046451024ca9709055f7a434009a2 Mon Sep 17 00:00:00 2001 From: John Furrow Date: Fri, 5 Feb 2016 22:35:30 -0800 Subject: [PATCH] Add Torrent class --- server/models/Torrent.js | 187 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 server/models/Torrent.js diff --git a/server/models/Torrent.js b/server/models/Torrent.js new file mode 100644 index 00000000..344bf31b --- /dev/null +++ b/server/models/Torrent.js @@ -0,0 +1,187 @@ +'use strict'; + +let _ = require('lodash'); + +let stringUtil = require('../../util/stringUtil'); + +const CALCULATED_DATA = [ + 'eta', + 'percentComplete', + 'status', + 'totalPeers', + 'totalSeeds' +]; + +const REQUESTED_DATA = [ + // Torrent List data + 'hash', + 'added', + 'bytesDone', + 'downloadRate', + 'downloadTotal', + 'eta', + 'name', + 'percentComplete', + 'ratio', + 'sizeBytes', + 'status', + 'totalPeers', + 'totalSeeds', + 'uploadTotal', + 'uploadRate', + + // Torrent Details data + 'creationDate', + 'freeDiskSpace', + 'connectedPeers', + 'connectedSeeds', + 'message', + 'basePath', + 'ignoreScheduler', + 'comment', + 'isPrivate', + 'directory', + 'filename' +]; + +class Torrent { + constructor(clientData, opts) { + if (!clientData) { + return; + } + + clientData = clientData || {}; + opts = opts || {}; + 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); + } + + 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) { + return (clientData.bytesDone / clientData.sizeBytes * 100).toFixed(2); + } + + 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('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); + } +} + +module.exports = Torrent;