mirror of
https://github.com/syumai/workers.git
synced 2025-03-10 17:29:11 +00:00
move Reqeust / Response / ResponseWriterBuffer to jsutil
This commit is contained in:
parent
8bb44582c5
commit
cd154341ff
@ -47,14 +47,14 @@ func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) {
|
|||||||
if httpHandler == nil {
|
if httpHandler == nil {
|
||||||
return js.Value{}, fmt.Errorf("Serve must be called before handleRequest.")
|
return js.Value{}, fmt.Errorf("Serve must be called before handleRequest.")
|
||||||
}
|
}
|
||||||
req, err := toRequest(reqObj)
|
req, err := jsutil.ToRequest(reqObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
ctx := runtimecontext.New(context.Background(), runtimeCtxObj)
|
ctx := runtimecontext.New(context.Background(), runtimeCtxObj)
|
||||||
req = req.WithContext(ctx)
|
req = req.WithContext(ctx)
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
w := &responseWriterBuffer{
|
w := &jsutil.ResponseWriterBuffer{
|
||||||
header: http.Header{},
|
header: http.Header{},
|
||||||
statusCode: http.StatusOK,
|
statusCode: http.StatusOK,
|
||||||
reader: reader,
|
reader: reader,
|
||||||
@ -66,7 +66,7 @@ func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) {
|
|||||||
defer writer.Close()
|
defer writer.Close()
|
||||||
httpHandler.ServeHTTP(w, req)
|
httpHandler.ServeHTTP(w, req)
|
||||||
}()
|
}()
|
||||||
return toJSResponse(w)
|
return jsutil.ToJSResponse(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server serves http.Handler on Cloudflare Workers.
|
// Server serves http.Handler on Cloudflare Workers.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package workers
|
package jsutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
@ -7,24 +7,22 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
|
|
||||||
"github.com/syumai/workers/internal/jsutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// toBody converts JavaScripts sides ReadableStream (can be null) to io.ReadCloser.
|
// ToBody converts JavaScripts sides ReadableStream (can be null) to io.ReadCloser.
|
||||||
// - ReadableStream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
|
// - ReadableStream: https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
|
||||||
func toBody(streamOrNull js.Value) io.ReadCloser {
|
func ToBody(streamOrNull js.Value) io.ReadCloser {
|
||||||
if streamOrNull.IsNull() {
|
if streamOrNull.IsNull() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
sr := streamOrNull.Call("getReader")
|
sr := streamOrNull.Call("getReader")
|
||||||
return io.NopCloser(jsutil.ConvertStreamReaderToReader(sr))
|
return io.NopCloser(ConvertStreamReaderToReader(sr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// toHeader converts JavaScript sides Headers to http.Header.
|
// ToHeader converts JavaScript sides Headers to http.Header.
|
||||||
// - Headers: https://developer.mozilla.org/ja/docs/Web/API/Headers
|
// - Headers: https://developer.mozilla.org/ja/docs/Web/API/Headers
|
||||||
func toHeader(headers js.Value) http.Header {
|
func ToHeader(headers js.Value) http.Header {
|
||||||
entries := jsutil.ArrayFrom(headers.Call("entries"))
|
entries := ArrayFrom(headers.Call("entries"))
|
||||||
headerLen := entries.Length()
|
headerLen := entries.Length()
|
||||||
h := http.Header{}
|
h := http.Header{}
|
||||||
for i := 0; i < headerLen; i++ {
|
for i := 0; i < headerLen; i++ {
|
||||||
@ -38,14 +36,14 @@ func toHeader(headers js.Value) http.Header {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// toRequest converts JavaScript sides Request to *http.Request.
|
// ToRequest converts JavaScript sides Request to *http.Request.
|
||||||
// - Request: https://developer.mozilla.org/ja/docs/Web/API/Request
|
// - Request: https://developer.mozilla.org/ja/docs/Web/API/Request
|
||||||
func toRequest(req js.Value) (*http.Request, error) {
|
func ToRequest(req js.Value) (*http.Request, error) {
|
||||||
reqUrl, err := url.Parse(req.Get("url").String())
|
reqUrl, err := url.Parse(req.Get("url").String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
header := toHeader(req.Get("headers"))
|
header := ToHeader(req.Get("headers"))
|
||||||
|
|
||||||
// ignore err
|
// ignore err
|
||||||
contentLength, _ := strconv.ParseInt(header.Get("Content-Length"), 10, 64)
|
contentLength, _ := strconv.ParseInt(header.Get("Content-Length"), 10, 64)
|
||||||
@ -53,7 +51,7 @@ func toRequest(req js.Value) (*http.Request, error) {
|
|||||||
Method: req.Get("method").String(),
|
Method: req.Get("method").String(),
|
||||||
URL: reqUrl,
|
URL: reqUrl,
|
||||||
Header: header,
|
Header: header,
|
||||||
Body: toBody(req.Get("body")),
|
Body: ToBody(req.Get("body")),
|
||||||
ContentLength: contentLength,
|
ContentLength: contentLength,
|
||||||
TransferEncoding: strings.Split(header.Get("Transfer-Encoding"), ","),
|
TransferEncoding: strings.Split(header.Get("Transfer-Encoding"), ","),
|
||||||
Host: header.Get("Host"),
|
Host: header.Get("Host"),
|
30
internal/jsutil/response.go
Normal file
30
internal/jsutil/response.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package jsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"syscall/js"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToJSHeader(header http.Header) js.Value {
|
||||||
|
h := HeadersClass.New()
|
||||||
|
for key, values := range header {
|
||||||
|
for _, value := range values {
|
||||||
|
h.Call("append", key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToJSResponse(w *ResponseWriterBuffer) (js.Value, error) {
|
||||||
|
<-w.readyCh // wait until ready
|
||||||
|
status := w.statusCode
|
||||||
|
if status == 0 {
|
||||||
|
status = http.StatusOK
|
||||||
|
}
|
||||||
|
respInit := NewObject()
|
||||||
|
respInit.Set("status", status)
|
||||||
|
respInit.Set("statusText", http.StatusText(status))
|
||||||
|
respInit.Set("headers", ToJSHeader(w.Header()))
|
||||||
|
readableStream := ConvertReaderToReadableStream(w.reader)
|
||||||
|
return ResponseClass.New(readableStream, respInit), nil
|
||||||
|
}
|
38
internal/jsutil/responsewriter.go
Normal file
38
internal/jsutil/responsewriter.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package jsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResponseWriterBuffer struct {
|
||||||
|
header http.Header
|
||||||
|
statusCode int
|
||||||
|
reader *io.PipeReader
|
||||||
|
writer *io.PipeWriter
|
||||||
|
readyCh chan struct{}
|
||||||
|
once sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ http.ResponseWriter = &ResponseWriterBuffer{}
|
||||||
|
|
||||||
|
// ready indicates that ResponseWriterBuffer is ready to be converted to Response.
|
||||||
|
func (w *ResponseWriterBuffer) ready() {
|
||||||
|
w.once.Do(func() {
|
||||||
|
close(w.readyCh)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *ResponseWriterBuffer) Write(data []byte) (n int, err error) {
|
||||||
|
w.ready()
|
||||||
|
return w.writer.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *ResponseWriterBuffer) Header() http.Header {
|
||||||
|
return w.header
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *ResponseWriterBuffer) WriteHeader(statusCode int) {
|
||||||
|
w.statusCode = statusCode
|
||||||
|
}
|
32
response.go
32
response.go
@ -1,32 +0,0 @@
|
|||||||
package workers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"syscall/js"
|
|
||||||
|
|
||||||
"github.com/syumai/workers/internal/jsutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func toJSHeader(header http.Header) js.Value {
|
|
||||||
h := jsutil.HeadersClass.New()
|
|
||||||
for key, values := range header {
|
|
||||||
for _, value := range values {
|
|
||||||
h.Call("append", key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
func toJSResponse(w *responseWriterBuffer) (js.Value, error) {
|
|
||||||
<-w.readyCh // wait until ready
|
|
||||||
status := w.statusCode
|
|
||||||
if status == 0 {
|
|
||||||
status = http.StatusOK
|
|
||||||
}
|
|
||||||
respInit := jsutil.NewObject()
|
|
||||||
respInit.Set("status", status)
|
|
||||||
respInit.Set("statusText", http.StatusText(status))
|
|
||||||
respInit.Set("headers", toJSHeader(w.Header()))
|
|
||||||
readableStream := jsutil.ConvertReaderToReadableStream(w.reader)
|
|
||||||
return jsutil.ResponseClass.New(readableStream, respInit), nil
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package workers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type responseWriterBuffer struct {
|
|
||||||
header http.Header
|
|
||||||
statusCode int
|
|
||||||
reader *io.PipeReader
|
|
||||||
writer *io.PipeWriter
|
|
||||||
readyCh chan struct{}
|
|
||||||
once sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ http.ResponseWriter = &responseWriterBuffer{}
|
|
||||||
|
|
||||||
// ready indicates that responseWriterBuffer is ready to be converted to Response.
|
|
||||||
func (w *responseWriterBuffer) ready() {
|
|
||||||
w.once.Do(func() {
|
|
||||||
close(w.readyCh)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *responseWriterBuffer) Write(data []byte) (n int, err error) {
|
|
||||||
w.ready()
|
|
||||||
return w.writer.Write(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *responseWriterBuffer) Header() http.Header {
|
|
||||||
return w.header
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *responseWriterBuffer) WriteHeader(statusCode int) {
|
|
||||||
w.statusCode = statusCode
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user