2020-08-21 02:01:38 +08:00
|
|
|
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",
|
2021-08-16 17:30:01 +08:00
|
|
|
Help: `Allows listing of test plugins with the rclone.test set to true in package.json of the plugin.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes no parameters and returns:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- loadedTestPlugins - list of currently available test plugins.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
E.g.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/listTestPlugins
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func rcListTestPlugins(_ context.Context, _ rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
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",
|
2021-08-16 17:30:01 +08:00
|
|
|
Help: `This allows you to remove a plugin using it's name.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes the following parameters:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- name - name of the plugin in the format ` + "`author`/`plugin_name`" + `.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
Example:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/removeTestPlugin name=rclone/rclone-webui-react
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func rcRemoveTestPlugin(_ context.Context, in rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
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",
|
2021-08-16 17:30:01 +08:00
|
|
|
Help: `Used for adding a plugin to the webgui.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes the following parameters:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- url - http url of the github repo where the plugin is hosted (http://github.com/rclone/rclone-webui-react).
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
Example:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/addPlugin
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func rcAddPlugin(_ context.Context, in rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
pluginURL, err := in.GetString("url")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-08-14 10:56:32 +08:00
|
|
|
author, repoName, repoBranch, err := getAuthorRepoBranchGitHub(pluginURL)
|
2020-08-21 02:01:38 +08:00
|
|
|
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/<author>/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.
|
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes no parameters and returns:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- loadedPlugins - list of current production plugins.
|
|
|
|
- testPlugins - list of temporarily loaded development plugins, usually running on a different server.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
E.g.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/listPlugins
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func rcGetPlugins(_ context.Context, _ rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
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",
|
2021-08-16 17:30:01 +08:00
|
|
|
Help: `This allows you to remove a plugin using it's name.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes parameters:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- name - name of the plugin in the format ` + "`author`/`plugin_name`" + `.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
E.g.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/removePlugin name=rclone/video-plugin
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func rcRemovePlugin(_ context.Context, in rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
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",
|
2021-08-16 17:30:01 +08:00
|
|
|
Help: `This shows all possible plugins by a mime type.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
This takes the following parameters:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- 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).
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
Returns:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
- loadedPlugins - list of current production plugins.
|
|
|
|
- testPlugins - list of temporarily loaded development plugins, usually running on a different server.
|
2020-08-21 02:01:38 +08:00
|
|
|
|
2021-08-16 17:30:01 +08:00
|
|
|
Example:
|
2020-08-21 02:01:38 +08:00
|
|
|
|
|
|
|
rclone rc pluginsctl/getPluginsForType type=video/mp4
|
|
|
|
`,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func rcGetPluginsForType(_ context.Context, in rc.Params) (out rc.Params, err error) {
|
2020-09-18 03:06:51 +08:00
|
|
|
err = initPluginsOrError()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-08-21 02:01:38 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
}
|