206 lines
7.4 KiB
JavaScript
206 lines
7.4 KiB
JavaScript
const { join } = require("path");
|
|
const { spawn, ChildProcess } = require("child_process");
|
|
|
|
let { platform } = process;
|
|
|
|
const RCLONE_DIR = join(__dirname, "bin");
|
|
const DEFAULT_RCLONE_EXECUTABLE = join(RCLONE_DIR, `rclone${ platform === "windows"? ".exe" : "" }`);
|
|
const {
|
|
RCLONE_EXECUTABLE = DEFAULT_RCLONE_EXECUTABLE,
|
|
} = process.env;
|
|
|
|
const CHILD_OPTIONS = [
|
|
"cwd",
|
|
"env",
|
|
"argv0",
|
|
"stdio",
|
|
"detached",
|
|
"uid",
|
|
"gid",
|
|
"serialization",
|
|
"shell",
|
|
"windowsVerbatimArguments",
|
|
"windowsHide",
|
|
"signal",
|
|
"timeout",
|
|
"killSignal",
|
|
];
|
|
|
|
/**
|
|
* Spawns a rclone process to execute with the supplied arguments.
|
|
*
|
|
* The last argument can also be an object with all the flags.
|
|
*
|
|
* Options for the child process can also be passed into this last argument,
|
|
* and they will be picked out.
|
|
*
|
|
* @param {...string|object} args arguments for the API call.
|
|
* @returns {ChildProcess} the rclone subprocess.
|
|
*/
|
|
const api = function(...args) {
|
|
let flags = args.pop();
|
|
let childOptions = {};
|
|
|
|
if (!!flags && flags.constructor === Object) {
|
|
Object.entries(flags).forEach(([key, value]) => {
|
|
if (CHILD_OPTIONS.indexOf(key) > -1) {
|
|
childOptions[key] = value;
|
|
return;
|
|
}
|
|
|
|
// No need to handle key when value is null or undefined.
|
|
if (value == null) {
|
|
return;
|
|
}
|
|
|
|
if (value === false) {
|
|
key = `no-${ key }`;
|
|
}
|
|
const values = Array.isArray(value)? value : [value];
|
|
values.forEach(value => {
|
|
args.push(`--${ key }`);
|
|
if (typeof value === "boolean") return;
|
|
if (typeof value === "string") {
|
|
args.push(`${ value }`);
|
|
} else {
|
|
args.push(`${ JSON.stringify(value) }`);
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
// Not a flag object, push it back.
|
|
args.push(flags);
|
|
}
|
|
|
|
return spawn(RCLONE_EXECUTABLE, args, childOptions);
|
|
}
|
|
|
|
// Promise-based API.
|
|
const promises = api.promises = function(...args) {
|
|
return new Promise((resolve, reject) => {
|
|
const subprocess = api(...args);
|
|
|
|
subprocess.on("error", (error) => {
|
|
reject(error);
|
|
});
|
|
|
|
const stdout = [], stderr = [];
|
|
subprocess.stdout.on("data", (chunk) => {
|
|
stdout.push(chunk);
|
|
});
|
|
subprocess.stdout.on("end", () => {
|
|
resolve(Buffer.concat(stdout));
|
|
});
|
|
subprocess.stderr.on("data", (chunk) => {
|
|
stderr.push(chunk);
|
|
});
|
|
subprocess.stderr.on("end", () => {
|
|
if (stderr.length) {
|
|
reject(Buffer.concat(stderr));
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
const COMMANDS = [
|
|
"about", // Get quota information from the remote.
|
|
"authorize", // Remote authorization.
|
|
"backend", // Run a backend specific command.
|
|
"cat", // Concatenates any files and sends them to stdout.
|
|
"check", // Checks the files in the source and destination match.
|
|
"checksum", // Checks the files in the source against a SUM file.
|
|
"cleanup", // Clean up the remote if possible.
|
|
"config", // Enter an interactive configuration session.
|
|
"config create", // Create a new remote with name, type and options.
|
|
"config delete", // Delete an existing remote name.
|
|
"config disconnect", // Disconnects user from remote
|
|
"config dump", // Dump the config file as JSON.
|
|
"config edit", // Enter an interactive configuration session.
|
|
"config file", // Show path of configuration file in use.
|
|
"config password", // Update password in an existing remote.
|
|
"config providers", // List in JSON format all the providers and options.
|
|
"config reconnect", // Re-authenticates user with remote.
|
|
"config show", // Print (decrypted) config file, or the config for a single remote.
|
|
"config update", // Update options in an existing remote.
|
|
"config userinfo", // Prints info about logged in user of remote.
|
|
"copy", // Copy files from source to dest, skipping already copied.
|
|
"copyto", // Copy files from source to dest, skipping already copied.
|
|
"copyurl", // Copy url content to dest.
|
|
"cryptcheck", // Cryptcheck checks the integrity of a crypted remote.
|
|
"cryptdecode", // Cryptdecode returns unencrypted file names.
|
|
"dedupe", // Interactively find duplicate filenames and delete/rename them.
|
|
"delete", // Remove the contents of path.
|
|
"deletefile", // Remove a single file from remote.
|
|
"genautocomplete", // Output completion script for a given shell.
|
|
"genautocomplete bash", // Output bash completion script for rclone.
|
|
"genautocomplete fish", // Output fish completion script for rclone.
|
|
"genautocomplete zsh", // Output zsh completion script for rclone.
|
|
"gendocs", // Output markdown docs for rclone to the directory supplied.
|
|
"hashsum", // Produces a hashsum file for all the objects in the path.
|
|
"help", // Show help for rclone commands, flags and backends.
|
|
"link", // Generate public link to file/folder.
|
|
"listremotes", // List all the remotes in the config file.
|
|
"ls", // List the objects in the path with size and path.
|
|
"lsd", // List all directories/containers/buckets in the path.
|
|
"lsf", // List directories and objects in remote:path formatted for parsing.
|
|
"lsjson", // List directories and objects in the path in JSON format.
|
|
"lsl", // List the objects in path with modification time, size and path.
|
|
"md5sum", // Produces an md5sum file for all the objects in the path.
|
|
"mkdir", // Make the path if it doesn't already exist.
|
|
"mount", // Mount the remote as file system on a mountpoint.
|
|
"move", // Move files from source to dest.
|
|
"moveto", // Move file or directory from source to dest.
|
|
"ncdu", // Explore a remote with a text based user interface.
|
|
"obscure", // Obscure password for use in the rclone config file.
|
|
"purge", // Remove the path and all of its contents.
|
|
"rc", // Run a command against a running rclone.
|
|
"rcat", // Copies standard input to file on remote.
|
|
"rcd", // Run rclone listening to remote control commands only.
|
|
"rmdir", // Remove the path if empty.
|
|
"rmdirs", // Remove empty directories under the path.
|
|
"selfupdate", // Update the rclone binary.
|
|
"serve", // Serve a remote over a protocol.
|
|
"serve dlna", // Serve remote:path over DLNA
|
|
"serve ftp", // Serve remote:path over FTP.
|
|
"serve http", // Serve the remote over HTTP.
|
|
"serve restic", // Serve the remote for restic's REST API.
|
|
"serve sftp", // Serve the remote over SFTP.
|
|
"serve webdav", // Serve remote:path over webdav.
|
|
"settier", // Changes storage class/tier of objects in remote.
|
|
"sha1sum", // Produces an sha1sum file for all the objects in the path.
|
|
"size", // Prints the total size and number of objects in remote:path.
|
|
"sync", // Make source and dest identical, modifying destination only.
|
|
"test", // Run a test command.
|
|
"touch", // Create new file or change file modification time.
|
|
"tree", // List the contents of the remote in a tree like fashion.
|
|
"version", // Show the version number.
|
|
];
|
|
|
|
COMMANDS.forEach(commandName => {
|
|
// Normal API command to return a subprocess.
|
|
Object.defineProperty(api, commandName, {
|
|
/**
|
|
* @param {...string|object} args arguments for the API call
|
|
* @returns {ChildProcess} the rclone subprocess.
|
|
*/
|
|
value: function(...args) {
|
|
return api(commandName, ...args);
|
|
},
|
|
enumerable: true,
|
|
});
|
|
|
|
// Promise API command to return a Promise.
|
|
Object.defineProperty(promises, commandName, {
|
|
/**
|
|
* @param {...string|object} args arguments for the API call
|
|
* @returns {Promise<string>} the output of the command.
|
|
*/
|
|
value: function(...args) {
|
|
return promises(commandName, ...args);
|
|
},
|
|
enumerable: true,
|
|
});
|
|
});
|
|
|
|
module.exports = api;
|