Skip to content

Commit

Permalink
support iterator chan
Browse files Browse the repository at this point in the history
  • Loading branch information
zyxkad committed Jan 16, 2024
1 parent 1a80720 commit 601d96f
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 42 deletions.
6 changes: 5 additions & 1 deletion cmds/mcla_wasm/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ func fetchContext(ctx context.Context, url string, opts ...Map) (res *Response,
header.Set(v.Index(0).String(), v.Index(1).String())
return
})
var body io.Reader
if body, err = wrapJsValueAsReader(res0.Get("body")); err != nil {
return
}
res = &Response{
native: res0,
Status: res0.Get("statusText").String(),
StatusCode: res0.Get("status").Int(),
Body: readCloser{wrapJsValueAsReader(res0.Get("body"))},
Body: readCloser{body},
Type: res0.Get("type").String(),
Url: res0.Get("url").String(),
Header: header,
Expand Down
2 changes: 2 additions & 0 deletions cmds/mcla_wasm/js_globals.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ var (
global = js.Global()
// class
Object = global.Get("Object")
Reflect = global.Get("Reflect")
Symbol = global.Get("Symbol")
Promise = global.Get("Promise")
Uint8Array = global.Get("Uint8Array")
ReadableStream = global.Get("ReadableStream")
Expand Down
58 changes: 33 additions & 25 deletions cmds/mcla_wasm/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//go:build tinygo.wasm

package main

import (
Expand All @@ -22,16 +20,16 @@ func createBackgroundCtx() (bgCtx context.Context) {
func getAPI() (m Map) {
return Map{
"version": version,
"parseCrashReport": asyncFuncOf(func(_ js.Value, args []js.Value) (res any) {
return asJsValue(parseCrashReport(args))
"parseCrashReport": asyncFuncOf(func(_ js.Value, args []js.Value) (res any, err error) {
return parseCrashReport(args)
}),
"parseLogErrors": asyncFuncOf(func(_ js.Value, args []js.Value) (res any) {
return asJsValue(parseLogErrors(args))
"parseLogErrors": asyncFuncOf(func(_ js.Value, args []js.Value) (res any, err error) {
return parseLogErrors(args)
}),
"analyzeLogErrors": asyncFuncOf(func(_ js.Value, args []js.Value) (res any) {
"analyzeLogErrors": asyncFuncOf(func(_ js.Value, args []js.Value) (res any, err error) {
return analyzeLogErrors(args)
}),
"analyzeLogErrorsIter": asyncFuncOf(func(_ js.Value, args []js.Value) (res any) {
"analyzeLogErrorsIter": asyncFuncOf(func(_ js.Value, args []js.Value) (res any, err error) {
return analyzeLogErrorsIter(args)
}),
"setGhDbPrefix": js.FuncOf(func(_ js.Value, args []js.Value) (res any) {
Expand Down Expand Up @@ -66,46 +64,56 @@ func main() {
<-bgCtx.Done()
}

func parseCrashReport(args []js.Value) (report *CrashReport) {
func parseCrashReport(args []js.Value) (report *CrashReport, err error) {
value := args[0]
r := wrapJsValueAsReader(value)
var err error
r, err := wrapJsValueAsReader(value)
if err != nil {
return
}
if report, err = ParseCrashReport(r); err != nil {
if err == io.EOF { // Couldn't find crash report, return null
return nil
if err == io.EOF {
// Couldn't find crash report, return null
return nil, nil
}
panic(err)
return
}
return
}

func parseLogErrors(args []js.Value) (errs []*JavaError) {
func parseLogErrors(args []js.Value) (errs []*JavaError, err error) {
value := args[0]
r := wrapJsValueAsReader(value)
var err error
if errs, err = ScanJavaErrors(r); err != nil {
panic(err)
r, err := wrapJsValueAsReader(value)
if err != nil {
return
}
return
return ScanJavaErrors(r)
}

func analyzeLogErrors(args []js.Value) (result []*ErrorResult) {
r := wrapJsValueAsReader(args[0])
func analyzeLogErrors(args []js.Value) (result []*ErrorResult, err error) {
value := args[0]
r, err := wrapJsValueAsReader(value)
if err != nil {
return
}
result = make([]*ErrorResult, 0, 5)
resCh, ctx := defaultAnalyzer.DoLogStream(bgCtx, r)
for {
select {
case res := <-resCh:
result = append(result, res)
case <-ctx.Done():
panic(context.Cause(ctx))
return nil, context.Cause(ctx)
}
}
return
}

func analyzeLogErrorsIter(args []js.Value) (iterator js.Value) {
r := wrapJsValueAsReader(args[0])
func analyzeLogErrorsIter(args []js.Value) (iterator js.Value, err error) {
value := args[0]
r, err := wrapJsValueAsReader(value)
if err != nil {
return
}
result, ctx := defaultAnalyzer.DoLogStream(bgCtx, r)
iterator = NewChannelIteratorContext(ctx, result)
return
Expand Down
43 changes: 27 additions & 16 deletions cmds/mcla_wasm/utils.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//go:build tinygo.wasm

package main

import (
"context"
"encoding/json"
"fmt"
"io"
"reflect"
"strings"
Expand Down Expand Up @@ -66,21 +65,29 @@ var _emptyIterNextFn = (func() js.Func {

func NewChannelIteratorContext[T any](ctx context.Context, ch <-chan T) (iter js.Value) {
iter = GoChannelIterator.New()
var nextMethod js.Func
nextMethod = asyncFuncOf(func(this js.Value, args []js.Value) (res any) {
var nextMethod, symAsyncItor js.Func
nextMethod = asyncFuncOf(func(this js.Value, args []js.Value) (res any, err error) {
select {
case <-ctx.Done():
panic(context.Cause(ctx))
iter.Set("next", _emptyIterNextFn)
nextMethod.Release()
symAsyncItor.Release()
return nil, context.Cause(ctx)
case val, ok := <-ch:
if !ok {
iter.Set("next", _emptyIterNextFn)
nextMethod.Release()
return Map{"done": true, "value": nil}
symAsyncItor.Release()
return Map{"done": true, "value": nil}, nil
}
return Map{"done": false, "value": val}
return Map{"done": false, "value": val}, nil
}
})
symAsyncItor = js.FuncOf(func(this js.Value, args []js.Value) (res any) {
return iter
})
iter.Set("next", nextMethod)
Reflect.Call("set", iter, Symbol.Get("asyncIterator"), symAsyncItor)
return
}

Expand Down Expand Up @@ -161,26 +168,25 @@ func (r readableStreamDefaultReaderWrapper) Close() (err error) {
return
}

func wrapJsValueAsReader(value js.Value) (r io.Reader) {
func wrapJsValueAsReader(value js.Value) (r io.Reader, err error) {
switch value.Type() {
case js.TypeString:
return strings.NewReader(value.String())
return strings.NewReader(value.String()), nil
case js.TypeObject:
if value.InstanceOf(Uint8Array) {
return io.NewSectionReader(uint8ArrayReader{value}, 0, (1<<63)-1)
return io.NewSectionReader(uint8ArrayReader{value}, 0, (1<<63)-1), nil
}
if value.InstanceOf(ReadableStream) {
value = value.Call("getReader" /*, Map{ "mode": "byob" } TODO*/)
}
if value.InstanceOf(ReadableStreamDefaultReader) {
return readableStreamDefaultReaderWrapper{value: value}
return readableStreamDefaultReaderWrapper{value: value}, nil
}
// if value.InstanceOf(ReadableStreamBYOBReader) { // TODO
// return readableStreamBYOBReaderWrapper{ value }
// }
}
panic("Unexpect value type " + value.Type().String())
return
return nil, fmt.Errorf("Unexpect value type %s", value.Type())
}

// have to ensure the argument is a really JS Promise instance
Expand Down Expand Up @@ -225,7 +231,9 @@ func awaitPromise(promise js.Value) (res js.Value, err error) {
return awaitPromiseContext(bgCtx, promise)
}

func asyncFuncOf(fn func(this js.Value, args []js.Value) (res any)) js.Func {
type asyncFuncSignature = func(this js.Value, args []js.Value) (res any, err error)

func asyncFuncOf(fn asyncFuncSignature) js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) (res any) {
var resolve, reject js.Value
pcb := js.FuncOf(func(_ js.Value, args []js.Value) (res any) {
Expand All @@ -246,8 +254,11 @@ func asyncFuncOf(fn func(this js.Value, args []js.Value) (res any)) js.Func {
}
}
}()
res := fn(this, args)
resolve.Invoke(asJsValue(res))
if res, err := fn(this, args); err != nil {
reject.Invoke(err.Error())
} else {
resolve.Invoke(asJsValue(res))
}
}()
return
})
Expand Down

0 comments on commit 601d96f

Please sign in to comment.