aria2TaskService.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. (function () {
  2. 'use strict';
  3. angular.module('ariaNg').factory('aria2TaskService', ['$q', 'bittorrentPeeridService', 'ariaNgConstants', 'aria2Errors', 'aria2RpcService', 'ariaNgCommonService', 'ariaNgLocalizationService', 'ariaNgLogService', 'ariaNgSettingService', function ($q, bittorrentPeeridService, ariaNgConstants, aria2Errors, aria2RpcService, ariaNgCommonService, ariaNgLocalizationService, ariaNgLogService, ariaNgSettingService) {
  4. var getFileName = function (file) {
  5. if (!file) {
  6. ariaNgLogService.warn('[aria2TaskService.getFileName] file is null');
  7. return '';
  8. }
  9. var path = file.path;
  10. var needUrlDecode = false;
  11. if (!path && file.uris && file.uris.length > 0) {
  12. path = file.uris[0].uri;
  13. needUrlDecode = true;
  14. }
  15. var index = path.lastIndexOf('/');
  16. if (index <= 0 || index === path.length) {
  17. return path;
  18. }
  19. var fileNameAndQueryString = path.substring(index + 1);
  20. var queryStringStartPos = fileNameAndQueryString.indexOf('?');
  21. var fileName = fileNameAndQueryString;
  22. if (queryStringStartPos > 0) {
  23. fileName = fileNameAndQueryString.substring(0, queryStringStartPos);
  24. }
  25. if (needUrlDecode) {
  26. try {
  27. fileName = decodeURI(fileName);
  28. } catch (ex) {
  29. ariaNgLogService.warn('[aria2TaskService.getFileName] failed to url decode file name, original file name: ' + fileName, ex);
  30. }
  31. }
  32. return fileName;
  33. };
  34. var calculateDownloadRemainTime = function (remainBytes, downloadSpeed) {
  35. if (downloadSpeed === 0) {
  36. return 0;
  37. }
  38. return remainBytes / downloadSpeed;
  39. };
  40. var getTaskName = function (task) {
  41. var taskName = '';
  42. var success = true;
  43. if (task.bittorrent && task.bittorrent.info) {
  44. taskName = task.bittorrent.info.name;
  45. }
  46. if (!taskName && task.files && task.files.length > 0) {
  47. taskName = getFileName(task.files[0]);
  48. }
  49. if (!taskName) {
  50. taskName = ariaNgLocalizationService.getLocalizedText('Unknown');
  51. success = false;
  52. }
  53. return {
  54. name: taskName,
  55. success: success
  56. };
  57. };
  58. var getRelativePath = function (task, file) {
  59. var downloadPath = task.dir;
  60. var relativePath = file.path;
  61. if (downloadPath) {
  62. downloadPath = downloadPath.replace(/\\/g, ariaNgConstants.defaultPathSeparator);
  63. }
  64. if (relativePath) {
  65. relativePath = relativePath.replace(/\\/g, ariaNgConstants.defaultPathSeparator);
  66. }
  67. var trimStartPathSeparator = function () {
  68. if (relativePath.length > 1 && relativePath.charAt(0) === ariaNgConstants.defaultPathSeparator) {
  69. relativePath = relativePath.substr(1);
  70. }
  71. };
  72. var trimEndPathSeparator = function () {
  73. if (relativePath.length > 1 && relativePath.charAt(relativePath.length - 1) === ariaNgConstants.defaultPathSeparator) {
  74. relativePath = relativePath.substr(0, relativePath.length - 1);
  75. }
  76. };
  77. if (downloadPath && relativePath.indexOf(downloadPath) === 0) {
  78. relativePath = relativePath.substr(downloadPath.length);
  79. }
  80. trimStartPathSeparator();
  81. if (task.bittorrent && task.bittorrent.mode === 'multi' && task.bittorrent.info && task.bittorrent.info.name) {
  82. var bittorrentName = task.bittorrent.info.name;
  83. if (relativePath.indexOf(bittorrentName) === 0) {
  84. relativePath = relativePath.substr(bittorrentName.length);
  85. }
  86. }
  87. trimStartPathSeparator();
  88. if (file.fileName && ((relativePath.lastIndexOf(file.fileName) + file.fileName.length) === relativePath.length)) {
  89. relativePath = relativePath.substr(0, relativePath.length - file.fileName.length);
  90. }
  91. trimEndPathSeparator();
  92. return relativePath;
  93. };
  94. var getDirectoryNode = function (path, allDirectories, allDirectoryMap) {
  95. var node = allDirectoryMap[path];
  96. if (node) {
  97. return node;
  98. }
  99. var parentNode = null;
  100. var nodeName = path;
  101. if (path.length) {
  102. var parentPath = '';
  103. var lastSeparatorIndex = path.lastIndexOf(ariaNgConstants.defaultPathSeparator);
  104. if (lastSeparatorIndex > 0) {
  105. parentPath = path.substring(0, lastSeparatorIndex);
  106. nodeName = path.substring(lastSeparatorIndex + 1);
  107. }
  108. parentNode = getDirectoryNode(parentPath, allDirectories, allDirectoryMap);
  109. }
  110. node = {
  111. isDir: true,
  112. nodePath: path,
  113. nodeName: nodeName,
  114. relativePath: (parentNode && parentNode.nodePath) || '',
  115. level: (parentNode && parentNode.level + 1) || 0,
  116. length: 0,
  117. selected: true,
  118. partialSelected: false,
  119. files: [],
  120. subDirs: []
  121. };
  122. allDirectories.push(node);
  123. allDirectoryMap[path] = node;
  124. if (parentNode) {
  125. parentNode.subDirs.push(node);
  126. }
  127. return node;
  128. };
  129. var pushFileToDirectoryNode = function (file, allDirectories, allDirectoryMap) {
  130. if (!file || !allDirectories || !allDirectoryMap) {
  131. return;
  132. }
  133. var nodePath = file.relativePath || '';
  134. var directoryNode = getDirectoryNode(nodePath, allDirectories, allDirectoryMap);
  135. directoryNode.files.push(file);
  136. return directoryNode;
  137. };
  138. var fillAllNodes = function (node, allDirectoryMap, allNodes) {
  139. if (!node) {
  140. return;
  141. }
  142. var allSubNodesLength = 0;
  143. var selectedSubNodesCount = 0;
  144. var partitalSelectedSubNodesCount = 0;
  145. if (node.subDirs && node.subDirs.length) {
  146. for (var i = 0; i < node.subDirs.length; i++) {
  147. var dirNode = node.subDirs[i];
  148. allNodes.push(dirNode);
  149. fillAllNodes(dirNode, allDirectoryMap, allNodes);
  150. allSubNodesLength += dirNode.length;
  151. selectedSubNodesCount += (dirNode.selected ? 1 : 0);
  152. partitalSelectedSubNodesCount += (dirNode.partialSelected ? 1 : 0);
  153. }
  154. }
  155. if (node.files && node.files.length) {
  156. for (var i = 0; i < node.files.length; i++) {
  157. var fileNode = node.files[i];
  158. allNodes.push(fileNode);
  159. allSubNodesLength += fileNode.length;
  160. selectedSubNodesCount += (fileNode.selected ? 1 : 0);
  161. }
  162. }
  163. node.length = allSubNodesLength;
  164. node.selected = (selectedSubNodesCount > 0 && selectedSubNodesCount === (node.subDirs.length + node.files.length));
  165. node.partialSelected = ((selectedSubNodesCount > 0 && selectedSubNodesCount < (node.subDirs.length + node.files.length)) || partitalSelectedSubNodesCount > 0);
  166. };
  167. var getTaskErrorDescription = function (task) {
  168. if (!task.errorCode) {
  169. return '';
  170. }
  171. if (!aria2Errors[task.errorCode] || !aria2Errors[task.errorCode].descriptionKey) {
  172. return '';
  173. }
  174. if (aria2Errors[task.errorCode].hide) {
  175. return '';
  176. }
  177. return aria2Errors[task.errorCode].descriptionKey;
  178. };
  179. var getPieceStatus = function (bitField, pieceCount) {
  180. var pieces = [];
  181. for (var i = 0; i < pieceCount; i++) {
  182. pieces.push(false);
  183. }
  184. if (!bitField) {
  185. return pieces;
  186. }
  187. var pieceIndex = 0;
  188. for (var i = 0; i < bitField.length; i++) {
  189. var bitSet = parseInt(bitField[i], 16);
  190. for (var j = 1; j <= 4; j++) {
  191. var bit = (1 << (4 - j));
  192. var isCompleted = (bitSet & bit) === bit;
  193. pieces[pieceIndex++] = isCompleted;
  194. if (pieceIndex >= pieceCount) {
  195. return pieces;
  196. }
  197. }
  198. }
  199. return pieces;
  200. };
  201. var getCombinedPieces = function (bitField, pieceCount) {
  202. var pieces = getPieceStatus(bitField, pieceCount);
  203. var combinedPieces = [];
  204. for (var i = 0; i < pieces.length; i++) {
  205. var isCompleted = pieces[i];
  206. if (combinedPieces.length > 0 && combinedPieces[combinedPieces.length - 1].isCompleted === isCompleted) {
  207. combinedPieces[combinedPieces.length - 1].count++;
  208. } else {
  209. combinedPieces.push({
  210. isCompleted: isCompleted,
  211. count: 1
  212. });
  213. }
  214. }
  215. return combinedPieces;
  216. };
  217. var processDownloadTask = function (task, addVirtualFileNode) {
  218. if (!task) {
  219. ariaNgLogService.warn('[aria2TaskService.processDownloadTask] task is null');
  220. return task;
  221. }
  222. addVirtualFileNode = addVirtualFileNode && task.bittorrent && task.bittorrent.mode === 'multi';
  223. var pieceStatus = getPieceStatus(task.bitfield, task.numPieces);
  224. task.totalLength = parseInt(task.totalLength);
  225. task.completedLength = parseInt(task.completedLength);
  226. task.completePercent = (task.totalLength > 0 ? task.completedLength / task.totalLength * 100 : 0);
  227. task.remainLength = task.totalLength - task.completedLength;
  228. task.remainPercent = 100 - task.completePercent;
  229. task.uploadLength = (task.uploadLength ? parseInt(task.uploadLength) : 0);
  230. task.shareRatio = (task.completedLength > 0 ? task.uploadLength / task.completedLength : 0);
  231. task.uploadSpeed = parseInt(task.uploadSpeed);
  232. task.downloadSpeed = parseInt(task.downloadSpeed);
  233. task.numPieces = parseInt(task.numPieces);
  234. task.completedPieces = ariaNgCommonService.countArray(pieceStatus, true);
  235. task.pieceLength = parseInt(task.pieceLength);
  236. task.idle = task.downloadSpeed === 0;
  237. task.remainTime = calculateDownloadRemainTime(task.remainLength, task.downloadSpeed);
  238. task.seeder = (task.seeder === true || task.seeder === 'true');
  239. if (task.verifiedLength && task.totalLength) {
  240. task.verifiedPercent = parseInt(task.verifiedLength / task.totalLength * 100);
  241. } else {
  242. task.verifiedPercent = undefined;
  243. }
  244. var taskNameResult = getTaskName(task);
  245. task.taskName = taskNameResult.name;
  246. task.hasTaskName = taskNameResult.success;
  247. task.errorDescription = getTaskErrorDescription(task);
  248. if (task.files) {
  249. var selectedFileCount = 0;
  250. var allDirectories = [];
  251. var allDirectoryMap = {};
  252. for (var i = 0; i < task.files.length; i++) {
  253. var file = task.files[i];
  254. file.index = parseInt(file.index);
  255. file.fileName = getFileName(file);
  256. file.length = parseInt(file.length);
  257. file.selected = (file.selected === true || file.selected === 'true');
  258. file.completedLength = parseInt(file.completedLength);
  259. file.completePercent = (file.length > 0 ? file.completedLength / file.length * 100 : 0);
  260. if (addVirtualFileNode) {
  261. file.relativePath = getRelativePath(task, file);
  262. var dirNode = pushFileToDirectoryNode(file, allDirectories, allDirectoryMap);
  263. file.level = dirNode.level + 1;
  264. }
  265. selectedFileCount += file.selected ? 1 : 0;
  266. }
  267. if (addVirtualFileNode && allDirectories.length > 1) {
  268. var allNodes = [];
  269. var rootNode = allDirectoryMap[''];
  270. fillAllNodes(rootNode, allDirectoryMap, allNodes);
  271. task.files = allNodes;
  272. task.multiDir = true;
  273. }
  274. task.selectedFileCount = selectedFileCount;
  275. }
  276. if (task.files && task.files.length === 1 && task.files[0].uris && task.files[0].uris[0]) {
  277. var isSingleUrlTask = true;
  278. var firstUri = task.files[0].uris[0].uri;
  279. for (var i = 0; i < task.files[0].uris.length; i++) {
  280. var uri = task.files[0].uris[i].uri;
  281. if (uri !== firstUri) {
  282. isSingleUrlTask = false;
  283. break;
  284. }
  285. }
  286. if (isSingleUrlTask) {
  287. task.singleUrl = firstUri;
  288. }
  289. }
  290. ariaNgLogService.debug('[aria2TaskService.processDownloadTask] process success', task);
  291. return task;
  292. };
  293. var processBtPeers = function (peers, task, includeLocalPeer) {
  294. if (!peers) {
  295. ariaNgLogService.warn('[aria2TaskService.processBtPeers] peers is null');
  296. return peers;
  297. }
  298. var localTaskCompletedPieces = getPieceStatus(task.bitfield, task.numPieces);
  299. var localTaskCompletedPieceCount = ariaNgCommonService.countArray(localTaskCompletedPieces, true);
  300. var localTaskCompletedPercent = task.completePercent;
  301. for (var i = 0; i < peers.length; i++) {
  302. var peer = peers[i];
  303. var upstreamToSpeed = parseInt(peer.uploadSpeed);
  304. var downstreamFromSpeed = parseInt(peer.downloadSpeed);
  305. var completedPieces = getPieceStatus(peer.bitfield, task.numPieces);
  306. var completedPieceCount = ariaNgCommonService.countArray(completedPieces, true);
  307. peer.name = peer.ip + ':' + peer.port;
  308. peer.completePercent = completedPieceCount / task.numPieces * 100;
  309. peer.downloadSpeed = upstreamToSpeed;
  310. peer.uploadSpeed = downstreamFromSpeed;
  311. peer.seeder = (peer.seeder === true || peer.seeder === 'true');
  312. if (completedPieceCount === localTaskCompletedPieceCount && peer.completePercent !== localTaskCompletedPercent) {
  313. peer.completePercent = localTaskCompletedPercent;
  314. }
  315. if (peer.peerId) {
  316. var peerId = ariaNgCommonService.decodePercentEncodedString(peer.peerId);
  317. var clientInfo = (peerId ? bittorrentPeeridService.parseClient(peerId) : null);
  318. if (clientInfo && clientInfo.client !== 'unknown') {
  319. var client = {
  320. name: (clientInfo.client ? clientInfo.client.trim() : ''),
  321. version: (clientInfo.version ? clientInfo.version.trim() : '')
  322. };
  323. client.info = client.name + (client.version ? ' ' + client.version : '');
  324. peer.client = client;
  325. }
  326. }
  327. }
  328. if (includeLocalPeer) {
  329. peers.push(createLocalPeerFromTask(task));
  330. }
  331. return peers;
  332. };
  333. var createTaskEventCallback = function (getTaskStatusFunc, callback, type) {
  334. return function (event) {
  335. var context = {
  336. type: type,
  337. task: null
  338. };
  339. if (event && event.gid) {
  340. getTaskStatusFunc(event.gid, function (response) {
  341. context.task = (response.success ? response.data : null);
  342. callback(context);
  343. }, true);
  344. } else {
  345. callback(context);
  346. }
  347. };
  348. };
  349. var createLocalPeerFromTask = function (task) {
  350. return {
  351. local: true,
  352. bitfield: task.bitfield,
  353. completePercent: task.completePercent,
  354. downloadSpeed: task.downloadSpeed,
  355. name: '(local)',
  356. seeder: task.seeder,
  357. uploadSpeed: task.uploadSpeed
  358. };
  359. };
  360. return {
  361. getTaskList: function (type, full, callback, silent) {
  362. var invokeMethod = null;
  363. if (type === 'downloading') {
  364. invokeMethod = aria2RpcService.tellActive;
  365. } else if (type === 'waiting') {
  366. invokeMethod = aria2RpcService.tellWaiting;
  367. } else if (type === 'stopped') {
  368. invokeMethod = aria2RpcService.tellStopped;
  369. } else {
  370. return;
  371. }
  372. return invokeMethod({
  373. requestWholeInfo: full,
  374. requestParams: full ? aria2RpcService.getFullTaskParams() : aria2RpcService.getBasicTaskParams(),
  375. silent: !!silent,
  376. callback: function (response) {
  377. if (!callback) {
  378. ariaNgLogService.warn('[aria2TaskService.getTaskList] callback is null');
  379. return;
  380. }
  381. callback(response);
  382. }
  383. });
  384. },
  385. getTaskStatus: function (gid, callback, silent, addVirtualFileNode) {
  386. return aria2RpcService.tellStatus({
  387. gid: gid,
  388. silent: !!silent,
  389. callback: function (response) {
  390. if (!callback) {
  391. ariaNgLogService.warn('[aria2TaskService.getTaskStatus] callback is null');
  392. return;
  393. }
  394. if (response.success) {
  395. processDownloadTask(response.data, addVirtualFileNode);
  396. }
  397. callback(response);
  398. }
  399. });
  400. },
  401. getTaskOptions: function (gid, callback, silent) {
  402. return aria2RpcService.getOption({
  403. gid: gid,
  404. silent: !!silent,
  405. callback: callback
  406. });
  407. },
  408. setTaskOption: function (gid, key, value, callback, silent) {
  409. var data = {};
  410. data[key] = value;
  411. return aria2RpcService.changeOption({
  412. gid: gid,
  413. options: data,
  414. silent: !!silent,
  415. callback: callback
  416. });
  417. },
  418. selectTaskFile: function (gid, selectedFileIndexArr, callback, silent) {
  419. var selectedFileIndex = '';
  420. for (var i = 0; i < selectedFileIndexArr.length; i++) {
  421. if (selectedFileIndex.length > 0) {
  422. selectedFileIndex += ',';
  423. }
  424. selectedFileIndex += selectedFileIndexArr[i];
  425. }
  426. return this.setTaskOption(gid, 'select-file', selectedFileIndex, callback, silent);
  427. },
  428. getBtTaskPeers: function (task, callback, silent, includeLocalPeer) {
  429. return aria2RpcService.getPeers({
  430. gid: task.gid,
  431. silent: !!silent,
  432. callback: function (response) {
  433. if (!callback) {
  434. ariaNgLogService.warn('[aria2TaskService.getBtTaskPeers] callback is null');
  435. return;
  436. }
  437. if (response.success) {
  438. processBtPeers(response.data, task, includeLocalPeer);
  439. }
  440. callback(response);
  441. }
  442. });
  443. },
  444. getTaskStatusAndBtPeers: function (gid, callback, silent, requirePeers, includeLocalPeer, addVirtualFileNode) {
  445. var methods = [
  446. aria2RpcService.tellStatus({ gid: gid }, true)
  447. ];
  448. if (requirePeers) {
  449. methods.push(aria2RpcService.getPeers({ gid: gid }, true));
  450. }
  451. return aria2RpcService.multicall({
  452. methods: methods,
  453. silent: !!silent,
  454. callback: function (response) {
  455. if (!callback) {
  456. ariaNgLogService.warn('[aria2TaskService.getTaskStatusAndBtPeers] callback is null');
  457. return;
  458. }
  459. response.task = {};
  460. if (response.success && response.data.length > 0) {
  461. response.task = response.data[0][0];
  462. processDownloadTask(response.task, addVirtualFileNode);
  463. }
  464. if (response.success && response.task.bittorrent && response.data.length > 1) {
  465. response.peers = response.data[1][0];
  466. processBtPeers(response.peers, response.task, includeLocalPeer);
  467. }
  468. callback(response);
  469. }
  470. });
  471. },
  472. newUriTask: function (task, pauseOnAdded, callback, silent) {
  473. return aria2RpcService.addUri({
  474. task: task,
  475. pauseOnAdded: !!pauseOnAdded,
  476. silent: !!silent,
  477. callback: callback
  478. });
  479. },
  480. newUriTasks: function (tasks, pauseOnAdded, callback, silent) {
  481. return aria2RpcService.addUriMulti({
  482. tasks: tasks,
  483. pauseOnAdded: !!pauseOnAdded,
  484. silent: !!silent,
  485. callback: callback
  486. });
  487. },
  488. newTorrentTask: function (task, pauseOnAdded, callback, silent) {
  489. return aria2RpcService.addTorrent({
  490. task: task,
  491. pauseOnAdded: !!pauseOnAdded,
  492. silent: !!silent,
  493. callback: callback
  494. });
  495. },
  496. newMetalinkTask: function (task, pauseOnAdded, callback, silent) {
  497. return aria2RpcService.addMetalink({
  498. task: task,
  499. pauseOnAdded: !!pauseOnAdded,
  500. silent: !!silent,
  501. callback: callback
  502. });
  503. },
  504. startTasks: function (gids, callback, silent) {
  505. return aria2RpcService.unpauseMulti({
  506. gids: gids,
  507. silent: !!silent,
  508. callback: callback
  509. });
  510. },
  511. pauseTasks: function (gids, callback, silent) {
  512. return aria2RpcService.forcePauseMulti({
  513. gids: gids,
  514. silent: !!silent,
  515. callback: callback
  516. });
  517. },
  518. retryTask: function (gid, callback, silent) {
  519. var deferred = $q.defer();
  520. var methods = [
  521. aria2RpcService.tellStatus({gid: gid}, true),
  522. aria2RpcService.getOption({gid: gid}, true)
  523. ];
  524. var task = null, options = null;
  525. aria2RpcService.multicall({
  526. methods: methods,
  527. silent: !!silent,
  528. callback: function (response) {
  529. if (!callback) {
  530. ariaNgLogService.warn('[aria2TaskService.retryTask] callback is null');
  531. return;
  532. }
  533. if (!response.success) {
  534. ariaNgLogService.warn('[aria2TaskService.retryTask] response is not success', response);
  535. deferred.reject(response);
  536. callback(response);
  537. return;
  538. }
  539. if (response.data.length > 0) {
  540. task = response.data[0][0];
  541. }
  542. if (response.data.length > 1) {
  543. options = response.data[1][0];
  544. }
  545. if (!task || !options || !task.files || task.files.length !== 1 || task.bittorrent) {
  546. if (!task) {
  547. ariaNgLogService.warn('[aria2TaskService.retryTask] task is null');
  548. }
  549. if (!options) {
  550. ariaNgLogService.warn('[aria2TaskService.retryTask] options is null');
  551. }
  552. if (!task.files) {
  553. ariaNgLogService.warn('[aria2TaskService.retryTask] task file is null');
  554. }
  555. if (task.files.length !== 1) {
  556. ariaNgLogService.warn('[aria2TaskService.retryTask] task file length is not equal 1');
  557. }
  558. if (task.bittorrent) {
  559. ariaNgLogService.warn('[aria2TaskService.retryTask] task is bittorrent');
  560. }
  561. deferred.reject(gid);
  562. callback({
  563. success: false
  564. });
  565. return;
  566. }
  567. var file = task.files[0];
  568. var urls = [];
  569. for (var i = 0; i < file.uris.length; i++) {
  570. var uriObj = file.uris[i];
  571. urls.push(uriObj.uri);
  572. }
  573. aria2RpcService.addUri({
  574. task: {
  575. urls: urls,
  576. options: options
  577. },
  578. pauseOnAdded: false,
  579. silent: !!silent,
  580. callback: function (response) {
  581. if (!response.success) {
  582. ariaNgLogService.warn('[aria2TaskService.retryTask] addUri response is not success', response);
  583. deferred.reject(response);
  584. callback(response);
  585. return;
  586. }
  587. if (ariaNgSettingService.getRemoveOldTaskAfterRetrying()) {
  588. aria2RpcService.removeDownloadResult({
  589. gid: gid,
  590. silent: true,
  591. callback: function (response) {
  592. if (!response.success) {
  593. ariaNgLogService.warn('[aria2TaskService.retryTask] removeDownloadResult response is not success', response);
  594. }
  595. }
  596. });
  597. }
  598. deferred.resolve(response);
  599. callback(response);
  600. }
  601. });
  602. }
  603. });
  604. return deferred.promise;
  605. },
  606. retryTasks: function (tasks, callback, silent) {
  607. if (!callback) {
  608. ariaNgLogService.warn('[aria2TaskService.retryTasks] callback is null');
  609. return;
  610. }
  611. var retryTaskFunc = this.retryTask;
  612. var deferred = $q.defer();
  613. var lastPromise = null;
  614. var successCount = 0;
  615. var failedCount = 0;
  616. var doRetryFunc = function (task, index) {
  617. ariaNgLogService.debug('[aria2TaskService.retryTasks] task#' + index + ', gid=' + task.gid + ' start retrying', task);
  618. return retryTaskFunc(task.gid, function (response) {
  619. ariaNgLogService.debug('[aria2TaskService.retryTasks] task#' + index + ', gid=' + task.gid + ', result=' + response.success, task);
  620. if (response.success) {
  621. successCount++;
  622. } else {
  623. failedCount++;
  624. }
  625. if ((successCount + failedCount) === tasks.length) {
  626. var finalResponse = {
  627. successCount: successCount,
  628. failedCount: failedCount,
  629. hasSuccess: successCount > 0,
  630. hasError: failedCount > 0
  631. };
  632. deferred.resolve(finalResponse);
  633. callback(finalResponse);
  634. }
  635. }, silent);
  636. };
  637. for (var i = 0; i < tasks.length; i++) {
  638. var task = tasks[i];
  639. var currentPromise = null;
  640. if (!lastPromise) {
  641. currentPromise = doRetryFunc(task, i);
  642. } else {
  643. currentPromise = (function (task, index) {
  644. return lastPromise.then(function onSuccess() {
  645. return doRetryFunc(task, index);
  646. }).catch(function onError() {
  647. return doRetryFunc(task, index);
  648. });
  649. })(task, i);
  650. }
  651. lastPromise = currentPromise;
  652. }
  653. return deferred.promise;
  654. },
  655. removeTasks: function (tasks, callback, silent) {
  656. var runningTaskGids = [];
  657. var stoppedTaskGids = [];
  658. for (var i = 0; i < tasks.length; i++) {
  659. if (tasks[i].status === 'complete' || tasks[i].status === 'error' || tasks[i].status === 'removed') {
  660. stoppedTaskGids.push(tasks[i].gid);
  661. } else {
  662. runningTaskGids.push(tasks[i].gid);
  663. }
  664. }
  665. var promises = [];
  666. var hasSuccess = false;
  667. var hasError = false;
  668. var results = [];
  669. if (runningTaskGids.length > 0) {
  670. promises.push(aria2RpcService.forceRemoveMulti({
  671. gids: runningTaskGids,
  672. silent: !!silent,
  673. callback: function (response) {
  674. ariaNgCommonService.pushArrayTo(results, response.results);
  675. hasSuccess = hasSuccess || response.hasSuccess;
  676. hasError = hasError || response.hasError;
  677. }
  678. }));
  679. }
  680. if (stoppedTaskGids.length > 0) {
  681. promises.push(aria2RpcService.removeDownloadResultMulti({
  682. gids: stoppedTaskGids,
  683. silent: !!silent,
  684. callback: function (response) {
  685. ariaNgCommonService.pushArrayTo(results, response.results);
  686. hasSuccess = hasSuccess || response.hasSuccess;
  687. hasError = hasError || response.hasError;
  688. }
  689. }));
  690. }
  691. return $q.all(promises).then(function onSuccess() {
  692. if (callback) {
  693. callback({
  694. hasSuccess: !!hasSuccess,
  695. hasError: !!hasError,
  696. results: results
  697. });
  698. }
  699. });
  700. },
  701. changeTaskPosition: function (gid, position, callback, silent) {
  702. return aria2RpcService.changePosition({
  703. gid: gid,
  704. pos: position,
  705. how: 'POS_SET',
  706. silent: !!silent,
  707. callback: callback
  708. });
  709. },
  710. clearStoppedTasks: function (callback, silent) {
  711. return aria2RpcService.purgeDownloadResult({
  712. silent: !!silent,
  713. callback: callback
  714. });
  715. },
  716. onConnectionSuccess: function (callback) {
  717. if (!callback) {
  718. ariaNgLogService.warn('[aria2TaskService.onConnectionSuccess] callback is null');
  719. return;
  720. }
  721. aria2RpcService.onConnectionSuccess({
  722. callback: callback
  723. });
  724. },
  725. onConnectionFailed: function (callback) {
  726. if (!callback) {
  727. ariaNgLogService.warn('[aria2TaskService.onConnectionFailed] callback is null');
  728. return;
  729. }
  730. aria2RpcService.onConnectionFailed({
  731. callback: callback
  732. });
  733. },
  734. onFirstSuccess: function (callback) {
  735. if (!callback) {
  736. ariaNgLogService.warn('[aria2TaskService.onFirstSuccess] callback is null');
  737. return;
  738. }
  739. aria2RpcService.onFirstSuccess({
  740. callback: callback
  741. });
  742. },
  743. onOperationSuccess: function (callback) {
  744. if (!callback) {
  745. ariaNgLogService.warn('[aria2TaskService.onOperationSuccess] callback is null');
  746. return;
  747. }
  748. aria2RpcService.onOperationSuccess({
  749. callback: callback
  750. });
  751. },
  752. onOperationError: function (callback) {
  753. if (!callback) {
  754. ariaNgLogService.warn('[aria2TaskService.onOperationError] callback is null');
  755. return;
  756. }
  757. aria2RpcService.onOperationError({
  758. callback: callback
  759. });
  760. },
  761. onTaskCompleted: function (callback) {
  762. if (!callback) {
  763. ariaNgLogService.warn('[aria2TaskService.onTaskCompleted] callback is null');
  764. return;
  765. }
  766. aria2RpcService.onDownloadComplete({
  767. callback: createTaskEventCallback(this.getTaskStatus, callback, 'completed')
  768. });
  769. },
  770. onBtTaskCompleted: function (callback) {
  771. if (!callback) {
  772. ariaNgLogService.warn('[aria2TaskService.onBtTaskCompleted] callback is null');
  773. return;
  774. }
  775. aria2RpcService.onBtDownloadComplete({
  776. callback: createTaskEventCallback(this.getTaskStatus, callback, 'btcompleted')
  777. });
  778. },
  779. onTaskErrorOccur: function (callback) {
  780. if (!callback) {
  781. ariaNgLogService.warn('[aria2TaskService.onTaskErrorOccur] callback is null');
  782. return;
  783. }
  784. aria2RpcService.onDownloadError({
  785. callback: createTaskEventCallback(this.getTaskStatus, callback, 'error')
  786. });
  787. },
  788. processDownloadTasks: function (tasks, addVirtualFileNode) {
  789. if (!angular.isArray(tasks)) {
  790. ariaNgLogService.warn('[aria2TaskService.processDownloadTasks] tasks is not array', tasks);
  791. return;
  792. }
  793. for (var i = 0; i < tasks.length; i++) {
  794. processDownloadTask(tasks[i], addVirtualFileNode);
  795. }
  796. },
  797. getPieceStatus: function (bitField, pieceCount) {
  798. return getPieceStatus(bitField, pieceCount);
  799. },
  800. getCombinedPieces: function (bitField, pieceCount) {
  801. return getCombinedPieces(bitField, pieceCount);
  802. },
  803. estimateHealthPercentFromPeers: function (task, peers) {
  804. if (!task || task.numPieces < 1 || peers.length < 1) {
  805. ariaNgLogService.warn('[aria2TaskService.estimateHealthPercentFromPeers] tasks is null or numPieces < 1 or peers < 1', task);
  806. return task.completePercent;
  807. }
  808. var totalPieces = [];
  809. var maxCompletedPieceCount = 0;
  810. var maxCompletedPercent = task.completePercent;
  811. for (var i = 0; i < task.numPieces; i++) {
  812. totalPieces.push(0);
  813. }
  814. for (var i = 0; i < peers.length; i++) {
  815. var peer = peers[i];
  816. var peerPieces = getPieceStatus(peer.bitfield, task.numPieces);
  817. var completedPieceCount = 0;
  818. for (var j = 0; j < peerPieces.length; j++) {
  819. var count = (peerPieces[j] ? 1 : 0);
  820. totalPieces[j] += count;
  821. completedPieceCount += count;
  822. }
  823. if (completedPieceCount > maxCompletedPieceCount) {
  824. maxCompletedPieceCount = completedPieceCount;
  825. maxCompletedPercent = peer.completePercent;
  826. } else if (completedPieceCount === maxCompletedPieceCount && peer.completePercent > maxCompletedPercent) {
  827. maxCompletedPercent = peer.completePercent;
  828. }
  829. }
  830. var totalCompletedPieceCount = 0;
  831. if (totalPieces.length > 0) {
  832. while (true) {
  833. var completed = true;
  834. for (var i = 0; i < totalPieces.length; i++) {
  835. if (totalPieces[i] > 0) {
  836. totalCompletedPieceCount++;
  837. totalPieces[i]--;
  838. } else {
  839. completed = false;
  840. }
  841. }
  842. if (!completed) {
  843. break;
  844. }
  845. }
  846. }
  847. if (totalCompletedPieceCount <= maxCompletedPieceCount) {
  848. return maxCompletedPercent;
  849. }
  850. var healthPercent = totalCompletedPieceCount / task.numPieces * 100;
  851. if (healthPercent <= maxCompletedPercent) {
  852. return maxCompletedPercent;
  853. }
  854. return healthPercent;
  855. }
  856. };
  857. }]);
  858. }());