From 53f7f48c95c4c65374a404b7eb1d4864a10a78ee Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Wed, 30 Sep 2020 11:59:01 +0800 Subject: [PATCH] API: group Torrents APIs to /torrents routes --- .../src/javascript/actions/TorrentActions.ts | 24 +- server/routes/api.ts | 3 + server/routes/client.ts | 163 +------------ server/routes/torrents.ts | 222 ++++++++++++++++++ shared/types/Action.ts | 23 +- 5 files changed, 252 insertions(+), 183 deletions(-) create mode 100644 server/routes/torrents.ts diff --git a/client/src/javascript/actions/TorrentActions.ts b/client/src/javascript/actions/TorrentActions.ts index e64a552a..b241724b 100644 --- a/client/src/javascript/actions/TorrentActions.ts +++ b/client/src/javascript/actions/TorrentActions.ts @@ -19,7 +19,7 @@ const baseURI = ConfigStore.getBaseURI(); const TorrentActions = { addTorrentsByUrls: (options: AddTorrentByURLOptions) => axios - .post(`${baseURI}api/client/torrents/add`, options) + .post(`${baseURI}api/torrents/add`, options) .then((json) => json.data) .then( (response) => { @@ -44,7 +44,7 @@ const TorrentActions = { addTorrentsByFiles: (options: AddTorrentByFileOptions) => axios - .post(`${baseURI}api/client/torrents/add-files`, options) + .post(`${baseURI}api/torrents/add-files`, options) .then((json) => json.data) .then( (data) => { @@ -69,7 +69,7 @@ const TorrentActions = { deleteTorrents: (options: DeleteTorrentsOptions) => axios - .post(`${baseURI}api/client/torrents/delete`, options) + .post(`${baseURI}api/torrents/delete`, options) .then((json) => json.data) .then( (data) => { @@ -95,7 +95,7 @@ const TorrentActions = { checkHash: (options: CheckTorrentsOptions) => axios - .post(`${baseURI}api/client/torrents/check-hash`, options) + .post(`${baseURI}api/torrents/check-hash`, options) .then((json) => json.data) .then( (data) => { @@ -120,7 +120,7 @@ const TorrentActions = { fetchTorrentDetails: (hash: TorrentProperties['hash']) => axios - .get(`${baseURI}api/client/torrents/${hash}/details`) + .get(`${baseURI}api/torrents/${hash}/details`) .then((json) => json.data) .then( (torrentDetails) => { @@ -144,7 +144,7 @@ const TorrentActions = { moveTorrents: (options: MoveTorrentsOptions) => { return axios - .post(`${baseURI}api/client/torrents/move`, options) + .post(`${baseURI}api/torrents/move`, options) .then((json) => json.data) .then( (data) => { @@ -170,7 +170,7 @@ const TorrentActions = { startTorrents: (options: StartTorrentsOptions) => axios - .post(`${baseURI}api/client/torrents/start`, options) + .post(`${baseURI}api/torrents/start`, options) .then((json) => json.data) .then( (data) => { @@ -189,7 +189,7 @@ const TorrentActions = { stopTorrents: (options: StopTorrentsOptions) => axios - .post(`${baseURI}api/client/torrents/stop`, options) + .post(`${baseURI}api/torrents/stop`, options) .then((json) => json.data) .then( (data) => { @@ -208,7 +208,7 @@ const TorrentActions = { setPriority: (hash: TorrentProperties['hash'], priority: number) => axios - .patch(`${baseURI}api/client/torrents/${hash}/priority`, { + .patch(`${baseURI}api/torrents/${hash}/priority`, { hash, priority, }) @@ -230,7 +230,7 @@ const TorrentActions = { setFilePriority: (hash: TorrentProperties['hash'], fileIndices: Array, priority: number) => axios - .patch(`${baseURI}api/client/torrents/${hash}/file-priority`, { + .patch(`${baseURI}api/torrents/${hash}/file-priority`, { hash, fileIndices, priority, @@ -258,7 +258,7 @@ const TorrentActions = { setTaxonomy: (hashes: Array, tags: Array, options = {}) => axios - .patch(`${baseURI}api/client/torrents/taxonomy`, { + .patch(`${baseURI}api/torrents/taxonomy`, { hashes, tags, options, @@ -281,7 +281,7 @@ const TorrentActions = { setTracker: (hashes: Array, tracker: string, options = {}) => axios - .patch(`${baseURI}api/client/torrents/tracker`, { + .patch(`${baseURI}api/torrents/tracker`, { hashes, tracker, options, diff --git a/server/routes/api.ts b/server/routes/api.ts index 3b908077..c931daf3 100644 --- a/server/routes/api.ts +++ b/server/routes/api.ts @@ -15,6 +15,7 @@ import eventStream from '../middleware/eventStream'; import Filesystem from '../models/Filesystem'; import mediainfo from '../util/mediainfo'; import settings from '../models/settings'; +import torrentsRoutes from './torrents'; const router = express.Router(); @@ -22,6 +23,8 @@ router.use('/', passport.authenticate('jwt', {session: false}), appendUserServic router.use('/client', clientRoutes); +router.use('/torrents', torrentsRoutes); + router.get('/activity-stream', eventStream, clientActivityStream); router.get('/download', (req, res) => { diff --git a/server/routes/client.ts b/server/routes/client.ts index 76045d15..ee2437d1 100644 --- a/server/routes/client.ts +++ b/server/routes/client.ts @@ -1,13 +1,5 @@ import express from 'express'; -import type { - CheckTorrentsOptions, - DeleteTorrentsOptions, - MoveTorrentsOptions, - StartTorrentsOptions, - StopTorrentsOptions, -} from '@shared/types/Action'; - import ajaxUtil from '../util/ajaxUtil'; import client from '../models/client'; @@ -47,160 +39,7 @@ router.put('/settings/speed-limits', (req, res) => { client.setSpeedLimits(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); }); -router.post('/torrents/add', (req, res) => { - client.addUrls(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); -}); - -router.post('/torrents/add-files', (req, res) => { - client.addFiles(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); -}); - -/** - * POST /api/client/torrents/start - * @summary Starts torrents. - * @tags Torrents - * @security AuthenticatedUser - * @param {StartTorrentsOptions} request.body.required - options - application/json - * @return {object} 200 - success response - application/json - * @return {Error} 500 - failure response - application/json - */ -router.post('/torrents/start', (req, res) => { - const {hashes} = req.body; - const callback = ajaxUtil.getResponseFn(res); - - req.services?.clientGatewayService - .startTorrents({hashes}) - .then((response) => { - req.services?.torrentService.fetchTorrentList(); - return response; - }) - .then(callback) - .catch((err) => { - callback(null, err); - }); -}); - -/** - * POST /api/client/torrents/stop - * @summary Stops torrents. - * @tags Torrents - * @security AuthenticatedUser - * @param {StopTorrentsOptions} request.body.required - options - application/json - * @return {object} 200 - success response - application/json - * @return {Error} 500 - failure response - application/json - */ -router.post('/torrents/stop', (req, res) => { - const {hashes} = req.body; - const callback = ajaxUtil.getResponseFn(res); - - req.services?.clientGatewayService - .stopTorrents({hashes}) - .then((response) => { - req.services?.torrentService.fetchTorrentList(); - return response; - }) - .then(callback) - .catch((err) => { - callback(null, err); - }); -}); - -/** - * POST /api/client/torrents/check-hash - * @summary Hash checks torrents. - * @tags Torrents - * @security AuthenticatedUser - * @param {CheckTorrentsOptions} request.body.required - options - application/json - * @return {object} 200 - success response - application/json - * @return {Error} 500 - failure response - application/json - */ -router.post('/torrents/check-hash', (req, res) => { - const {hashes} = req.body; - const callback = ajaxUtil.getResponseFn(res); - - req.services?.clientGatewayService - .checkTorrents({hashes}) - .then((response) => { - req.services?.torrentService.fetchTorrentList(); - return response; - }) - .then(callback) - .catch((err) => { - callback(null, err); - }); -}); - -/** - * POST /api/client/torrents/move - * @summary Moves torrents to specified destination path. - * @tags Torrents - * @security AuthenticatedUser - * @param {MoveTorrentsOptions} request.body.required - options - application/json - * @return {object} 200 - success response - application/json - * @return {Error} 500 - failure response - application/json - */ -router.post('/torrents/move', (req, res) => { - const {hashes, destination, moveFiles, isBasePath, isCheckHash} = req.body; - const callback = ajaxUtil.getResponseFn(res); - - req.services?.clientGatewayService - .moveTorrents({hashes, destination, moveFiles, isBasePath, isCheckHash}) - .then((response) => { - req.services?.torrentService.fetchTorrentList(); - return response; - }) - .then(callback) - .catch((err) => { - callback(null, err); - }); -}); - -/** - * POST /api/client/torrents/delete - * @summary Removes torrents from Flood. Optionally deletes data of torrents. - * @tags Torrents - * @security AuthenticatedUser - * @param {DeleteTorrentsOptions} request.body.required - options - application/json - * @return {object} 200 - success response - application/json - * @return {Error} 500 - failure response - application/json - */ -router.post('/torrents/delete', (req, res) => { - const {hashes, deleteData} = req.body; - const callback = ajaxUtil.getResponseFn(res); - - req.services?.clientGatewayService - .removeTorrents({hashes, deleteData}) - .then((response) => { - req.services?.torrentService.fetchTorrentList(); - return response; - }) - .then(callback) - .catch((err) => { - callback(null, err); - }); -}); - -router.patch('/torrents/taxonomy', (req, res) => { - client.setTaxonomy(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); -}); - -router.patch('/torrents/tracker', (req, res) => { - client.setTracker(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); -}); - -router.get('/torrents/:hash/details', (req, res) => { - client.getTorrentDetails(req.user, req.services, req.params.hash, ajaxUtil.getResponseFn(res)); -}); - -router.patch('/torrents/:hash/priority', (req, res) => { - client.setPriority(req.user, req.services, req.params.hash, req.body, ajaxUtil.getResponseFn(res)); -}); - -router.patch('/torrents/:hash/file-priority', (req, res) => { - client.setFilePriority(req.user, req.services, req.params.hash, req.body, ajaxUtil.getResponseFn(res)); -}); - -router.get('/methods.json', (req, res) => { +router.get('/rtorrent-methods', (req, res) => { const {type} = req.query; const {args} = req.query; let method = 'system.listMethods'; diff --git a/server/routes/torrents.ts b/server/routes/torrents.ts new file mode 100644 index 00000000..c65711de --- /dev/null +++ b/server/routes/torrents.ts @@ -0,0 +1,222 @@ +import express from 'express'; + +import type { + AddTorrentByFileOptions, + AddTorrentByURLOptions, + CheckTorrentsOptions, + DeleteTorrentsOptions, + MoveTorrentsOptions, + StartTorrentsOptions, + StopTorrentsOptions, +} from '@shared/types/Action'; + +import ajaxUtil from '../util/ajaxUtil'; +import client from '../models/client'; + +const router = express.Router(); + +/** + * POST /api/torrents/add + * @summary Adds torrents by URLs. + * @tags Torrents + * @security AuthenticatedUser + * @param {AddTorrentByURLOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/add', (req, res) => { + client.addUrls(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); +}); + +/** + * POST /api/torrents/add-files + * @summary Adds torrents by files. + * @tags Torrents + * @security AuthenticatedUser + * @param {AddTorrentByFileOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/add-files', (req, res) => { + client.addFiles(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); +}); + +/** + * POST /api/torrents/start + * @summary Starts torrents. + * @tags Torrents + * @security AuthenticatedUser + * @param {StartTorrentsOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/start', (req, res) => { + const {hashes} = req.body; + const callback = ajaxUtil.getResponseFn(res); + + req.services?.clientGatewayService + .startTorrents({hashes}) + .then((response) => { + req.services?.torrentService.fetchTorrentList(); + return response; + }) + .then(callback) + .catch((err) => { + callback(null, err); + }); +}); + +/** + * POST /api/torrents/stop + * @summary Stops torrents. + * @tags Torrents + * @security AuthenticatedUser + * @param {StopTorrentsOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/stop', (req, res) => { + const {hashes} = req.body; + const callback = ajaxUtil.getResponseFn(res); + + req.services?.clientGatewayService + .stopTorrents({hashes}) + .then((response) => { + req.services?.torrentService.fetchTorrentList(); + return response; + }) + .then(callback) + .catch((err) => { + callback(null, err); + }); +}); + +/** + * POST /api/torrents/check-hash + * @summary Hash checks torrents. + * @tags Torrents + * @security AuthenticatedUser + * @param {CheckTorrentsOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/check-hash', (req, res) => { + const {hashes} = req.body; + const callback = ajaxUtil.getResponseFn(res); + + req.services?.clientGatewayService + .checkTorrents({hashes}) + .then((response) => { + req.services?.torrentService.fetchTorrentList(); + return response; + }) + .then(callback) + .catch((err) => { + callback(null, err); + }); +}); + +/** + * POST /api/torrents/move + * @summary Moves torrents to specified destination path. + * @tags Torrents + * @security AuthenticatedUser + * @param {MoveTorrentsOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/move', (req, res) => { + const {hashes, destination, moveFiles, isBasePath, isCheckHash} = req.body; + const callback = ajaxUtil.getResponseFn(res); + + req.services?.clientGatewayService + .moveTorrents({hashes, destination, moveFiles, isBasePath, isCheckHash}) + .then((response) => { + req.services?.torrentService.fetchTorrentList(); + return response; + }) + .then(callback) + .catch((err) => { + callback(null, err); + }); +}); + +/** + * POST /api/torrents/delete + * @summary Removes torrents from Flood. Optionally deletes data of torrents. + * @tags Torrents + * @security AuthenticatedUser + * @param {DeleteTorrentsOptions} request.body.required - options - application/json + * @return {object} 200 - success response - application/json + * @return {Error} 500 - failure response - application/json + */ +router.post('/delete', (req, res) => { + const {hashes, deleteData} = req.body; + const callback = ajaxUtil.getResponseFn(res); + + req.services?.clientGatewayService + .removeTorrents({hashes, deleteData}) + .then((response) => { + req.services?.torrentService.fetchTorrentList(); + return response; + }) + .then(callback) + .catch((err) => { + callback(null, err); + }); +}); + +/** + * PATCH /api/torrents/taxonomy + * @summary Sets tags of torrents. + * @tags Torrents + * @security AuthenticatedUser + */ +router.patch('/taxonomy', (req, res) => { + client.setTaxonomy(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); +}); + +/** + * PATCH /api/torrents/tracker + * @summary Sets tracker of torrents. + * @tags Torrents + * @security AuthenticatedUser + */ +router.patch('/tracker', (req, res) => { + client.setTracker(req.user, req.services, req.body, ajaxUtil.getResponseFn(res)); +}); + +/** + * + * APIs below operate on a single torrent. + * + */ + +/** + * GET /api/{hash}/details + * @summary Gets details of a torrent. + * @security AuthenticatedUser + */ +router.get('/:hash/details', (req, res) => { + client.getTorrentDetails(req.user, req.services, req.params.hash, ajaxUtil.getResponseFn(res)); +}); + +/** + * PATCH /api/{hash}/priority + * @summary Sets priority of a torrent. + * @security AuthenticatedUser + */ +router.patch('/:hash/priority', (req, res) => { + client.setPriority(req.user, req.services, req.params.hash, req.body, ajaxUtil.getResponseFn(res)); +}); + +/** + * PATCH /api/{hash}/file-priority + * @summary Sets priority of files of a torrent. + * @security AuthenticatedUser + */ +router.patch('/:hash/file-priority', (req, res) => { + client.setFilePriority(req.user, req.services, req.params.hash, req.body, ajaxUtil.getResponseFn(res)); +}); + +export default router; diff --git a/shared/types/Action.ts b/shared/types/Action.ts index b5c6162b..680f3fda 100644 --- a/shared/types/Action.ts +++ b/shared/types/Action.ts @@ -1,15 +1,20 @@ import {TorrentProperties} from './Torrent'; -// POST /api/client/add +// POST /api/torrents/add export interface AddTorrentByURLOptions { + // URLs to download torrents from urls: Array; + // Path of destination destination: string; - isBasePath: boolean; - start: boolean; + // Tags tags?: Array; + // Whether destination is the base path + isBasePath: boolean; + // Whether to start torrent + start: boolean; } -// POST /api/client/add-files +// POST /api/torrents/add-files export interface AddTorrentByFileOptions { // Torrent files in base64 files: Array; @@ -23,13 +28,13 @@ export interface AddTorrentByFileOptions { start: boolean; } -// POST /api/client/torrents/check-hash +// POST /api/torrents/check-hash export interface CheckTorrentsOptions { // An array of string representing hashes of torrents to be checked hashes: Array; } -// POST /api/client/torrents/delete +// POST /api/torrents/delete export interface DeleteTorrentsOptions { // An array of string representing hashes of torrents to be removed hashes: Array; @@ -37,7 +42,7 @@ export interface DeleteTorrentsOptions { deleteData?: boolean; } -// POST /api/client/torrents/move +// POST /api/torrents/move export interface MoveTorrentsOptions { // Hashes of torrents to be moved hashes: Array; @@ -51,13 +56,13 @@ export interface MoveTorrentsOptions { isCheckHash: boolean; } -// POST /api/client/torrents/start +// POST /api/torrents/start export interface StartTorrentsOptions { // An array of string representing hashes of torrents to be started hashes: Array; } -// POST /api/client/torrents/stop +// POST /api/torrents/stop export interface StopTorrentsOptions { // An array of string representing hashes of torrents to be stopped hashes: Array;