From ff3693451c3782217df60b25bfc9765e5f33cbec Mon Sep 17 00:00:00 2001 From: Scott Cooper Date: Sun, 3 Mar 2019 17:43:49 -0800 Subject: [PATCH] feat: use shared torrent config, allow proxy agent --- package-lock.json | 40 +++++++++++++++++++--------------- package.json | 6 +++++- src/index.ts | 54 ++++++++++++++++++++++++++-------------------- test/index.spec.ts | 22 +++++++++---------- 4 files changed, 70 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2bc86b..e4db2c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -159,6 +159,14 @@ "to-fast-properties": "^2.0.0" } }, + "@ctrl/shared-torrent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@ctrl/shared-torrent/-/shared-torrent-1.0.1.tgz", + "integrity": "sha512-40i1e4cPLcLYYnAq8qEXsmh/qDsF5q+9Vj7pTLaDk7QJC/QuhmoUNYMqURUvjKvadDi2Wmio73wpsXbrkYCPDA==", + "requires": { + "@types/got": "^9.4.1" + } + }, "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", @@ -375,7 +383,6 @@ "version": "9.4.1", "resolved": "https://registry.npmjs.org/@types/got/-/got-9.4.1.tgz", "integrity": "sha512-m7Uc07bG/bZ+Dis7yI3mGssYDcAdUvP4irF3ZmBzf0ig7zEd1FyADfnELVGcf+p1Ol/iPCXbZYwcSNOJA2a+Qg==", - "dev": true, "requires": { "@types/node": "*", "@types/tough-cookie": "*" @@ -429,8 +436,7 @@ "@types/node": { "version": "11.10.4", "resolved": "https://registry.npmjs.org/@types/node/-/node-11.10.4.tgz", - "integrity": "sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==", - "dev": true + "integrity": "sha512-wa09itaLE8L705aXd8F80jnFpxz3Y1/KRHfKsYL2bPc0XF+wEWu8sR9n5bmeu8Ba1N9z2GRNzm/YdHcghLkLKg==" }, "@types/p-wait-for": { "version": "2.0.0", @@ -451,8 +457,7 @@ "@types/tough-cookie": { "version": "2.3.5", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", - "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==", - "dev": true + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==" }, "@typescript-eslint/eslint-plugin": { "version": "1.4.2", @@ -541,9 +546,9 @@ } }, "aggregate-error": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-2.1.0.tgz", - "integrity": "sha512-rIZJqC4XACGWwmPpi18IhDjIzXTJ93KQwYHXuyMCa0Ak9mtzLIbykuei+0i5EnGDy6ts8JVnSyRnZc2cVIMvVg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-2.2.0.tgz", + "integrity": "sha512-E5n+IZkhh22/pFdUvHUU/o9z752lc+7tgHt+FXS/g6BjlbE9249dGmuS/SxIWMPhTljZJkFN+7OXE0+O5+WT8w==", "dev": true, "requires": { "clean-stack": "^2.0.0", @@ -551,9 +556,9 @@ } }, "ajv": { - "version": "6.9.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.9.2.tgz", - "integrity": "sha512-4UFy0/LgDo7Oa/+wOAlj44tp9K78u38E5/359eSrqEp1Z5PdVfimCcs7SluXMP755RUQu6d2b4AvF0R1C9RZjg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -913,9 +918,9 @@ "dev": true }, "bottleneck": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.17.0.tgz", - "integrity": "sha512-0WpG/tVEBkhl9LLAFcjMTWhzQvLCYTD4wNlvtf+BZ9Q9xkMVpP5TbGPKkj2sADZtC/GQqgUMF2ij/7nD3abFLg==", + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.17.1.tgz", + "integrity": "sha512-ARJKJRNq6+W7BBYZnkqA1F4+HDclht7QyRJl2haAVtD7xBTG8Prpy6huO+canGLUxZaRrek8U/0NjTvoXACsaQ==", "dev": true }, "brace-expansion": { @@ -3154,11 +3159,12 @@ "dev": true }, "globby": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-9.0.0.tgz", - "integrity": "sha512-q0qiO/p1w/yJ0hk8V9x1UXlgsXUxlGd0AHUOXZVXBO6aznDtpx7M8D1kBrCAItoPm+4l8r6ATXV1JpjY2SBQOw==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.1.0.tgz", + "integrity": "sha512-VtYjhHr7ncls724Of5W6Kaahz0ag7dB4G62/2HsN+xEKG6SrPzM1AJMerGxQTwJGnN9reeyxdvXbuZYpfssCvg==", "dev": true, "requires": { + "@types/glob": "^7.1.1", "array-union": "^1.0.2", "dir-glob": "^2.2.1", "fast-glob": "^2.2.6", diff --git a/package.json b/package.json index 1ee068e..5ba720d 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "semantic-release": "cd dist && semantic-release" }, "dependencies": { - "got": "9.6.0" + "@ctrl/shared-torrent": "^1.0.1", + "got": "^9.6.0" }, "devDependencies": { "@types/got": "9.4.1", @@ -48,6 +49,9 @@ "typedoc": "0.14.2", "typescript": "3.3.3333" }, + "publishConfig": { + "access": "public" + }, "release": { "branch": "master" }, diff --git a/src/index.ts b/src/index.ts index f80c59c..9018086 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import { resolve } from 'url'; -import got, { Response } from 'got'; +import { resolve, URL } from 'url'; +import got, { Response, GotJSONOptions } from 'got'; import fs from 'fs'; import { AddTorrentOptions, @@ -11,27 +11,20 @@ import { DefaultResponse, FreeSpaceResponse, } from './types'; +import { TorrentSettings } from '@ctrl/shared-torrent'; -export interface TramissionConfig { - baseURL: string; - path: string; - username: string; - password: string; -} - -const defaults: TramissionConfig = { - baseURL: 'http://localhost:9091/', +const defaults: Partial = { path: '/transmission/rpc', username: '', password: '', }; export class Transmission { - config: TramissionConfig; + config: Partial; sessionId?: string; - constructor(options: Partial = {}) { + constructor(options: Partial = {}) { this.config = { ...defaults, ...options }; } @@ -186,20 +179,35 @@ export class Transmission { 'X-Transmission-Session-Id': this.sessionId, }; if (this.config.username || this.config.password) { - const auth = this.config.username + (this.config.password ? `:${this.config.password}` : ''); + let auth = this.config.username || ''; + if (this.config.password) { + auth = `${this.config.username}:${this.config.password}`; + } + headers.Authorization = 'Basic ' + Buffer.from(auth).toString('base64'); } - const url = resolve(this.config.baseURL, this.config.path); + const baseUrl = new URL(this.config.host as string); + if (this.config.port) { + baseUrl.port = `${this.config.port}`; + } + + const url = resolve(baseUrl.toString(), this.config.path as string); + const options: GotJSONOptions = { + body: { + method, + arguments: args, + }, + headers, + json: true, + }; + // allow proxy agent + if (this.config.agent) { + options.agent = this.config.agent; + } + try { - return await got.post(url, { - json: true, - body: { - method, - arguments: args, - }, - headers, - }); + return await got.post(url, options); } catch (error) { if (error.response && error.response.statusCode === 409) { this.sessionId = error.response.headers['x-transmission-session-id']; diff --git a/test/index.spec.ts b/test/index.spec.ts index 29efbbb..897a449 100644 --- a/test/index.spec.ts +++ b/test/index.spec.ts @@ -4,7 +4,7 @@ import path from 'path'; import { Transmission } from '../src/index'; -const baseURL = 'http://localhost:9091/'; +const host = 'http://localhost:9091/'; const torrentFile = path.join(__dirname, '/ubuntu-18.04.1-desktop-amd64.iso.torrent'); async function setupTorrent(transmission: Transmission) { @@ -21,7 +21,7 @@ async function setupTorrent(transmission: Transmission) { describe('Transmission', () => { afterEach(async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const res = await transmission.listTorrents(); // clean up all torrents for (const torrent of res.arguments.torrents) { @@ -29,43 +29,43 @@ describe('Transmission', () => { } }); it('should be instantiable', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); expect(transmission).toBeTruthy(); }); it('should add torrent from file path string', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const res = await transmission.addTorrent(torrentFile); expect(res.result).toBe('success'); }); it('should add torrent from file buffer', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const res = await transmission.addTorrent(fs.readFileSync(torrentFile)); expect(res.result).toBe('success'); }); it('should add torrent from file contents base64', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const contents = Buffer.from(fs.readFileSync(torrentFile)).toString('base64'); const res = await transmission.addTorrent(contents); expect(res.result).toBe('success'); }); it('should get torrents', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); await setupTorrent(transmission); const res = await transmission.listTorrents(undefined, ['id']); expect(res.arguments.torrents).toHaveLength(1); }); it('should remove torrent', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const key = await setupTorrent(transmission); await transmission.removeTorrent(key, false); }); it('should verify torrent', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const key = await setupTorrent(transmission); await transmission.verifyTorrent(key); }); it('should move in queue', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const key = await setupTorrent(transmission); await transmission.queueUp(key); await transmission.queueDown(key); @@ -73,7 +73,7 @@ describe('Transmission', () => { await transmission.queueBottom(key); }); it('should report free space', async () => { - const transmission = new Transmission({ baseURL }); + const transmission = new Transmission({ host }); const p = '/downloads'; const res = await transmission.freeSpace(p); expect(res.result).toBe('success');