package webgui import ( "context" "fmt" "os" "path/filepath" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/rc" ) func init() { rc.Add(rc.Call{ Path: "pluginsctl/listTestPlugins", AuthRequired: true, Fn: rcListTestPlugins, Title: "Show currently loaded test plugins", Help: `Allows listing of test plugins with the rclone.test set to true in package.json of the plugin. This takes no parameters and returns: - loadedTestPlugins - list of currently available test plugins. E.g. rclone rc pluginsctl/listTestPlugins `, }) } func rcListTestPlugins(_ context.Context, _ rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } return rc.Params{ "loadedTestPlugins": filterPlugins(loadedPlugins, func(json *PackageJSON) bool { return json.isTesting() }), }, nil } func init() { rc.Add(rc.Call{ Path: "pluginsctl/removeTestPlugin", AuthRequired: true, Fn: rcRemoveTestPlugin, Title: "Remove a test plugin", Help: `This allows you to remove a plugin using it's name. This takes the following parameters: - name - name of the plugin in the format ` + "`author`/`plugin_name`" + `. Example: rclone rc pluginsctl/removeTestPlugin name=rclone/rclone-webui-react `, }) } func rcRemoveTestPlugin(_ context.Context, in rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } name, err := in.GetString("name") if err != nil { return nil, err } err = loadedPlugins.removePlugin(name) if err != nil { return nil, err } return nil, nil } func init() { rc.Add(rc.Call{ Path: "pluginsctl/addPlugin", AuthRequired: true, Fn: rcAddPlugin, Title: "Add a plugin using url", Help: `Used for adding a plugin to the webgui. This takes the following parameters: - url - http url of the github repo where the plugin is hosted (http://github.com/rclone/rclone-webui-react). Example: rclone rc pluginsctl/addPlugin `, }) } func rcAddPlugin(_ context.Context, in rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } pluginURL, err := in.GetString("url") if err != nil { return nil, err } author, repoName, repoBranch, err := getAuthorRepoBranchGithub(pluginURL) if err != nil { return nil, err } branch, err := in.GetString("branch") if err != nil || branch == "" { branch = repoBranch } version, err := in.GetString("version") if err != nil || version == "" { version = "latest" } err = CreatePathIfNotExist(PluginsPath) if err != nil { return nil, err } // fetch and package.json // https://raw.githubusercontent.com/rclone/rclone-webui-react/master/package.json pluginID := fmt.Sprintf("%s/%s", author, repoName) currentPluginPath := filepath.Join(PluginsPath, pluginID) err = CreatePathIfNotExist(currentPluginPath) if err != nil { return nil, err } packageJSONUrl := fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/%s/package.json", author, repoName, branch) packageJSONFilePath := filepath.Join(currentPluginPath, "package.json") err = DownloadFile(packageJSONFilePath, packageJSONUrl) if err != nil { return nil, err } // register in plugins // download release and save in plugins//repo-name/app // https://api.github.com/repos/rclone/rclone-webui-react/releases/latest releaseURL, tag, _, err := GetLatestReleaseURL(fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/%s", author, repoName, version)) if err != nil { return nil, err } zipName := tag + ".zip" zipPath := filepath.Join(currentPluginPath, zipName) err = DownloadFile(zipPath, releaseURL) if err != nil { return nil, err } extractPath := filepath.Join(currentPluginPath, "app") err = CreatePathIfNotExist(extractPath) if err != nil { return nil, err } err = os.RemoveAll(extractPath) if err != nil { fs.Logf(nil, "No previous downloads to remove") } fs.Logf(nil, "Unzipping plugin binary") err = Unzip(zipPath, extractPath) if err != nil { return nil, err } err = loadedPlugins.addPlugin(pluginID, packageJSONFilePath) if err != nil { return nil, err } return nil, nil } func init() { rc.Add(rc.Call{ Path: "pluginsctl/listPlugins", AuthRequired: true, Fn: rcGetPlugins, Title: "Get the list of currently loaded plugins", Help: `This allows you to get the currently enabled plugins and their details. This takes no parameters and returns: - loadedPlugins - list of current production plugins. - testPlugins - list of temporarily loaded development plugins, usually running on a different server. E.g. rclone rc pluginsctl/listPlugins `, }) } func rcGetPlugins(_ context.Context, _ rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } err = loadedPlugins.readFromFile() if err != nil { return nil, err } return rc.Params{ "loadedPlugins": filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { return !packageJSON.isTesting() }), "loadedTestPlugins": filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { return packageJSON.isTesting() }), }, nil } func init() { rc.Add(rc.Call{ Path: "pluginsctl/removePlugin", AuthRequired: true, Fn: rcRemovePlugin, Title: "Remove a loaded plugin", Help: `This allows you to remove a plugin using it's name. This takes parameters: - name - name of the plugin in the format ` + "`author`/`plugin_name`" + `. E.g. rclone rc pluginsctl/removePlugin name=rclone/video-plugin `, }) } func rcRemovePlugin(_ context.Context, in rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } name, err := in.GetString("name") if err != nil { return nil, err } err = loadedPlugins.removePlugin(name) if err != nil { return nil, err } return nil, nil } func init() { rc.Add(rc.Call{ Path: "pluginsctl/getPluginsForType", AuthRequired: true, Fn: rcGetPluginsForType, Title: "Get plugins with type criteria", Help: `This shows all possible plugins by a mime type. This takes the following parameters: - type - supported mime type by a loaded plugin e.g. (video/mp4, audio/mp3). - pluginType - filter plugins based on their type e.g. (DASHBOARD, FILE_HANDLER, TERMINAL). Returns: - loadedPlugins - list of current production plugins. - testPlugins - list of temporarily loaded development plugins, usually running on a different server. Example: rclone rc pluginsctl/getPluginsForType type=video/mp4 `, }) } func rcGetPluginsForType(_ context.Context, in rc.Params) (out rc.Params, err error) { err = initPluginsOrError() if err != nil { return nil, err } handlesType, err := in.GetString("type") if err != nil { handlesType = "" } pluginType, err := in.GetString("pluginType") if err != nil { pluginType = "" } var loadedPluginsResult map[string]PackageJSON var loadedTestPluginsResult map[string]PackageJSON if pluginType == "" || pluginType == "FileHandler" { loadedPluginsResult = filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { for i := range packageJSON.Rclone.HandlesType { if packageJSON.Rclone.HandlesType[i] == handlesType && !packageJSON.Rclone.Test { return true } } return false }) loadedTestPluginsResult = filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { for i := range packageJSON.Rclone.HandlesType { if packageJSON.Rclone.HandlesType[i] == handlesType && packageJSON.Rclone.Test { return true } } return false }) } else { loadedPluginsResult = filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { return packageJSON.Rclone.PluginType == pluginType && !packageJSON.isTesting() }) loadedTestPluginsResult = filterPlugins(loadedPlugins, func(packageJSON *PackageJSON) bool { return packageJSON.Rclone.PluginType == pluginType && packageJSON.isTesting() }) } return rc.Params{ "loadedPlugins": loadedPluginsResult, "loadedTestPlugins": loadedTestPluginsResult, }, nil }