mirror of
https://github.com/rclone/rclone.git
synced 2024-12-02 05:23:47 +08:00
e43b5ce5e5
This is possible now that we no longer support go1.12 and brings rclone into line with standard practices in the Go world. This also removes errors.New and errors.Errorf from lib/errors and prefers the stdlib errors package over lib/errors.
147 lines
3.5 KiB
Go
147 lines
3.5 KiB
Go
// Rclone as a wasm library
|
|
//
|
|
// This library exports the core rc functionality
|
|
|
|
//go:build js
|
|
// +build js
|
|
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"runtime"
|
|
"syscall/js"
|
|
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/rc"
|
|
|
|
// Core functionality we need
|
|
_ "github.com/rclone/rclone/fs/operations"
|
|
_ "github.com/rclone/rclone/fs/sync"
|
|
|
|
// _ "github.com/rclone/rclone/backend/all" // import all backends
|
|
|
|
// Backends
|
|
_ "github.com/rclone/rclone/backend/memory"
|
|
)
|
|
|
|
var (
|
|
document js.Value
|
|
jsJSON js.Value
|
|
)
|
|
|
|
func getElementById(name string) js.Value {
|
|
node := document.Call("getElementById", name)
|
|
if node.IsUndefined() {
|
|
log.Fatalf("Couldn't find element %q", name)
|
|
}
|
|
return node
|
|
}
|
|
|
|
func time() int {
|
|
return js.Global().Get("Date").New().Call("getTime").Int()
|
|
}
|
|
|
|
func paramToValue(in rc.Params) (out js.Value) {
|
|
return js.Value{}
|
|
}
|
|
|
|
// errorValue turns an error into a js.Value
|
|
func errorValue(method string, in js.Value, err error) js.Value {
|
|
fs.Errorf(nil, "rc: %q: error: %v", method, err)
|
|
// Adjust the error return for some well known errors
|
|
status := http.StatusInternalServerError
|
|
switch {
|
|
case errors.Is(err, fs.ErrorDirNotFound) || errors.Is(err, fs.ErrorObjectNotFound):
|
|
status = http.StatusNotFound
|
|
case rc.IsErrParamInvalid(err) || rc.IsErrParamNotFound(err):
|
|
status = http.StatusBadRequest
|
|
}
|
|
return js.ValueOf(map[string]interface{}{
|
|
"status": status,
|
|
"error": err.Error(),
|
|
"input": in,
|
|
"path": method,
|
|
})
|
|
}
|
|
|
|
// rcCallback is a callback for javascript to access the api
|
|
//
|
|
// FIXME should this should return a promise so we can return errors properly?
|
|
func rcCallback(this js.Value, args []js.Value) interface{} {
|
|
ctx := context.Background() // FIXME
|
|
log.Printf("rcCallback: this=%v args=%v", this, args)
|
|
|
|
if len(args) != 2 {
|
|
return errorValue("", js.Undefined(), errors.New("need two parameters to rc call"))
|
|
}
|
|
method := args[0].String()
|
|
inRaw := args[1]
|
|
var in = rc.Params{}
|
|
switch inRaw.Type() {
|
|
case js.TypeNull:
|
|
case js.TypeObject:
|
|
inJSON := jsJSON.Call("stringify", inRaw).String()
|
|
err := json.Unmarshal([]byte(inJSON), &in)
|
|
if err != nil {
|
|
return errorValue(method, inRaw, fmt.Errorf("couldn't unmarshal input: %w", err))
|
|
}
|
|
default:
|
|
return errorValue(method, inRaw, errors.New("in parameter must be null or object"))
|
|
}
|
|
|
|
call := rc.Calls.Get(method)
|
|
if call == nil {
|
|
return errorValue(method, inRaw, fmt.Errorf("method %q not found", method))
|
|
}
|
|
|
|
out, err := call.Fn(ctx, in)
|
|
if err != nil {
|
|
return errorValue(method, inRaw, fmt.Errorf("method call failed: %w", err))
|
|
}
|
|
if out == nil {
|
|
return nil
|
|
}
|
|
var out2 map[string]interface{}
|
|
err = rc.Reshape(&out2, out)
|
|
if err != nil {
|
|
return errorValue(method, inRaw, fmt.Errorf("result reshape failed: %w", err))
|
|
}
|
|
|
|
return js.ValueOf(out2)
|
|
}
|
|
|
|
func main() {
|
|
log.Printf("Running on goos/goarch = %s/%s", runtime.GOOS, runtime.GOARCH)
|
|
if js.Global().IsUndefined() {
|
|
log.Fatalf("Didn't find Global - not running in browser")
|
|
}
|
|
document = js.Global().Get("document")
|
|
if document.IsUndefined() {
|
|
log.Fatalf("Didn't find document - not running in browser")
|
|
}
|
|
|
|
jsJSON = js.Global().Get("JSON")
|
|
if jsJSON.IsUndefined() {
|
|
log.Fatalf("can't find JSON")
|
|
}
|
|
|
|
// Set rc
|
|
js.Global().Set("rc", js.FuncOf(rcCallback))
|
|
|
|
// Signal that it is valid
|
|
rcValidResolve := js.Global().Get("rcValidResolve")
|
|
if rcValidResolve.IsUndefined() {
|
|
log.Fatalf("Didn't find rcValidResolve")
|
|
}
|
|
rcValidResolve.Invoke()
|
|
|
|
// Wait forever
|
|
select {}
|
|
}
|