setup vscode for consistent JS formatting
This commit is contained in:
parent
a641717245
commit
ec63e1cef7
15 changed files with 1675 additions and 1338 deletions
|
|
@ -1,131 +1,132 @@
|
|||
// Interface for the Torrent API response
|
||||
export interface TorrentId {
|
||||
id: number;
|
||||
info_hash: string;
|
||||
id: number;
|
||||
info_hash: string;
|
||||
}
|
||||
|
||||
export interface TorrentFile {
|
||||
name: string;
|
||||
length: number;
|
||||
included: boolean;
|
||||
name: string;
|
||||
length: number;
|
||||
included: boolean;
|
||||
}
|
||||
|
||||
// Interface for the Torrent Details API response
|
||||
export interface TorrentDetails {
|
||||
info_hash: string,
|
||||
files: Array<TorrentFile>;
|
||||
info_hash: string;
|
||||
files: Array<TorrentFile>;
|
||||
}
|
||||
|
||||
export interface AddTorrentResponse {
|
||||
id: number | null;
|
||||
details: TorrentDetails;
|
||||
output_folder: string,
|
||||
seen_peers?: Array<string>;
|
||||
id: number | null;
|
||||
details: TorrentDetails;
|
||||
output_folder: string;
|
||||
seen_peers?: Array<string>;
|
||||
}
|
||||
|
||||
export interface ListTorrentsResponse {
|
||||
torrents: Array<TorrentId>;
|
||||
torrents: Array<TorrentId>;
|
||||
}
|
||||
|
||||
export interface Speed {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
}
|
||||
|
||||
// Interface for the Torrent Stats API response
|
||||
export interface LiveTorrentStats {
|
||||
snapshot: {
|
||||
have_bytes: number;
|
||||
downloaded_and_checked_bytes: number;
|
||||
downloaded_and_checked_pieces: number;
|
||||
fetched_bytes: number;
|
||||
uploaded_bytes: number;
|
||||
initially_needed_bytes: number;
|
||||
remaining_bytes: number;
|
||||
total_bytes: number;
|
||||
total_piece_download_ms: number;
|
||||
peer_stats: {
|
||||
queued: number;
|
||||
connecting: number;
|
||||
live: number;
|
||||
seen: number;
|
||||
dead: number;
|
||||
not_needed: number;
|
||||
};
|
||||
snapshot: {
|
||||
have_bytes: number;
|
||||
downloaded_and_checked_bytes: number;
|
||||
downloaded_and_checked_pieces: number;
|
||||
fetched_bytes: number;
|
||||
uploaded_bytes: number;
|
||||
initially_needed_bytes: number;
|
||||
remaining_bytes: number;
|
||||
total_bytes: number;
|
||||
total_piece_download_ms: number;
|
||||
peer_stats: {
|
||||
queued: number;
|
||||
connecting: number;
|
||||
live: number;
|
||||
seen: number;
|
||||
dead: number;
|
||||
not_needed: number;
|
||||
};
|
||||
average_piece_download_time: {
|
||||
secs: number;
|
||||
nanos: number;
|
||||
};
|
||||
average_piece_download_time: {
|
||||
secs: number;
|
||||
nanos: number;
|
||||
};
|
||||
download_speed: Speed;
|
||||
upload_speed: Speed;
|
||||
all_time_download_speed: {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
};
|
||||
time_remaining: {
|
||||
human_readable: string;
|
||||
duration?: {
|
||||
secs: number;
|
||||
};
|
||||
download_speed: Speed;
|
||||
upload_speed: Speed;
|
||||
all_time_download_speed: {
|
||||
mbps: number;
|
||||
human_readable: string;
|
||||
};
|
||||
time_remaining: {
|
||||
human_readable: string;
|
||||
duration?: {
|
||||
secs: number,
|
||||
}
|
||||
} | null;
|
||||
} | null;
|
||||
}
|
||||
|
||||
export const STATE_INITIALIZING = 'initializing';
|
||||
export const STATE_PAUSED = 'paused';
|
||||
export const STATE_LIVE = 'live';
|
||||
export const STATE_ERROR = 'error';
|
||||
export const STATE_INITIALIZING = "initializing";
|
||||
export const STATE_PAUSED = "paused";
|
||||
export const STATE_LIVE = "live";
|
||||
export const STATE_ERROR = "error";
|
||||
|
||||
export interface TorrentStats {
|
||||
state: 'initializing' | 'paused' | 'live' | 'error',
|
||||
error: string | null,
|
||||
progress_bytes: number,
|
||||
finished: boolean,
|
||||
total_bytes: number,
|
||||
live: LiveTorrentStats | null;
|
||||
state: "initializing" | "paused" | "live" | "error";
|
||||
error: string | null;
|
||||
progress_bytes: number;
|
||||
finished: boolean;
|
||||
total_bytes: number;
|
||||
live: LiveTorrentStats | null;
|
||||
}
|
||||
|
||||
|
||||
export interface ErrorDetails {
|
||||
id?: number,
|
||||
method?: string,
|
||||
path?: string,
|
||||
status?: number,
|
||||
statusText?: string,
|
||||
text: string,
|
||||
};
|
||||
id?: number;
|
||||
method?: string;
|
||||
path?: string;
|
||||
status?: number;
|
||||
statusText?: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export type Duration = number;
|
||||
|
||||
export interface PeerConnectionOptions {
|
||||
connect_timeout?: Duration | null;
|
||||
read_write_timeout?: Duration | null;
|
||||
keep_alive_interval?: Duration | null;
|
||||
connect_timeout?: Duration | null;
|
||||
read_write_timeout?: Duration | null;
|
||||
keep_alive_interval?: Duration | null;
|
||||
}
|
||||
|
||||
export interface AddTorrentOptions {
|
||||
paused?: boolean;
|
||||
only_files_regex?: string | null;
|
||||
only_files?: number[] | null;
|
||||
overwrite?: boolean;
|
||||
list_only?: boolean;
|
||||
output_folder?: string | null;
|
||||
sub_folder?: string | null;
|
||||
peer_opts?: PeerConnectionOptions | null;
|
||||
force_tracker_interval?: Duration | null;
|
||||
initial_peers?: string[] | null; // Assuming SocketAddr is equivalent to a string in TypeScript
|
||||
preferred_id?: number | null;
|
||||
paused?: boolean;
|
||||
only_files_regex?: string | null;
|
||||
only_files?: number[] | null;
|
||||
overwrite?: boolean;
|
||||
list_only?: boolean;
|
||||
output_folder?: string | null;
|
||||
sub_folder?: string | null;
|
||||
peer_opts?: PeerConnectionOptions | null;
|
||||
force_tracker_interval?: Duration | null;
|
||||
initial_peers?: string[] | null; // Assuming SocketAddr is equivalent to a string in TypeScript
|
||||
preferred_id?: number | null;
|
||||
}
|
||||
|
||||
|
||||
export interface RqbitAPI {
|
||||
listTorrents: () => Promise<ListTorrentsResponse>,
|
||||
getTorrentDetails: (index: number) => Promise<TorrentDetails>,
|
||||
getTorrentStats: (index: number) => Promise<TorrentStats>;
|
||||
uploadTorrent: (data: string | File, opts?: AddTorrentOptions) => Promise<AddTorrentResponse>;
|
||||
listTorrents: () => Promise<ListTorrentsResponse>;
|
||||
getTorrentDetails: (index: number) => Promise<TorrentDetails>;
|
||||
getTorrentStats: (index: number) => Promise<TorrentStats>;
|
||||
uploadTorrent: (
|
||||
data: string | File,
|
||||
opts?: AddTorrentOptions
|
||||
) => Promise<AddTorrentResponse>;
|
||||
|
||||
pause: (index: number) => Promise<void>;
|
||||
start: (index: number) => Promise<void>;
|
||||
forget: (index: number) => Promise<void>;
|
||||
delete: (index: number) => Promise<void>;
|
||||
}
|
||||
pause: (index: number) => Promise<void>;
|
||||
start: (index: number) => Promise<void>;
|
||||
forget: (index: number) => Promise<void>;
|
||||
delete: (index: number) => Promise<void>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,103 +1,121 @@
|
|||
import { AddTorrentResponse, ErrorDetails, ListTorrentsResponse, RqbitAPI, TorrentDetails, TorrentStats } from "./api-types";
|
||||
import {
|
||||
AddTorrentResponse,
|
||||
ErrorDetails,
|
||||
ListTorrentsResponse,
|
||||
RqbitAPI,
|
||||
TorrentDetails,
|
||||
TorrentStats,
|
||||
} from "./api-types";
|
||||
|
||||
// Define API URL and base path
|
||||
const apiUrl = (window.origin === 'null' || window.origin === 'http://localhost:3031') ? 'http://localhost:3030' : '';
|
||||
const apiUrl =
|
||||
window.origin === "null" || window.origin === "http://localhost:3031"
|
||||
? "http://localhost:3030"
|
||||
: "";
|
||||
|
||||
const makeRequest = async (method: string, path: string, data?: any): Promise<any> => {
|
||||
console.log(method, path);
|
||||
const url = apiUrl + path;
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: data,
|
||||
};
|
||||
const makeRequest = async (
|
||||
method: string,
|
||||
path: string,
|
||||
data?: any
|
||||
): Promise<any> => {
|
||||
console.log(method, path);
|
||||
const url = apiUrl + path;
|
||||
const options: RequestInit = {
|
||||
method,
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: data,
|
||||
};
|
||||
|
||||
let error: ErrorDetails = {
|
||||
method: method,
|
||||
path: path,
|
||||
text: ''
|
||||
};
|
||||
let error: ErrorDetails = {
|
||||
method: method,
|
||||
path: path,
|
||||
text: "",
|
||||
};
|
||||
|
||||
let response: Response;
|
||||
let response: Response;
|
||||
|
||||
try {
|
||||
response = await fetch(url, options);
|
||||
} catch (e) {
|
||||
error.text = "network error";
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
error.status = response.status;
|
||||
error.statusText = `${response.status} ${response.statusText}`;
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
try {
|
||||
response = await fetch(url, options);
|
||||
const json = JSON.parse(errorBody);
|
||||
error.text =
|
||||
json.human_readable !== undefined
|
||||
? json.human_readable
|
||||
: JSON.stringify(json, null, 2);
|
||||
} catch (e) {
|
||||
error.text = 'network error';
|
||||
return Promise.reject(error);
|
||||
error.text = errorBody;
|
||||
}
|
||||
|
||||
error.status = response.status;
|
||||
error.statusText = `${response.status} ${response.statusText}`;
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
try {
|
||||
const json = JSON.parse(errorBody);
|
||||
error.text = json.human_readable !== undefined ? json.human_readable : JSON.stringify(json, null, 2);
|
||||
} catch (e) {
|
||||
error.text = errorBody;
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const result = await response.json();
|
||||
return result;
|
||||
}
|
||||
return Promise.reject(error);
|
||||
}
|
||||
const result = await response.json();
|
||||
return result;
|
||||
};
|
||||
|
||||
export const API: RqbitAPI & { getVersion: () => Promise<string> } = {
|
||||
listTorrents: (): Promise<ListTorrentsResponse> => makeRequest('GET', '/torrents'),
|
||||
getTorrentDetails: (index: number): Promise<TorrentDetails> => {
|
||||
return makeRequest('GET', `/torrents/${index}`);
|
||||
},
|
||||
getTorrentStats: (index: number): Promise<TorrentStats> => {
|
||||
return makeRequest('GET', `/torrents/${index}/stats/v1`);
|
||||
},
|
||||
listTorrents: (): Promise<ListTorrentsResponse> =>
|
||||
makeRequest("GET", "/torrents"),
|
||||
getTorrentDetails: (index: number): Promise<TorrentDetails> => {
|
||||
return makeRequest("GET", `/torrents/${index}`);
|
||||
},
|
||||
getTorrentStats: (index: number): Promise<TorrentStats> => {
|
||||
return makeRequest("GET", `/torrents/${index}/stats/v1`);
|
||||
},
|
||||
|
||||
uploadTorrent: (data, opts): Promise<AddTorrentResponse> => {
|
||||
let url = '/torrents?&overwrite=true';
|
||||
if (opts?.list_only) {
|
||||
url += '&list_only=true';
|
||||
}
|
||||
if (opts?.only_files != null) {
|
||||
url += `&only_files=${opts.only_files.join(',')}`;
|
||||
}
|
||||
if (opts?.peer_opts?.connect_timeout) {
|
||||
url += `&peer_connect_timeout=${opts.peer_opts.connect_timeout}`;
|
||||
}
|
||||
if (opts?.peer_opts?.read_write_timeout) {
|
||||
url += `&peer_read_write_timeout=${opts.peer_opts.read_write_timeout}`;
|
||||
}
|
||||
if (opts?.initial_peers) {
|
||||
url += `&initial_peers=${opts.initial_peers.join(',')}`;
|
||||
}
|
||||
if (opts?.output_folder) {
|
||||
url += `&output_folder=${opts.output_folder}`;
|
||||
}
|
||||
if (typeof data === 'string') {
|
||||
url += '&is_url=true';
|
||||
}
|
||||
return makeRequest('POST', url, data)
|
||||
},
|
||||
|
||||
pause: (index: number): Promise<void> => {
|
||||
return makeRequest('POST', `/torrents/${index}/pause`);
|
||||
},
|
||||
|
||||
start: (index: number): Promise<void> => {
|
||||
return makeRequest('POST', `/torrents/${index}/start`);
|
||||
},
|
||||
|
||||
forget: (index: number): Promise<void> => {
|
||||
return makeRequest('POST', `/torrents/${index}/forget`);
|
||||
},
|
||||
|
||||
delete: (index: number): Promise<void> => {
|
||||
return makeRequest('POST', `/torrents/${index}/delete`);
|
||||
},
|
||||
getVersion: async (): Promise<string> => {
|
||||
const r = await makeRequest('GET', '/');
|
||||
return r.version;
|
||||
uploadTorrent: (data, opts): Promise<AddTorrentResponse> => {
|
||||
let url = "/torrents?&overwrite=true";
|
||||
if (opts?.list_only) {
|
||||
url += "&list_only=true";
|
||||
}
|
||||
}
|
||||
if (opts?.only_files != null) {
|
||||
url += `&only_files=${opts.only_files.join(",")}`;
|
||||
}
|
||||
if (opts?.peer_opts?.connect_timeout) {
|
||||
url += `&peer_connect_timeout=${opts.peer_opts.connect_timeout}`;
|
||||
}
|
||||
if (opts?.peer_opts?.read_write_timeout) {
|
||||
url += `&peer_read_write_timeout=${opts.peer_opts.read_write_timeout}`;
|
||||
}
|
||||
if (opts?.initial_peers) {
|
||||
url += `&initial_peers=${opts.initial_peers.join(",")}`;
|
||||
}
|
||||
if (opts?.output_folder) {
|
||||
url += `&output_folder=${opts.output_folder}`;
|
||||
}
|
||||
if (typeof data === "string") {
|
||||
url += "&is_url=true";
|
||||
}
|
||||
return makeRequest("POST", url, data);
|
||||
},
|
||||
|
||||
pause: (index: number): Promise<void> => {
|
||||
return makeRequest("POST", `/torrents/${index}/pause`);
|
||||
},
|
||||
|
||||
start: (index: number): Promise<void> => {
|
||||
return makeRequest("POST", `/torrents/${index}/start`);
|
||||
},
|
||||
|
||||
forget: (index: number): Promise<void> => {
|
||||
return makeRequest("POST", `/torrents/${index}/forget`);
|
||||
},
|
||||
|
||||
delete: (index: number): Promise<void> => {
|
||||
return makeRequest("POST", `/torrents/${index}/delete`);
|
||||
},
|
||||
getVersion: async (): Promise<string> => {
|
||||
const r = await makeRequest("GET", "/");
|
||||
return r.version;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,27 +1,33 @@
|
|||
import { StrictMode, useEffect, useState } from "react";
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { RqbitWebUI, APIContext, customSetInterval } from "./rqbit-web";
|
||||
import { API } from "./http-api";
|
||||
|
||||
const RootWithVersion = () => {
|
||||
let [title, setTitle] = useState<string>("rqbit web UI");
|
||||
useEffect(() => {
|
||||
const refreshVersion = () => API.getVersion().then((version) => {
|
||||
setTitle(`rqbit web UI - v${version}`);
|
||||
return 10000;
|
||||
}, (e) => {
|
||||
return 1000;
|
||||
});
|
||||
return customSetInterval(refreshVersion, 0)
|
||||
}, [])
|
||||
let [title, setTitle] = useState<string>("rqbit web UI");
|
||||
useEffect(() => {
|
||||
const refreshVersion = () =>
|
||||
API.getVersion().then(
|
||||
(version) => {
|
||||
setTitle(`rqbit web UI - v${version}`);
|
||||
return 10000;
|
||||
},
|
||||
(e) => {
|
||||
return 1000;
|
||||
}
|
||||
);
|
||||
return customSetInterval(refreshVersion, 0);
|
||||
}, []);
|
||||
|
||||
return <StrictMode>
|
||||
<APIContext.Provider value={API}>
|
||||
<RqbitWebUI title={title} />
|
||||
</APIContext.Provider>
|
||||
</StrictMode>;
|
||||
}
|
||||
return (
|
||||
<StrictMode>
|
||||
<APIContext.Provider value={API}>
|
||||
<RqbitWebUI title={title} />
|
||||
</APIContext.Provider>
|
||||
</StrictMode>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('app') as HTMLInputElement).render(
|
||||
<RootWithVersion />
|
||||
ReactDOM.createRoot(document.getElementById("app") as HTMLInputElement).render(
|
||||
<RootWithVersion />
|
||||
);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue