Full OpenAPI-based client for the Rclone RC API
Built on top of rclone-openapi (by yours truly) Β· Works with Vanilla Fetch Β· React Query Β· SWR Β· Rust
cargo add rclone-sdk[dependencies]
rclone-sdk = "1.72"
tokio = { version = "1", features = ["full"] }use rclone_sdk::Client;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::new("http://localhost:5572");
// Get rclone version info
let version = client.core_version(None, None).await?;
let v = version.into_inner();
println!("Rclone {} on {}/{}", v.version, v.os, v.arch);
// List all configured remotes
let remotes = client.config_listremotes(None, None).await?;
println!("Remotes: {:?}", remotes.into_inner().remotes);
// Get storage info for a remote
let about = client.operations_about(None, None, "gdrive:").await?;
let info = about.into_inner();
println!("Storage: {} / {} bytes used", info.used, info.total);
Ok(())
}npm install rclone-sdkimport createRCDClient from 'rclone-sdk'
const rcd = createRCDClient({ baseUrl: 'http://localhost:5572' })
// List all configured remotes
const { data: remotes } = await rcd.POST('/config/listremotes')
console.log(remotes?.remotes) // ['gdrive', 'dropbox', 's3']
// List files in a remote
const { data: files } = await rcd.POST('/operations/list', {
body: { fs: 'gdrive:', remote: 'Documents' }
})
console.log(files?.list)
// Get storage info for a remote
const { data: about } = await rcd.POST('/operations/about', {
body: { fs: 'gdrive:' }
})
console.log(`Used: ${about?.used} / ${about?.total}`)import createRCDQueryClient from 'rclone-sdk/query'
const rq = createRCDQueryClient({ baseUrl: 'http://localhost:5572' })
function RemotesList() {
const { data, isLoading, error } = rq.useQuery('post', '/config/listremotes')
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<ul>
{data?.remotes?.map(remote => (
<li key={remote}>{remote}</li>
))}
</ul>
)
}
function StorageInfo({ remote }: { remote: string }) {
const { data } = rq.useQuery('post', '/operations/about', {
body: { fs: `${remote}:` }
})
return <span>{data?.used} / {data?.total} bytes</span>
}import createRCDSWR from 'rclone-sdk/swr'
const swr = createRCDSWR({ baseUrl: 'http://localhost:5572' })
function RemotesList() {
const { data, error, isLoading } = swr.useQuery('post', '/config/listremotes')
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return (
<ul>
{data?.remotes?.map(remote => (
<li key={remote}>{remote}</li>
))}
</ul>
)
}
function FileList({ remote, path }: { remote: string; path: string }) {
const { data } = swr.useQuery('post', '/operations/list', {
body: { fs: `${remote}:`, remote: path }
})
return (
<ul>
{data?.list?.map(item => (
<li key={item.Path}>
{item.IsDir ? 'π' : 'π'} {item.Name}
</li>
))}
</ul>
)
}Even though the client supports all HTTP methods, rclone expects everything as a POST request.
If you want to wrap the client to only send POST requests and throw errors automatically, here's a quick snippet (adjust to taste):
import createRCDClient, {
type OpenApiMethodResponse,
type OpenApiClient,
type OpenApiClientPathsWithMethod,
type OpenApiMaybeOptionalInit,
type OpenApiRequiredKeysOf,
type RCDClient,
} from 'rclone-sdk'
type ClientPaths<T> = T extends OpenApiClient<infer P, any> ? P : never
type Paths = ClientPaths<RCDClient>
type InitParam<Init> = OpenApiRequiredKeysOf<Init> extends never
? [(Init & { [key: string]: unknown })?]
: [Init & { [key: string]: unknown }]
export default async function rclone<
Path extends OpenApiClientPathsWithMethod<RCDClient, 'post'>,
Init extends OpenApiMaybeOptionalInit<Paths[Path], 'post'> = OpenApiMaybeOptionalInit<
Paths[Path],
'post'
>,
>(
path: Path,
...init: InitParam<Init>
): Promise<OpenApiMethodResponse<RCDClient, 'post', Path, Init>> {
const client = createRCDClient({ baseUrl: 'http://localhost:5572' })
const result = await client.POST(
path,
...(init as InitParam<OpenApiMaybeOptionalInit<Paths[Path], 'post'>>)
)
if (result?.error) {
const message =
typeof result.error === 'string' ? result.error : JSON.stringify(result.error)
throw new Error(message)
}
const data = result.data as { error?: unknown } | undefined
if (data?.error) {
const message = typeof data.error === 'string' ? data.error : JSON.stringify(data.error)
throw new Error(message)
}
if (!result.response.ok) {
throw new Error(`${result.response.status} ${result.response.statusText}`)
}
return result.data as OpenApiMethodResponse<typeof client, 'post', Path, Init>
}Now you'll be able to
- call
rclone('config/listremotes')directly - get the data as the return value (correctly typed, and without having to de-construct the resulting object)
- have it throw on error with a detailed error message (instead of checking the
errorfield manually)
Contributions = welcome! Just make sure to check if the PR isn't a better fit for the rclone-openapi repo.
Made with βοΈ for the rclone community