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
|
package cloudflare
|
||||||
|
|
||||||
import "github.com/syumai/workers/internal/jsutil"
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
// Getenv gets a value of an environment variable.
|
// Getenv gets a value of an environment variable.
|
||||||
// - https://developers.cloudflare.com/workers/platform/environment-variables/
|
// - https://developers.cloudflare.com/workers/platform/environment-variables/
|
||||||
// - Technically, this function is just an alias for js.Global().Get(env_name).String().
|
// - This function panics when a runtime context is not found.
|
||||||
func Getenv(name string) string {
|
func Getenv(ctx context.Context, name string) string {
|
||||||
return jsutil.Global.Get(name).String()
|
return getRuntimeContextEnv(ctx).Get(name).String()
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cloudflare
|
package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
@ -17,9 +18,10 @@ type KVNamespace struct {
|
|||||||
|
|
||||||
// NewKVNamespace returns KVNamespace for given variable name.
|
// NewKVNamespace returns KVNamespace for given variable name.
|
||||||
// - variable name must be defined in wrangler.toml as kv_namespace's binding.
|
// - 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.
|
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||||
func NewKVNamespace(varName string) (*KVNamespace, error) {
|
// - This function panics when a runtime context is not found.
|
||||||
inst := js.Global().Get(varName)
|
func NewKVNamespace(ctx context.Context, varName string) (*KVNamespace, error) {
|
||||||
|
inst := getRuntimeContextEnv(ctx).Get(varName)
|
||||||
if inst.IsUndefined() {
|
if inst.IsUndefined() {
|
||||||
return nil, fmt.Errorf("%s is undefined", varName)
|
return nil, fmt.Errorf("%s is undefined", varName)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package cloudflare
|
package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
@ -18,9 +19,10 @@ type R2Bucket struct {
|
|||||||
// NewR2Bucket returns R2Bucket for given variable name.
|
// NewR2Bucket returns R2Bucket for given variable name.
|
||||||
// - variable name must be defined in wrangler.toml.
|
// - variable name must be defined in wrangler.toml.
|
||||||
// - see example: https://github.com/syumai/workers/tree/main/examples/r2-image-viewer
|
// - 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.
|
// - if the given variable name doesn't exist on runtime context, returns error.
|
||||||
func NewR2Bucket(varName string) (*R2Bucket, error) {
|
// - This function panics when a runtime context is not found.
|
||||||
inst := js.Global().Get(varName)
|
func NewR2Bucket(ctx context.Context, varName string) (*R2Bucket, error) {
|
||||||
|
inst := getRuntimeContextEnv(ctx).Get(varName)
|
||||||
if inst.IsUndefined() {
|
if inst.IsUndefined() {
|
||||||
return nil, fmt.Errorf("%s is undefined", varName)
|
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
|
package workers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"syscall/js"
|
"syscall/js"
|
||||||
|
|
||||||
"github.com/syumai/workers/internal/jsutil"
|
"github.com/syumai/workers/internal/jsutil"
|
||||||
|
"github.com/syumai/workers/internal/runtimecontext"
|
||||||
)
|
)
|
||||||
|
|
||||||
var httpHandler http.Handler
|
var httpHandler http.Handler
|
||||||
@ -14,15 +16,20 @@ var httpHandler http.Handler
|
|||||||
func init() {
|
func init() {
|
||||||
var handleRequestCallback js.Func
|
var handleRequestCallback js.Func
|
||||||
handleRequestCallback = js.FuncOf(func(this js.Value, args []js.Value) any {
|
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)))
|
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
|
var cb js.Func
|
||||||
cb = js.FuncOf(func(_ js.Value, pArgs []js.Value) any {
|
cb = js.FuncOf(func(_ js.Value, pArgs []js.Value) any {
|
||||||
defer cb.Release()
|
defer cb.Release()
|
||||||
resolve := pArgs[0]
|
resolve := pArgs[0]
|
||||||
go func() {
|
go func() {
|
||||||
res, err := handleRequest(args[0])
|
res, err := handleRequest(reqObj, runtimeCtxObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@ -36,7 +43,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleRequest accepts a Request object and returns Response object.
|
// 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 {
|
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.")
|
||||||
}
|
}
|
||||||
@ -44,6 +51,8 @@ func handleRequest(reqObj js.Value) (js.Value, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
ctx := runtimecontext.New(context.Background(), runtimeCtxObj)
|
||||||
|
req = req.WithContext(ctx)
|
||||||
reader, writer := io.Pipe()
|
reader, writer := io.Pipe()
|
||||||
w := &responseWriterBuffer{
|
w := &responseWriterBuffer{
|
||||||
header: http.Header{},
|
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