mirror of
https://github.com/zoriya/flood.git
synced 2025-12-05 23:06:20 +00:00
298 lines
7.5 KiB
TypeScript
298 lines
7.5 KiB
TypeScript
import axios, {AxiosError} from 'axios';
|
|
|
|
import type {TransmissionConnectionSettings} from '@shared/schema/ClientConnectionSettings';
|
|
|
|
import type {
|
|
TransmissionSessionGetArguments,
|
|
TransmissionSessionProperties,
|
|
TransmissionSessionSetArguments,
|
|
TransmissionSessionStats,
|
|
} from './types/TransmissionSessionMethods';
|
|
import {
|
|
TransmissionTorrentIDs,
|
|
TransmissionTorrentProperties,
|
|
TransmissionTorrentAddArguments,
|
|
TransmissionTorrentsGetArguments,
|
|
TransmissionTorrentsRemoveArguments,
|
|
TransmissionTorrentsSetArguments,
|
|
TransmissionTorrentsSetLocationArguments,
|
|
} from './types/TransmissionTorrentsMethods';
|
|
|
|
class ClientRequestManager {
|
|
private rpcURL: string;
|
|
private authHeader: string;
|
|
private sessionID?: Promise<string | undefined>;
|
|
|
|
async fetchSessionID(url = this.rpcURL, authHeader = this.authHeader): Promise<string | undefined> {
|
|
return axios
|
|
.get(url, {
|
|
headers: {
|
|
Authorization: authHeader,
|
|
},
|
|
})
|
|
.then<string | undefined>(
|
|
() => {
|
|
return undefined;
|
|
},
|
|
(err: AxiosError) => {
|
|
if (err.response?.status === 409) {
|
|
return err.response?.headers['x-transmission-session-id'];
|
|
}
|
|
throw err;
|
|
},
|
|
);
|
|
}
|
|
|
|
async updateSessionID(url = this.rpcURL, authHeader = this.authHeader): Promise<void> {
|
|
let authFailed = false;
|
|
|
|
this.sessionID = new Promise((resolve) => {
|
|
this.fetchSessionID(url, authHeader).then(
|
|
(sessionID) => {
|
|
resolve(sessionID);
|
|
},
|
|
() => {
|
|
authFailed = true;
|
|
resolve(undefined);
|
|
},
|
|
);
|
|
});
|
|
|
|
await this.sessionID;
|
|
|
|
return authFailed ? Promise.reject() : Promise.resolve();
|
|
}
|
|
|
|
async getRequestHeaders(): Promise<Record<string, string>> {
|
|
const sessionID = await this.sessionID;
|
|
|
|
return {
|
|
Authorization: this.authHeader,
|
|
...(sessionID == null ? {} : {'X-Transmission-Session-Id': sessionID}),
|
|
};
|
|
}
|
|
|
|
async getSessionStats(): Promise<TransmissionSessionStats> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'session-stats'},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
return res.data.arguments;
|
|
});
|
|
}
|
|
|
|
async getSessionProperties<T extends TransmissionSessionGetArguments['fields']>(
|
|
fields: T,
|
|
): Promise<Pick<TransmissionSessionProperties, T[number]>> {
|
|
const sessionGetArguments: TransmissionSessionGetArguments = {fields};
|
|
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'session-get', arguments: sessionGetArguments},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
return res.data.arguments;
|
|
});
|
|
}
|
|
|
|
async setSessionProperties(properties: TransmissionSessionSetArguments): Promise<void> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'session-set', arguments: properties},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async getTorrents<T extends TransmissionTorrentsGetArguments['fields']>(
|
|
ids: TransmissionTorrentIDs | null,
|
|
fields: T,
|
|
): Promise<Array<Pick<TransmissionTorrentProperties, T[number]>>> {
|
|
const torrentsGetArguments: TransmissionTorrentsGetArguments = {
|
|
ids: ids || undefined,
|
|
fields,
|
|
format: 'objects',
|
|
};
|
|
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-get', arguments: torrentsGetArguments},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success' || res.data.arguments.torrents == null) {
|
|
throw new Error();
|
|
}
|
|
return res.data.arguments.torrents;
|
|
});
|
|
}
|
|
|
|
async addTorrent(
|
|
args: TransmissionTorrentAddArguments,
|
|
): Promise<Pick<TransmissionTorrentProperties, 'id' | 'name' | 'hashString'>> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-add', arguments: args},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
return res.data.arguments;
|
|
});
|
|
}
|
|
|
|
async setTorrentsProperties(args: TransmissionTorrentsSetArguments): Promise<void> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-set', arguments: args},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async startTorrents(ids: TransmissionTorrentIDs): Promise<void> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-start-now', arguments: {ids}},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async stopTorrents(ids: TransmissionTorrentIDs): Promise<void> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-stop', arguments: {ids}},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async verifyTorrents(ids: TransmissionTorrentIDs): Promise<void> {
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-verify', arguments: {ids}},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async removeTorrents(ids: TransmissionTorrentIDs, deleteData?: boolean): Promise<void> {
|
|
const removeTorrentsArguments: TransmissionTorrentsRemoveArguments = {
|
|
ids,
|
|
'delete-local-data': deleteData,
|
|
};
|
|
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{method: 'torrent-remove', arguments: removeTorrentsArguments},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
async setTorrentsLocation(ids: TransmissionTorrentIDs, location: string, move?: boolean): Promise<void> {
|
|
const torrentsSetLocationArguments: TransmissionTorrentsSetLocationArguments = {
|
|
ids,
|
|
location,
|
|
move,
|
|
};
|
|
|
|
return axios
|
|
.post(
|
|
this.rpcURL,
|
|
{
|
|
method: 'torrent-set-location',
|
|
arguments: torrentsSetLocationArguments,
|
|
},
|
|
{
|
|
headers: await this.getRequestHeaders(),
|
|
},
|
|
)
|
|
.then((res) => {
|
|
if (res.data.result !== 'success') {
|
|
throw new Error();
|
|
}
|
|
});
|
|
}
|
|
|
|
constructor(connectionSettings: TransmissionConnectionSettings) {
|
|
const {url, username, password} = connectionSettings;
|
|
|
|
this.rpcURL = url;
|
|
this.authHeader = `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`;
|
|
|
|
this.updateSessionID().catch(() => undefined);
|
|
setInterval(() => {
|
|
this.updateSessionID().catch(() => undefined);
|
|
}, 1000 * 60 * 60 * 8);
|
|
}
|
|
}
|
|
|
|
export default ClientRequestManager;
|