mirror of
https://github.com/syumai/workers.git
synced 2025-03-10 17:29:11 +00:00
add runtime context
This commit is contained in:
parent
0e499ad79c
commit
9e87698fac
@ -1,10 +1,12 @@
|
||||
package cloudflare
|
||||
|
||||
import "github.com/syumai/workers/internal/jsutil"
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// Getenv gets a value of an environment variable.
|
||||
// - https://developers.cloudflare.com/workers/platform/environment-variables/
|
||||
// - Technically, this function is just an alias for js.Global().Get(env_name).String().
|
||||
func Getenv(name string) string {
|
||||
return jsutil.Global.Get(name).String()
|
||||
// - This function panics when a runtime context is not found.
|
||||
func Getenv(ctx context.Context, name string) string {
|
||||
return getRuntimeContextEnv(ctx).Get(name).String()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
@ -17,9 +18,10 @@ type KVNamespace struct {
|
||||
|
||||
// NewKVNamespace returns KVNamespace for given variable name.
|
||||
// - variable name must be defined in wrangler.toml as kv_namespace's binding.
|
||||
// - if the given variable name doesn't exist on Global object, returns error.
|
||||
func NewKVNamespace(varName string) (*KVNamespace, error) {
|
||||
inst := js.Global().Get(varName)
|
||||
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||
// - This function panics when a runtime context is not found.
|
||||
func NewKVNamespace(ctx context.Context, varName string) (*KVNamespace, error) {
|
||||
inst := getRuntimeContextEnv(ctx).Get(varName)
|
||||
if inst.IsUndefined() {
|
||||
return nil, fmt.Errorf("%s is undefined", varName)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"syscall/js"
|
||||
@ -18,9 +19,10 @@ type R2Bucket struct {
|
||||
// NewR2Bucket returns R2Bucket for given variable name.
|
||||
// - variable name must be defined in wrangler.toml.
|
||||
// - see example: https://github.com/syumai/workers/tree/main/examples/r2-image-viewer
|
||||
// - if the given variable name doesn't exist on Global object, returns error.
|
||||
func NewR2Bucket(varName string) (*R2Bucket, error) {
|
||||
inst := js.Global().Get(varName)
|
||||
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||
// - This function panics when a runtime context is not found.
|
||||
func NewR2Bucket(ctx context.Context, varName string) (*R2Bucket, error) {
|
||||
inst := getRuntimeContextEnv(ctx).Get(varName)
|
||||
if inst.IsUndefined() {
|
||||
return nil, fmt.Errorf("%s is undefined", varName)
|
||||
}
|
||||
|
35
cloudflare/runtimecontext.go
Normal file
35
cloudflare/runtimecontext.go
Normal file
@ -0,0 +1,35 @@
|
||||
package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/internal/runtimecontext"
|
||||
)
|
||||
|
||||
/**
|
||||
* The type definition of RuntimeContext for Cloudflare Worker expects:
|
||||
* ```ts
|
||||
* type RuntimeContext {
|
||||
* env: Env;
|
||||
* ctx: ExecutionContext;
|
||||
* }
|
||||
* ```
|
||||
* This type is based on the type definition of ExportedHandlerFetchHandler.
|
||||
* - see: https://github.com/cloudflare/workers-types/blob/c8d9533caa4415c2156d2cf1daca75289d01ae70/index.d.ts#LL564
|
||||
*/
|
||||
|
||||
// getRuntimeContextEnv gets object which holds environment variables bound to Cloudflare worker.
|
||||
// - see: https://github.com/cloudflare/workers-types/blob/c8d9533caa4415c2156d2cf1daca75289d01ae70/index.d.ts#L566
|
||||
func getRuntimeContextEnv(ctx context.Context) js.Value {
|
||||
runtimeCtxValue := runtimecontext.MustExtract(ctx)
|
||||
return runtimeCtxValue.Get("env")
|
||||
}
|
||||
|
||||
// getExecutionContext gets ExecutionContext object from context.
|
||||
// - see: https://github.com/cloudflare/workers-types/blob/c8d9533caa4415c2156d2cf1daca75289d01ae70/index.d.ts#L567
|
||||
// - see also: https://github.com/cloudflare/workers-types/blob/c8d9533caa4415c2156d2cf1daca75289d01ae70/index.d.ts#L554
|
||||
func getExecutionContext(ctx context.Context) js.Value {
|
||||
runtimeCtxValue := runtimecontext.MustExtract(ctx)
|
||||
return runtimeCtxValue.Get("ctx")
|
||||
}
|
15
handler.go
15
handler.go
@ -1,12 +1,14 @@
|
||||
package workers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/syumai/workers/internal/jsutil"
|
||||
"github.com/syumai/workers/internal/runtimecontext"
|
||||
)
|
||||
|
||||
var httpHandler http.Handler
|
||||
@ -14,15 +16,20 @@ var httpHandler http.Handler
|
||||
func init() {
|
||||
var handleRequestCallback js.Func
|
||||
handleRequestCallback = js.FuncOf(func(this js.Value, args []js.Value) any {
|
||||
if len(args) != 1 {
|
||||
if len(args) > 2 {
|
||||
panic(fmt.Errorf("too many args given to handleRequest: %d", len(args)))
|
||||
}
|
||||
reqObj := args[0]
|
||||
runtimeCtxObj := js.Null()
|
||||
if len(args) > 1 {
|
||||
runtimeCtxObj = args[1]
|
||||
}
|
||||
var cb js.Func
|
||||
cb = js.FuncOf(func(_ js.Value, pArgs []js.Value) any {
|
||||
defer cb.Release()
|
||||
resolve := pArgs[0]
|
||||
go func() {
|
||||
res, err := handleRequest(args[0])
|
||||
res, err := handleRequest(reqObj, runtimeCtxObj)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -36,7 +43,7 @@ func init() {
|
||||
}
|
||||
|
||||
// handleRequest accepts a Request object and returns Response object.
|
||||
func handleRequest(reqObj js.Value) (js.Value, error) {
|
||||
func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) {
|
||||
if httpHandler == nil {
|
||||
return js.Value{}, fmt.Errorf("Serve must be called before handleRequest.")
|
||||
}
|
||||
@ -44,6 +51,8 @@ func handleRequest(reqObj js.Value) (js.Value, error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx := runtimecontext.New(context.Background(), runtimeCtxObj)
|
||||
req = req.WithContext(ctx)
|
||||
reader, writer := io.Pipe()
|
||||
w := &responseWriterBuffer{
|
||||
header: http.Header{},
|
||||
|
25
internal/runtimecontext/context.go
Normal file
25
internal/runtimecontext/context.go
Normal file
@ -0,0 +1,25 @@
|
||||
package runtimecontext
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"syscall/js"
|
||||
)
|
||||
|
||||
type runtimeCtxKey struct{}
|
||||
|
||||
func New(ctx context.Context, runtimeCtxObj js.Value) context.Context {
|
||||
return context.WithValue(ctx, runtimeCtxKey{}, runtimeCtxObj)
|
||||
}
|
||||
|
||||
var ErrRuntimeContextNotFound = errors.New("runtime context was not found")
|
||||
|
||||
// MustExtract extracts runtime context object from context.
|
||||
// This function panics when runtime context object was not found.
|
||||
func MustExtract(ctx context.Context) js.Value {
|
||||
v, ok := ctx.Value(runtimeCtxKey{}).(js.Value)
|
||||
if !ok {
|
||||
panic(ErrRuntimeContextNotFound)
|
||||
}
|
||||
return v
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user