From 47970e0051afeb5bf7fab523845b3d17bde9f148 Mon Sep 17 00:00:00 2001 From: arzumify Date: Sat, 26 Oct 2024 17:05:29 +0100 Subject: [PATCH] Added the vice-versa conversions; you can now translate io.Readers into JS streams. --- main.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++--- tests/main.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 448dff5..47261d5 100644 --- a/main.go +++ b/main.go @@ -39,11 +39,12 @@ func (r *ReadableStream) Read(p []byte) (n int, err error) { readResult.Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} { defer waitGroup.Done() + if args[0].Get("done").Bool() || args[0].Get("value").Length() == 0 { + err = io.EOF + return nil + } data := args[0].Get("value") js.CopyBytesToGo(p, data) - if args[0].Get("done").Bool() { - err = io.EOF - } n = data.Length() return nil })) @@ -162,3 +163,51 @@ func NewWritableStream(stream ...js.Value) *WritableStream { return &WritableStream{stream: stream} } } + +// Now we do the vice versa: Reader to ReadableStream and Writer to WritableStream. + +// ReaderToReadableStream converts an io.Reader to a JavaScript ReadableStream. +func ReaderToReadableStream(r io.Reader) js.Value { + return js.Global().Get("ReadableStream").New(map[string]interface{}{ + "pull": js.FuncOf(func(this js.Value, args []js.Value) interface{} { + readController := args[0] + return js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, args []js.Value) interface{} { + var buffer []byte + buffer, err := io.ReadAll(r) + if err != nil { + panic(err.Error()) + } + if len(buffer) == 0 { + readController.Call("close") + return nil + } + jsBuffer := js.Global().Get("Uint8Array").New(len(buffer)) + js.CopyBytesToJS(jsBuffer, buffer) + readController.Call("enqueue", jsBuffer) + readController.Call("close") + args[0].Invoke() + return nil + })) + }), + "type": "bytes", + }) +} + +// WriterToWritableStream converts an io.Writer to a JavaScript WritableStream. +func WriterToWritableStream(w io.Writer) js.Value { + return js.Global().Get("WritableStream").New(map[string]interface{}{ + "write": js.FuncOf(func(this js.Value, args []js.Value) interface{} { + writeBuffer := args[0] + return js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, args []js.Value) interface{} { + buffer := make([]byte, writeBuffer.Length()) + js.CopyBytesToGo(buffer, writeBuffer) + _, err := w.Write(buffer) + if err != nil { + panic(err.Error()) + } + args[0].Invoke() + return nil + })) + }), + }) +} diff --git a/tests/main.go b/tests/main.go index 0fc7ada..0c34e89 100644 --- a/tests/main.go +++ b/tests/main.go @@ -1,11 +1,9 @@ package main import ( - "git.ailur.dev/ailur/jsStreams" - "fmt" + "git.ailur.dev/ailur/jsStreams" "io" - "syscall/js" ) @@ -41,5 +39,57 @@ func main() { return nil })) + js.Global().Set("TryWriterConversions", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + go func() { + reader, writer := io.Pipe() + go func() { + writeStream := jsStreams.WriterToWritableStream(writer) + buffer := js.Global().Get("Uint8Array").New(45) + js.CopyBytesToJS(buffer, []byte("Hi, I've been piped through a WritableStream!")) + writeStream.Call("getWriter").Call("write", buffer).Call("then", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + go func() { + err := writer.Close() + if err != nil { + fmt.Println(err) + } + }() + return nil + })) + }() + go func() { + fmt.Println("Reading stream...") + m, _ := io.ReadAll(reader) + fmt.Println(string(m)) + }() + }() + + return nil + })) + + js.Global().Set("TryReaderConversions", js.FuncOf(func(this js.Value, args []js.Value) interface{} { + go func() { + reader, writer := io.Pipe() + go func() { + _, err := writer.Write([]byte("Hi, I've been piped through a ReadableStream!")) + if err != nil { + fmt.Println(err) + return + } + err = writer.Close() + if err != nil { + fmt.Println(err) + return + } + }() + go func() { + fmt.Println("Reading stream...") + m, _ := io.ReadAll(jsStreams.NewReadableStream(jsStreams.ReaderToReadableStream(reader))) + fmt.Println(string(m)) + }() + }() + + return nil + })) + select {} }