🎉 Commit of go-promises
This commit is contained in:
commit
5d84d26c3a
13 changed files with 238 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.task/
|
||||
26
Taskfile.yml
Normal file
26
Taskfile.yml
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# https://taskfile.dev
|
||||
|
||||
version: '3'
|
||||
|
||||
tasks:
|
||||
wasm-compile:
|
||||
desc: "Compile wasm"
|
||||
sources:
|
||||
- '**/*go'
|
||||
generates:
|
||||
- internal/assets/app.wasm
|
||||
cmds:
|
||||
- GOOS=js GOARCH=wasm go build -o internal/assets/app.wasm ./internal/cmd/wasm/
|
||||
get-wasm-exec:
|
||||
desc: "Copies wasm_exec.js into internal/assets"
|
||||
generates:
|
||||
- internal/assets/wasm_exec.js
|
||||
cmds:
|
||||
- cp -v "$(go env GOROOT)"/misc/wasm/wasm_exec.js internal/assets/
|
||||
run-server:
|
||||
desc: "Run HTTP server"
|
||||
deps:
|
||||
- get-wasm-exec
|
||||
- wasm-compile
|
||||
cmds:
|
||||
- go run ./internal/cmd/server/
|
||||
10
errors.go
Normal file
10
errors.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package promises
|
||||
|
||||
import "syscall/js"
|
||||
|
||||
func GoErrorToJSError(err error) js.Value {
|
||||
if err == nil {
|
||||
return js.Null()
|
||||
}
|
||||
return NewGlobal("Error", err.Error())
|
||||
}
|
||||
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module codeberg.org/danjones000/go-promises
|
||||
|
||||
go 1.23.4
|
||||
5
internal/add.go
Normal file
5
internal/add.go
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
package internal
|
||||
|
||||
func Add(a, b int) int {
|
||||
return a + b
|
||||
}
|
||||
2
internal/assets/.gitignore
vendored
Normal file
2
internal/assets/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
app.wasm
|
||||
wasm_exec.js
|
||||
14
internal/assets/index.html
Normal file
14
internal/assets/index.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<script src="wasm_exec.js"></script>
|
||||
<script>
|
||||
const go = new Go();
|
||||
WebAssembly.instantiateStreaming(fetch("app.wasm"), go.importObject).then((result) => {
|
||||
go.run(result.instance);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
14
internal/cmd/server/main.go
Normal file
14
internal/cmd/server/main.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := http.ListenAndServe(":9090", http.FileServer(http.Dir("./internal/assets")))
|
||||
if err != nil {
|
||||
fmt.Println("Failed to start server", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
50
internal/cmd/wasm/main.go
Normal file
50
internal/cmd/wasm/main.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
promises "codeberg.org/danjones000/go-promises"
|
||||
"codeberg.org/danjones000/go-promises/internal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Some go")
|
||||
|
||||
js.Global().Set("add", promises.PromisifyGoFunc(func(_ js.Value, args []js.Value) (any, error) {
|
||||
if len(args) < 2 {
|
||||
return nil, errors.New("add called with too few arguments")
|
||||
}
|
||||
a := args[0]
|
||||
b := args[1]
|
||||
|
||||
if a.Type() != js.TypeNumber {
|
||||
return nil, fmt.Errorf("First argument must be a number. %s given", a.Type())
|
||||
}
|
||||
|
||||
if b.Type() != js.TypeNumber {
|
||||
return nil, fmt.Errorf("secong argument must be a number. %s given", b.Type())
|
||||
}
|
||||
|
||||
return internal.Add(a.Int(), b.Int()), nil
|
||||
}))
|
||||
|
||||
js.Global().Set("getUser", promises.PromisifyGoFunc(func(this js.Value, args []js.Value) (any, error) {
|
||||
if len(args) < 2 {
|
||||
return nil, errors.New("getUser called with too few arguments")
|
||||
}
|
||||
name := args[0]
|
||||
age := args[1]
|
||||
|
||||
if name.Type() != js.TypeString {
|
||||
return nil, fmt.Errorf("First argument must be a string. %s given", name.Type())
|
||||
}
|
||||
if age.Type() != js.TypeNumber {
|
||||
return nil, fmt.Errorf("Second argument must be a string. %s given", age.Type())
|
||||
}
|
||||
return internal.GetUser(name.String(), age.Int()), nil
|
||||
}))
|
||||
|
||||
<-make(chan struct{})
|
||||
}
|
||||
10
internal/struct.go
Normal file
10
internal/struct.go
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
package internal
|
||||
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
func GetUser(name string, age int) User {
|
||||
return User{name, age}
|
||||
}
|
||||
8
new.go
Normal file
8
new.go
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package promises
|
||||
|
||||
import "syscall/js"
|
||||
|
||||
func NewGlobal(thing string, args ...any) js.Value {
|
||||
newThing := js.Global().Get(thing)
|
||||
return newThing.New(args...)
|
||||
}
|
||||
28
promisify.go
Normal file
28
promisify.go
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package promises
|
||||
|
||||
import "syscall/js"
|
||||
|
||||
type JSWrapper func(this js.Value, args []js.Value) (any, error)
|
||||
|
||||
func PromisifyGoFunc(caller JSWrapper) js.Func {
|
||||
return js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||
return NewGlobal("Promise", js.FuncOf(func(_ js.Value, promArgs []js.Value) any {
|
||||
resolve := promArgs[0]
|
||||
reject := promArgs[1]
|
||||
go func() {
|
||||
val, err := caller(this, args)
|
||||
if err != nil {
|
||||
reject.Invoke(GoErrorToJSError(err))
|
||||
} else {
|
||||
jsVal, jsErr := ValueOf(val)
|
||||
if jsErr != nil {
|
||||
reject.Invoke(GoErrorToJSError(jsErr))
|
||||
} else {
|
||||
resolve.Invoke(jsVal)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}))
|
||||
})
|
||||
}
|
||||
67
value.go
Normal file
67
value.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
package promises
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
func ValueOf(val any) (js.Value, error) {
|
||||
switch v := val.(type) {
|
||||
case js.Value:
|
||||
return v, nil
|
||||
case js.Func:
|
||||
return js.ValueOf(v), nil
|
||||
case nil:
|
||||
return js.Null(), nil
|
||||
case bool:
|
||||
return js.ValueOf(v), nil
|
||||
case int:
|
||||
return js.ValueOf(v), nil
|
||||
case int8:
|
||||
return js.ValueOf(v), nil
|
||||
case int16:
|
||||
return js.ValueOf(v), nil
|
||||
case int32:
|
||||
return js.ValueOf(v), nil
|
||||
case int64:
|
||||
return js.ValueOf(v), nil
|
||||
case uint:
|
||||
return js.ValueOf(v), nil
|
||||
case uint8:
|
||||
return js.ValueOf(v), nil
|
||||
case uint16:
|
||||
return js.ValueOf(v), nil
|
||||
case uint32:
|
||||
return js.ValueOf(v), nil
|
||||
case uint64:
|
||||
return js.ValueOf(v), nil
|
||||
case float32:
|
||||
return js.ValueOf(v), nil
|
||||
case float64:
|
||||
return js.ValueOf(v), nil
|
||||
case string:
|
||||
return js.ValueOf(v), nil
|
||||
case []any:
|
||||
return js.ValueOf(v), nil
|
||||
case map[string]any:
|
||||
return js.ValueOf(v), nil
|
||||
case []byte:
|
||||
return js.ValueOf(string(v)), nil
|
||||
default:
|
||||
by, marshalErr := json.Marshal(val)
|
||||
if marshalErr == nil {
|
||||
m := make(map[string]any)
|
||||
unmarshallErr := json.Unmarshal(by, &m)
|
||||
if unmarshallErr == nil {
|
||||
return js.ValueOf(m), nil
|
||||
}
|
||||
s := []any{}
|
||||
unmarshallErr = json.Unmarshal(by, &s)
|
||||
if unmarshallErr == nil {
|
||||
return js.ValueOf(s), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return js.Value{}, fmt.Errorf("unable to create a JS value for %T", val)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue