-
-
Notifications
You must be signed in to change notification settings - Fork 4k
/
main.go
146 lines (124 loc) · 3.47 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// 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 {}
}