From bac0abd44ba48a888bc9f249ca7c02bf9bf0daeb Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:19:04 +0900 Subject: [PATCH 01/13] R: rename runtimecontext to cfcontext --- cloudflare/cron/cron.go | 3 +-- cloudflare/internal/cfruntimecontext/cfruntimecontext.go | 4 +--- handler.go | 3 +-- internal/{runtimecontext => cfcontext}/context.go | 2 +- 4 files changed, 4 insertions(+), 8 deletions(-) rename internal/{runtimecontext => cfcontext}/context.go (96%) diff --git a/cloudflare/cron/cron.go b/cloudflare/cron/cron.go index 9f6d6e1..aa6c279 100644 --- a/cloudflare/cron/cron.go +++ b/cloudflare/cron/cron.go @@ -8,7 +8,6 @@ import ( "time" "github.com/syumai/workers/internal/jsutil" - "github.com/syumai/workers/internal/runtimecontext" ) // Event represents information about the Cron that invoked this worker. @@ -42,7 +41,7 @@ func ScheduleTask(task Task) { } func runScheduler(eventObj js.Value, runtimeCtxObj js.Value) error { - ctx := runtimecontext.New(context.Background(), runtimeCtxObj) + ctx := cfcontext.New(context.Background(), runtimeCtxObj) event, err := toEvent(eventObj) if err != nil { return err diff --git a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go index 731190d..41e7ea6 100644 --- a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go +++ b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go @@ -4,8 +4,6 @@ import ( "context" "errors" "syscall/js" - - "github.com/syumai/workers/internal/runtimecontext" ) /** @@ -49,7 +47,7 @@ var ErrValueNotFound = errors.New("execution context value for specified key not // GetRuntimeContextValue gets value for specified key from RuntimeContext. // - if the value is undefined, return error. func GetRuntimeContextValue(ctx context.Context, key string) (js.Value, error) { - runtimeCtxValue := runtimecontext.MustExtract(ctx) + runtimeCtxValue := cfcontext.MustExtract(ctx) v := runtimeCtxValue.Get(key) if v.IsUndefined() { return js.Value{}, ErrValueNotFound diff --git a/handler.go b/handler.go index d1d732c..396a166 100644 --- a/handler.go +++ b/handler.go @@ -9,7 +9,6 @@ import ( "github.com/syumai/workers/internal/jshttp" "github.com/syumai/workers/internal/jsutil" - "github.com/syumai/workers/internal/runtimecontext" ) var httpHandler http.Handler @@ -49,7 +48,7 @@ func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) { if err != nil { panic(err) } - ctx := runtimecontext.New(context.Background(), runtimeCtxObj) + ctx := cfcontext.New(context.Background(), runtimeCtxObj) req = req.WithContext(ctx) reader, writer := io.Pipe() w := &jshttp.ResponseWriter{ diff --git a/internal/runtimecontext/context.go b/internal/cfcontext/context.go similarity index 96% rename from internal/runtimecontext/context.go rename to internal/cfcontext/context.go index aed2463..b14b168 100644 --- a/internal/runtimecontext/context.go +++ b/internal/cfcontext/context.go @@ -1,4 +1,4 @@ -package runtimecontext +package cfcontext import ( "context" From cdd8a26c53392c122b3a4a6f4e3028646c9ae452 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:21:34 +0900 Subject: [PATCH 02/13] F: add incoming property context --- .../cfruntimecontext/cfruntimecontext.go | 4 +++- handler.go | 3 ++- internal/cfcontext/context.go | 22 +++++++++++++++---- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go index 41e7ea6..6371e78 100644 --- a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go +++ b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go @@ -4,6 +4,8 @@ import ( "context" "errors" "syscall/js" + + "github.com/syumai/workers/internal/cfcontext" ) /** @@ -47,7 +49,7 @@ var ErrValueNotFound = errors.New("execution context value for specified key not // GetRuntimeContextValue gets value for specified key from RuntimeContext. // - if the value is undefined, return error. func GetRuntimeContextValue(ctx context.Context, key string) (js.Value, error) { - runtimeCtxValue := cfcontext.MustExtract(ctx) + runtimeCtxValue := cfcontext.MustExtractRuntimeContext(ctx) v := runtimeCtxValue.Get(key) if v.IsUndefined() { return js.Value{}, ErrValueNotFound diff --git a/handler.go b/handler.go index 396a166..d607d8a 100644 --- a/handler.go +++ b/handler.go @@ -7,6 +7,7 @@ import ( "net/http" "syscall/js" + "github.com/syumai/workers/internal/cfcontext" "github.com/syumai/workers/internal/jshttp" "github.com/syumai/workers/internal/jsutil" ) @@ -48,7 +49,7 @@ func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) { if err != nil { panic(err) } - ctx := cfcontext.New(context.Background(), runtimeCtxObj) + ctx := cfcontext.New(context.Background(), runtimeCtxObj, reqObj.Get("cf")) req = req.WithContext(ctx) reader, writer := io.Pipe() w := &jshttp.ResponseWriter{ diff --git a/internal/cfcontext/context.go b/internal/cfcontext/context.go index b14b168..d2da914 100644 --- a/internal/cfcontext/context.go +++ b/internal/cfcontext/context.go @@ -7,19 +7,33 @@ import ( ) type runtimeCtxKey struct{} +type incomingPropertyKey struct{} -func New(ctx context.Context, runtimeCtxObj js.Value) context.Context { - return context.WithValue(ctx, runtimeCtxKey{}, runtimeCtxObj) +func New(ctx context.Context, runtimeCtxObj, incomingPropertyObj js.Value) context.Context { + ctx = context.WithValue(ctx, runtimeCtxKey{}, runtimeCtxObj) + ctx = context.WithValue(ctx, incomingPropertyKey{}, incomingPropertyObj) + return ctx } var ErrRuntimeContextNotFound = errors.New("runtime context was not found") +var ErrIncomingPropertyNotFound = errors.New("incoming property was not found") -// MustExtract extracts runtime context object from context. +// MustExtractRuntimeContext extracts runtime context object from context. // This function panics when runtime context object was not found. -func MustExtract(ctx context.Context) js.Value { +func MustExtractRuntimeContext(ctx context.Context) js.Value { v, ok := ctx.Value(runtimeCtxKey{}).(js.Value) if !ok { panic(ErrRuntimeContextNotFound) } return v } + +// MustExtractIncomingProperty extracts incoming property object from context. +// This function panics when incoming property object was not found. +func MustExtractIncomingProperty(ctx context.Context) js.Value { + v, ok := ctx.Value(incomingPropertyKey{}).(js.Value) + if !ok { + panic(ErrIncomingPropertyNotFound) + } + return v +} From bb2644d33fa4df6612e684b4ed0b6dbfe3f6202a Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:36:37 +0900 Subject: [PATCH 03/13] F: add incoming property pkg --- cloudflare/incoming/property.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 cloudflare/incoming/property.go diff --git a/cloudflare/incoming/property.go b/cloudflare/incoming/property.go new file mode 100644 index 0000000..4e2055f --- /dev/null +++ b/cloudflare/incoming/property.go @@ -0,0 +1,18 @@ +package incoming + +import ( + "context" + + "github.com/syumai/workers/internal/cfcontext" +) + +type Properties struct { + AsOrganization string +} + +func NewProperties(ctx context.Context) *Properties { + obj := cfcontext.MustExtractIncomingProperty(ctx) + return &Properties{ + AsOrganization: obj.Get("asOrganization").String(), + } +} From e5294f4cd28e27316cec188cae58fabb2647f89f Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:46:44 +0900 Subject: [PATCH 04/13] F: add incoming property example --- _examples/incoming/.gitignore | 3 +++ _examples/incoming/Makefile | 12 ++++++++++++ _examples/incoming/go.mod | 7 +++++++ _examples/incoming/go.sum | 2 ++ _examples/incoming/main.go | 20 ++++++++++++++++++++ _examples/incoming/wrangler.toml | 9 +++++++++ 6 files changed, 53 insertions(+) create mode 100644 _examples/incoming/.gitignore create mode 100644 _examples/incoming/Makefile create mode 100644 _examples/incoming/go.mod create mode 100644 _examples/incoming/go.sum create mode 100644 _examples/incoming/main.go create mode 100644 _examples/incoming/wrangler.toml diff --git a/_examples/incoming/.gitignore b/_examples/incoming/.gitignore new file mode 100644 index 0000000..aee7b7e --- /dev/null +++ b/_examples/incoming/.gitignore @@ -0,0 +1,3 @@ +build +node_modules +.wrangler diff --git a/_examples/incoming/Makefile b/_examples/incoming/Makefile new file mode 100644 index 0000000..019492c --- /dev/null +++ b/_examples/incoming/Makefile @@ -0,0 +1,12 @@ +.PHONY: dev +dev: + wrangler dev + +.PHONY: build +build: + go run ../../cmd/workers-assets-gen + tinygo build -o ./build/app.wasm -target wasm -no-debug ./... + +.PHONY: deploy +deploy: + wrangler deploy diff --git a/_examples/incoming/go.mod b/_examples/incoming/go.mod new file mode 100644 index 0000000..d698bb5 --- /dev/null +++ b/_examples/incoming/go.mod @@ -0,0 +1,7 @@ +module github.com/syumai/workers/_examples/hello + +go 1.21.3 + +require github.com/syumai/workers v0.0.0 + +replace github.com/syumai/workers => ../../ diff --git a/_examples/incoming/go.sum b/_examples/incoming/go.sum new file mode 100644 index 0000000..8c27871 --- /dev/null +++ b/_examples/incoming/go.sum @@ -0,0 +1,2 @@ +github.com/syumai/workers v0.1.0 h1:z5QfQR2X+PCKzom7RodpI5J4D5YF7NT7Qwzb9AM9dgY= +github.com/syumai/workers v0.1.0/go.mod h1:alXIDhTyeTwSzh0ZgQ3cb9HQPyyYfIejupE4Z3efr14= diff --git a/_examples/incoming/main.go b/_examples/incoming/main.go new file mode 100644 index 0000000..9b8c6f6 --- /dev/null +++ b/_examples/incoming/main.go @@ -0,0 +1,20 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/syumai/workers" + "github.com/syumai/workers/cloudflare/incoming" +) + +func main() { + handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + p := incoming.NewProperties(req.Context()) + + buf, _ := json.Marshal(p) + fmt.Fprintf(w, "%s", string(buf)) + }) + workers.Serve(handler) +} diff --git a/_examples/incoming/wrangler.toml b/_examples/incoming/wrangler.toml new file mode 100644 index 0000000..5c85632 --- /dev/null +++ b/_examples/incoming/wrangler.toml @@ -0,0 +1,9 @@ +name = "incoming" +main = "./build/worker.mjs" +compatibility_date = "2022-05-13" +compatibility_flags = [ + "streams_enable_constructors" +] + +[build] +command = "make build" From 46459b445ad1d0be59e014b62cf35aee65ede8e7 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:52:16 +0900 Subject: [PATCH 05/13] R: fix --- cloudflare/cron/cron.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cloudflare/cron/cron.go b/cloudflare/cron/cron.go index aa6c279..b8c3959 100644 --- a/cloudflare/cron/cron.go +++ b/cloudflare/cron/cron.go @@ -7,6 +7,7 @@ import ( "syscall/js" "time" + "github.com/syumai/workers/internal/cfcontext" "github.com/syumai/workers/internal/jsutil" ) @@ -41,7 +42,7 @@ func ScheduleTask(task Task) { } func runScheduler(eventObj js.Value, runtimeCtxObj js.Value) error { - ctx := cfcontext.New(context.Background(), runtimeCtxObj) + ctx := cfcontext.New(context.Background(), runtimeCtxObj, nil) event, err := toEvent(eventObj) if err != nil { return err From b0d246c23b96a0f263df26453a141c8e284575c6 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Wed, 17 Jan 2024 17:55:58 +0900 Subject: [PATCH 06/13] T: fix test error --- cloudflare/cron/cron.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudflare/cron/cron.go b/cloudflare/cron/cron.go index b8c3959..923f62a 100644 --- a/cloudflare/cron/cron.go +++ b/cloudflare/cron/cron.go @@ -42,7 +42,7 @@ func ScheduleTask(task Task) { } func runScheduler(eventObj js.Value, runtimeCtxObj js.Value) error { - ctx := cfcontext.New(context.Background(), runtimeCtxObj, nil) + ctx := cfcontext.New(context.Background(), runtimeCtxObj, js.Value{}) event, err := toEvent(eventObj) if err != nil { return err From 7f9e061a7e62c35f9c3740afec42bd14c4718fd3 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:43:17 +0900 Subject: [PATCH 07/13] F: complete implementation --- _examples/incoming/main.go | 8 +- cloudflare/incoming/property.go | 145 +++++++++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 4 deletions(-) diff --git a/_examples/incoming/main.go b/_examples/incoming/main.go index 9b8c6f6..c07adad 100644 --- a/_examples/incoming/main.go +++ b/_examples/incoming/main.go @@ -13,8 +13,12 @@ func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { p := incoming.NewProperties(req.Context()) - buf, _ := json.Marshal(p) - fmt.Fprintf(w, "%s", string(buf)) + encoder := json.NewEncoder(w) + w.Header().Set("Content-Type", "application/json") + if err := encoder.Encode(p); err != nil { + http.Error(w, fmt.Sprintf("Error encoding JSON: %v", err), http.StatusInternalServerError) + return + } }) workers.Serve(handler) } diff --git a/cloudflare/incoming/property.go b/cloudflare/incoming/property.go index 4e2055f..b7e4abc 100644 --- a/cloudflare/incoming/property.go +++ b/cloudflare/incoming/property.go @@ -2,17 +2,158 @@ package incoming import ( "context" + "syscall/js" "github.com/syumai/workers/internal/cfcontext" + "github.com/syumai/workers/internal/jsutil" ) +type BotManagementJsDetection struct { + Passed bool +} + +func NewBotManagementJsDetection(obj js.Value) *BotManagementJsDetection { + if obj.IsUndefined() { + return nil + } + return &BotManagementJsDetection{ + Passed: obj.Get("passed").Bool(), + } +} + +type BotManagement struct { + CorporateProxy bool + VerifiedBot bool + JsDetection *BotManagementJsDetection + StaticResource bool + Score int +} + +func NewBotManagement(obj js.Value) *BotManagement { + if obj.IsUndefined() { + return nil + } + return &BotManagement{ + CorporateProxy: obj.Get("corporateProxy").Bool(), + VerifiedBot: obj.Get("verifiedBot").Bool(), + JsDetection: NewBotManagementJsDetection(obj.Get("jsDetection")), + StaticResource: obj.Get("staticResource").Bool(), + Score: obj.Get("score").Int(), + } +} + +type TLSClientAuth struct { + CertIssuerDNLegacy string + CertIssuerSKI string + CertSubjectDNRFC2253 string + CertSubjectDNLegacy string + CertFingerprintSHA256 string + CertNotBefore string + CertSKI string + CertSerial string + CertIssuerDN string + CertVerified string + CertNotAfter string + CertSubjectDN string + CertPresented string + CertRevoked string + CertIssuerSerial string + CertIssuerDNRFC2253 string + CertFingerprintSHA1 string +} + +func NewTLSClientAuth(obj js.Value) *TLSClientAuth { + if obj.IsUndefined() { + return nil + } + return &TLSClientAuth{ + CertIssuerDNLegacy: jsutil.MaybeString(obj.Get("certIssuerDNLegacy")), + CertIssuerSKI: jsutil.MaybeString(obj.Get("certIssuerSKI")), + CertSubjectDNRFC2253: jsutil.MaybeString(obj.Get("certSubjectDNRFC2253")), + CertSubjectDNLegacy: jsutil.MaybeString(obj.Get("certSubjectDNLegacy")), + CertFingerprintSHA256: jsutil.MaybeString(obj.Get("certFingerprintSHA256")), + CertNotBefore: jsutil.MaybeString(obj.Get("certNotBefore")), + CertSKI: jsutil.MaybeString(obj.Get("certSKI")), + CertSerial: jsutil.MaybeString(obj.Get("certSerial")), + CertIssuerDN: jsutil.MaybeString(obj.Get("certIssuerDN")), + CertVerified: jsutil.MaybeString(obj.Get("certVerified")), + CertNotAfter: jsutil.MaybeString(obj.Get("certNotAfter")), + CertSubjectDN: jsutil.MaybeString(obj.Get("certSubjectDN")), + CertPresented: jsutil.MaybeString(obj.Get("certPresented")), + CertRevoked: jsutil.MaybeString(obj.Get("certRevoked")), + CertIssuerSerial: jsutil.MaybeString(obj.Get("certIssuerSerial")), + CertIssuerDNRFC2253: jsutil.MaybeString(obj.Get("certIssuerDNRFC2253")), + CertFingerprintSHA1: jsutil.MaybeString(obj.Get("certFingerprintSHA1")), + } +} + +type TLSExportedAuthenticator struct { + ClientFinished string + ClientHandshake string + ServerHandshake string + ServerFinished string +} + +func NewTLSExportedAuthenticator(obj js.Value) *TLSExportedAuthenticator { + if obj.IsUndefined() { + return nil + } + return &TLSExportedAuthenticator{ + ClientFinished: jsutil.MaybeString(obj.Get("clientFinished")), + ClientHandshake: jsutil.MaybeString(obj.Get("clientHandshake")), + ServerHandshake: jsutil.MaybeString(obj.Get("serverHandshake")), + ServerFinished: jsutil.MaybeString(obj.Get("serverFinished")), + } +} + type Properties struct { - AsOrganization string + Longitude string + Latitude string + TlsCipher string + Continent string + Asn int + ClientAcceptEncoding string + Country string + TLSClientAuth *TLSClientAuth + TLSExportedAuthenticator *TLSExportedAuthenticator + TlsVersion string + Colo string + Timezone string + City string + VerifiedBotCategory string + // EdgeRequestKeepAliveStatus int + RequestPriority string `json:""` + HttpProtocol string `json:""` + Region string `json:"region"` + RegionCode string `json:"regionCode"` + AsOrganization string `json:"asOrganization"` + PostalCode string `json:"postalCode"` + BotManagement *BotManagement } func NewProperties(ctx context.Context) *Properties { obj := cfcontext.MustExtractIncomingProperty(ctx) return &Properties{ - AsOrganization: obj.Get("asOrganization").String(), + Longitude: jsutil.MaybeString(obj.Get("longitude")), + Latitude: jsutil.MaybeString(obj.Get("latitude")), + TlsCipher: jsutil.MaybeString(obj.Get("tlsCipher")), + Continent: jsutil.MaybeString(obj.Get("continent")), + Asn: obj.Get("asn").Int(), + ClientAcceptEncoding: jsutil.MaybeString(obj.Get("clientAcceptEncoding")), + Country: jsutil.MaybeString(obj.Get("country")), + TLSClientAuth: NewTLSClientAuth(obj.Get("tlsClientAuth")), + TLSExportedAuthenticator: NewTLSExportedAuthenticator(obj.Get("tlsExportedAuthenticator")), + TlsVersion: obj.Get("tlsVersion").String(), + Colo: obj.Get("colo").String(), + Timezone: obj.Get("timezone").String(), + City: jsutil.MaybeString(obj.Get("city")), + VerifiedBotCategory: jsutil.MaybeString(obj.Get("verifiedBotCategory")), + RequestPriority: jsutil.MaybeString(obj.Get("requestPriority")), + HttpProtocol: obj.Get("httpProtocol").String(), + Region: jsutil.MaybeString(obj.Get("region")), + RegionCode: jsutil.MaybeString(obj.Get("regionCode")), + AsOrganization: obj.Get("asOrganization").String(), + PostalCode: jsutil.MaybeString(obj.Get("postalCode")), + BotManagement: NewBotManagement(obj.Get("botManagement")), } } From 4035675827b94921d894038dfc1ef29d0021f2d9 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:46:50 +0900 Subject: [PATCH 08/13] R: remove json tag --- cloudflare/incoming/property.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cloudflare/incoming/property.go b/cloudflare/incoming/property.go index b7e4abc..4a76530 100644 --- a/cloudflare/incoming/property.go +++ b/cloudflare/incoming/property.go @@ -122,12 +122,12 @@ type Properties struct { City string VerifiedBotCategory string // EdgeRequestKeepAliveStatus int - RequestPriority string `json:""` - HttpProtocol string `json:""` - Region string `json:"region"` - RegionCode string `json:"regionCode"` - AsOrganization string `json:"asOrganization"` - PostalCode string `json:"postalCode"` + RequestPriority string + HttpProtocol string + Region string + RegionCode string + AsOrganization string + PostalCode string BotManagement *BotManagement } From 2eb402014f636604846fe0ec12b1b67e14bedfc9 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Mon, 22 Jan 2024 21:29:39 +0900 Subject: [PATCH 09/13] R: refactor context --- .../cfruntimecontext/cfruntimecontext.go | 6 +-- handler.go | 4 +- internal/cfcontext/context.go | 39 ------------------- internal/runtimecontext/context.go | 37 ++++++++++++++++++ 4 files changed, 42 insertions(+), 44 deletions(-) delete mode 100644 internal/cfcontext/context.go create mode 100644 internal/runtimecontext/context.go diff --git a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go index 6371e78..b36d9cc 100644 --- a/cloudflare/internal/cfruntimecontext/cfruntimecontext.go +++ b/cloudflare/internal/cfruntimecontext/cfruntimecontext.go @@ -5,7 +5,7 @@ import ( "errors" "syscall/js" - "github.com/syumai/workers/internal/cfcontext" + "github.com/syumai/workers/internal/runtimecontext" ) /** @@ -49,8 +49,8 @@ var ErrValueNotFound = errors.New("execution context value for specified key not // GetRuntimeContextValue gets value for specified key from RuntimeContext. // - if the value is undefined, return error. func GetRuntimeContextValue(ctx context.Context, key string) (js.Value, error) { - runtimeCtxValue := cfcontext.MustExtractRuntimeContext(ctx) - v := runtimeCtxValue.Get(key) + runtimeObj := runtimecontext.MustExtractRuntimeObj(ctx) + v := runtimeObj.Get(key) if v.IsUndefined() { return js.Value{}, ErrValueNotFound } diff --git a/handler.go b/handler.go index d607d8a..87398bb 100644 --- a/handler.go +++ b/handler.go @@ -7,9 +7,9 @@ import ( "net/http" "syscall/js" - "github.com/syumai/workers/internal/cfcontext" "github.com/syumai/workers/internal/jshttp" "github.com/syumai/workers/internal/jsutil" + "github.com/syumai/workers/internal/runtimecontext" ) var httpHandler http.Handler @@ -49,7 +49,7 @@ func handleRequest(reqObj js.Value, runtimeCtxObj js.Value) (js.Value, error) { if err != nil { panic(err) } - ctx := cfcontext.New(context.Background(), runtimeCtxObj, reqObj.Get("cf")) + ctx := runtimecontext.New(context.Background(), reqObj, runtimeCtxObj) req = req.WithContext(ctx) reader, writer := io.Pipe() w := &jshttp.ResponseWriter{ diff --git a/internal/cfcontext/context.go b/internal/cfcontext/context.go deleted file mode 100644 index d2da914..0000000 --- a/internal/cfcontext/context.go +++ /dev/null @@ -1,39 +0,0 @@ -package cfcontext - -import ( - "context" - "errors" - "syscall/js" -) - -type runtimeCtxKey struct{} -type incomingPropertyKey struct{} - -func New(ctx context.Context, runtimeCtxObj, incomingPropertyObj js.Value) context.Context { - ctx = context.WithValue(ctx, runtimeCtxKey{}, runtimeCtxObj) - ctx = context.WithValue(ctx, incomingPropertyKey{}, incomingPropertyObj) - return ctx -} - -var ErrRuntimeContextNotFound = errors.New("runtime context was not found") -var ErrIncomingPropertyNotFound = errors.New("incoming property was not found") - -// MustExtractRuntimeContext extracts runtime context object from context. -// This function panics when runtime context object was not found. -func MustExtractRuntimeContext(ctx context.Context) js.Value { - v, ok := ctx.Value(runtimeCtxKey{}).(js.Value) - if !ok { - panic(ErrRuntimeContextNotFound) - } - return v -} - -// MustExtractIncomingProperty extracts incoming property object from context. -// This function panics when incoming property object was not found. -func MustExtractIncomingProperty(ctx context.Context) js.Value { - v, ok := ctx.Value(incomingPropertyKey{}).(js.Value) - if !ok { - panic(ErrIncomingPropertyNotFound) - } - return v -} diff --git a/internal/runtimecontext/context.go b/internal/runtimecontext/context.go new file mode 100644 index 0000000..288e0cd --- /dev/null +++ b/internal/runtimecontext/context.go @@ -0,0 +1,37 @@ +package runtimecontext + +import ( + "context" + "syscall/js" +) + +type ( + contextKeyTriggerObj struct{} + contextKeyRuntimeObj struct{} +) + +func New(ctx context.Context, triggerObj, runtimeObj js.Value) context.Context { + ctx = context.WithValue(ctx, contextKeyTriggerObj{}, triggerObj) + ctx = context.WithValue(ctx, contextKeyRuntimeObj{}, runtimeObj) + return ctx +} + +// MustExtractTriggerObj extracts trigger object from context. +// This function panics when trigger object was not found. +func MustExtractTriggerObj(ctx context.Context) js.Value { + v, ok := ctx.Value(contextKeyTriggerObj{}).(js.Value) + if !ok { + panic("trigger object was not found") + } + return v +} + +// MustExtractRuntimeObj extracts runtime object from context. +// This function panics when runtime object was not found. +func MustExtractRuntimeObj(ctx context.Context) js.Value { + v, ok := ctx.Value(contextKeyRuntimeObj{}).(js.Value) + if !ok { + panic("runtime object was not found") + } + return v +} From a067e8e0b81e5fe6cd46a955d5747500e66899dc Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:06:54 +0900 Subject: [PATCH 10/13] R: refactor cron with new runtimecontext --- _examples/cron/main.go | 13 +++--- _examples/cron/wrangler.toml | 3 -- cloudflare/cron/cron.go | 82 ------------------------------------ cloudflare/cron/event.go | 28 ++++++++++++ cloudflare/cron/scheduler.go | 58 +++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 92 deletions(-) delete mode 100644 cloudflare/cron/cron.go create mode 100644 cloudflare/cron/event.go create mode 100644 cloudflare/cron/scheduler.go diff --git a/_examples/cron/main.go b/_examples/cron/main.go index 0b01bf5..73c3ec9 100644 --- a/_examples/cron/main.go +++ b/_examples/cron/main.go @@ -2,20 +2,19 @@ package main import ( "context" - "errors" "fmt" - "github.com/syumai/workers/cloudflare" "github.com/syumai/workers/cloudflare/cron" ) -func task(ctx context.Context, event *cron.Event) error { - fmt.Println(cloudflare.Getenv(ctx, "HELLO")) - - if event.ScheduledTime.Minute()%2 == 0 { - return errors.New("even numbers cause errors") +func task(ctx context.Context) error { + e, err := cron.NewEvent(ctx) + if err != nil { + return err } + fmt.Println(e.ScheduledTime.Unix()) + return nil } diff --git a/_examples/cron/wrangler.toml b/_examples/cron/wrangler.toml index c6d714e..e09dddd 100644 --- a/_examples/cron/wrangler.toml +++ b/_examples/cron/wrangler.toml @@ -3,9 +3,6 @@ main = "./build/worker.mjs" compatibility_date = "2023-02-24" workers_dev = false -[vars] -HELLO = "hello, world!" - [triggers] crons = ["* * * * *"] diff --git a/cloudflare/cron/cron.go b/cloudflare/cron/cron.go deleted file mode 100644 index 923f62a..0000000 --- a/cloudflare/cron/cron.go +++ /dev/null @@ -1,82 +0,0 @@ -package cron - -import ( - "context" - "errors" - "fmt" - "syscall/js" - "time" - - "github.com/syumai/workers/internal/cfcontext" - "github.com/syumai/workers/internal/jsutil" -) - -// Event represents information about the Cron that invoked this worker. -type Event struct { - Cron string - ScheduledTime time.Time -} - -// toEvent converts JS Object to Go Event struct -func toEvent(obj js.Value) (*Event, error) { - if obj.IsUndefined() { - return nil, errors.New("event is null") - } - cronVal := obj.Get("cron").String() - scheduledTimeVal := obj.Get("scheduledTime").Float() - return &Event{ - Cron: cronVal, - ScheduledTime: time.Unix(int64(scheduledTimeVal)/1000, 0).UTC(), - }, nil -} - -type Task func(ctx context.Context, event *Event) error - -var scheduledTask Task - -// ScheduleTask sets the Task to be executed -func ScheduleTask(task Task) { - scheduledTask = task - js.Global().Call("ready") - select {} -} - -func runScheduler(eventObj js.Value, runtimeCtxObj js.Value) error { - ctx := cfcontext.New(context.Background(), runtimeCtxObj, js.Value{}) - event, err := toEvent(eventObj) - if err != nil { - return err - } - err = scheduledTask(ctx, event) - if err != nil { - return err - } - return nil -} - -func init() { - runSchedulerCallback := js.FuncOf(func(_ js.Value, args []js.Value) any { - if len(args) != 2 { - panic(fmt.Errorf("invalid number of arguments given to runScheduler: %d", len(args))) - } - event := args[0] - runtimeCtx := args[1] - - var cb js.Func - cb = js.FuncOf(func(_ js.Value, pArgs []js.Value) any { - defer cb.Release() - resolve := pArgs[0] - go func() { - err := runScheduler(event, runtimeCtx) - if err != nil { - panic(err) - } - resolve.Invoke(js.Undefined()) - }() - return js.Undefined() - }) - - return jsutil.NewPromise(cb) - }) - jsutil.Binding.Set("runScheduler", runSchedulerCallback) -} diff --git a/cloudflare/cron/event.go b/cloudflare/cron/event.go new file mode 100644 index 0000000..96d104f --- /dev/null +++ b/cloudflare/cron/event.go @@ -0,0 +1,28 @@ +package cron + +import ( + "context" + "errors" + "time" + + "github.com/syumai/workers/internal/runtimecontext" +) + +// Event represents information about the Cron that invoked this worker. +type Event struct { + Cron string + ScheduledTime time.Time +} + +func NewEvent(ctx context.Context) (*Event, error) { + obj := runtimecontext.MustExtractTriggerObj(ctx) + if obj.IsUndefined() { + return nil, errors.New("event is null") + } + + scheduledTimeVal := obj.Get("scheduledTime").Float() + return &Event{ + Cron: obj.Get("cron").String(), + ScheduledTime: time.Unix(int64(scheduledTimeVal)/1000, 0).UTC(), + }, nil +} diff --git a/cloudflare/cron/scheduler.go b/cloudflare/cron/scheduler.go new file mode 100644 index 0000000..d559568 --- /dev/null +++ b/cloudflare/cron/scheduler.go @@ -0,0 +1,58 @@ +package cron + +import ( + "context" + "fmt" + "syscall/js" + + "github.com/syumai/workers/internal/jsutil" + "github.com/syumai/workers/internal/runtimecontext" +) + +type Task func(ctx context.Context) error + +var scheduledTask Task + +func runScheduler(eventObj js.Value, runtimeCtxObj js.Value) error { + ctx := runtimecontext.New(context.Background(), eventObj, runtimeCtxObj) + if err := scheduledTask(ctx); err != nil { + return err + } + return nil +} + +func init() { + runSchedulerCallback := js.FuncOf(func(_ js.Value, args []js.Value) any { + if len(args) != 1 { + panic(fmt.Errorf("invalid number of arguments given to runScheduler: %d", len(args))) + } + eventObj := args[0] + runtimeCtxObj := jsutil.RuntimeContext + var cb js.Func + cb = js.FuncOf(func(_ js.Value, pArgs []js.Value) any { + defer cb.Release() + resolve := pArgs[0] + go func() { + err := runScheduler(eventObj, runtimeCtxObj) + if err != nil { + panic(err) + } + resolve.Invoke(js.Undefined()) + }() + return js.Undefined() + }) + + return jsutil.NewPromise(cb) + }) + jsutil.Binding.Set("runScheduler", runSchedulerCallback) +} + +//go:wasmimport workers ready +func ready() + +// ScheduleTask sets the Task to be executed +func ScheduleTask(task Task) { + scheduledTask = task + ready() + select {} +} From 83be8bc6040a27fa57e9a75ad2e5d463cd4fb0af Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Mon, 22 Jan 2024 22:07:24 +0900 Subject: [PATCH 11/13] R: refactor incoming with new runtimecontext --- _examples/incoming/main.go | 9 ++- cloudflare/incoming/property.go | 130 +++++++++++++++++--------------- 2 files changed, 74 insertions(+), 65 deletions(-) diff --git a/_examples/incoming/main.go b/_examples/incoming/main.go index c07adad..5ac0f2f 100644 --- a/_examples/incoming/main.go +++ b/_examples/incoming/main.go @@ -2,7 +2,6 @@ package main import ( "encoding/json" - "fmt" "net/http" "github.com/syumai/workers" @@ -11,12 +10,16 @@ import ( func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - p := incoming.NewProperties(req.Context()) + p, err := incoming.NewProperties(req.Context()) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } encoder := json.NewEncoder(w) w.Header().Set("Content-Type", "application/json") if err := encoder.Encode(p); err != nil { - http.Error(w, fmt.Sprintf("Error encoding JSON: %v", err), http.StatusInternalServerError) + http.Error(w, err.Error(), http.StatusInternalServerError) return } }) diff --git a/cloudflare/incoming/property.go b/cloudflare/incoming/property.go index 4a76530..a15b2e3 100644 --- a/cloudflare/incoming/property.go +++ b/cloudflare/incoming/property.go @@ -2,22 +2,23 @@ package incoming import ( "context" + "errors" "syscall/js" - "github.com/syumai/workers/internal/cfcontext" "github.com/syumai/workers/internal/jsutil" + "github.com/syumai/workers/internal/runtimecontext" ) type BotManagementJsDetection struct { Passed bool } -func NewBotManagementJsDetection(obj js.Value) *BotManagementJsDetection { - if obj.IsUndefined() { +func NewBotManagementJsDetection(cf js.Value) *BotManagementJsDetection { + if cf.IsUndefined() { return nil } return &BotManagementJsDetection{ - Passed: obj.Get("passed").Bool(), + Passed: cf.Get("passed").Bool(), } } @@ -29,16 +30,16 @@ type BotManagement struct { Score int } -func NewBotManagement(obj js.Value) *BotManagement { - if obj.IsUndefined() { +func NewBotManagement(cf js.Value) *BotManagement { + if cf.IsUndefined() { return nil } return &BotManagement{ - CorporateProxy: obj.Get("corporateProxy").Bool(), - VerifiedBot: obj.Get("verifiedBot").Bool(), - JsDetection: NewBotManagementJsDetection(obj.Get("jsDetection")), - StaticResource: obj.Get("staticResource").Bool(), - Score: obj.Get("score").Int(), + CorporateProxy: cf.Get("corporateProxy").Bool(), + VerifiedBot: cf.Get("verifiedBot").Bool(), + JsDetection: NewBotManagementJsDetection(cf.Get("jsDetection")), + StaticResource: cf.Get("staticResource").Bool(), + Score: cf.Get("score").Int(), } } @@ -62,28 +63,28 @@ type TLSClientAuth struct { CertFingerprintSHA1 string } -func NewTLSClientAuth(obj js.Value) *TLSClientAuth { - if obj.IsUndefined() { +func NewTLSClientAuth(cf js.Value) *TLSClientAuth { + if cf.IsUndefined() { return nil } return &TLSClientAuth{ - CertIssuerDNLegacy: jsutil.MaybeString(obj.Get("certIssuerDNLegacy")), - CertIssuerSKI: jsutil.MaybeString(obj.Get("certIssuerSKI")), - CertSubjectDNRFC2253: jsutil.MaybeString(obj.Get("certSubjectDNRFC2253")), - CertSubjectDNLegacy: jsutil.MaybeString(obj.Get("certSubjectDNLegacy")), - CertFingerprintSHA256: jsutil.MaybeString(obj.Get("certFingerprintSHA256")), - CertNotBefore: jsutil.MaybeString(obj.Get("certNotBefore")), - CertSKI: jsutil.MaybeString(obj.Get("certSKI")), - CertSerial: jsutil.MaybeString(obj.Get("certSerial")), - CertIssuerDN: jsutil.MaybeString(obj.Get("certIssuerDN")), - CertVerified: jsutil.MaybeString(obj.Get("certVerified")), - CertNotAfter: jsutil.MaybeString(obj.Get("certNotAfter")), - CertSubjectDN: jsutil.MaybeString(obj.Get("certSubjectDN")), - CertPresented: jsutil.MaybeString(obj.Get("certPresented")), - CertRevoked: jsutil.MaybeString(obj.Get("certRevoked")), - CertIssuerSerial: jsutil.MaybeString(obj.Get("certIssuerSerial")), - CertIssuerDNRFC2253: jsutil.MaybeString(obj.Get("certIssuerDNRFC2253")), - CertFingerprintSHA1: jsutil.MaybeString(obj.Get("certFingerprintSHA1")), + CertIssuerDNLegacy: jsutil.MaybeString(cf.Get("certIssuerDNLegacy")), + CertIssuerSKI: jsutil.MaybeString(cf.Get("certIssuerSKI")), + CertSubjectDNRFC2253: jsutil.MaybeString(cf.Get("certSubjectDNRFC2253")), + CertSubjectDNLegacy: jsutil.MaybeString(cf.Get("certSubjectDNLegacy")), + CertFingerprintSHA256: jsutil.MaybeString(cf.Get("certFingerprintSHA256")), + CertNotBefore: jsutil.MaybeString(cf.Get("certNotBefore")), + CertSKI: jsutil.MaybeString(cf.Get("certSKI")), + CertSerial: jsutil.MaybeString(cf.Get("certSerial")), + CertIssuerDN: jsutil.MaybeString(cf.Get("certIssuerDN")), + CertVerified: jsutil.MaybeString(cf.Get("certVerified")), + CertNotAfter: jsutil.MaybeString(cf.Get("certNotAfter")), + CertSubjectDN: jsutil.MaybeString(cf.Get("certSubjectDN")), + CertPresented: jsutil.MaybeString(cf.Get("certPresented")), + CertRevoked: jsutil.MaybeString(cf.Get("certRevoked")), + CertIssuerSerial: jsutil.MaybeString(cf.Get("certIssuerSerial")), + CertIssuerDNRFC2253: jsutil.MaybeString(cf.Get("certIssuerDNRFC2253")), + CertFingerprintSHA1: jsutil.MaybeString(cf.Get("certFingerprintSHA1")), } } @@ -94,29 +95,29 @@ type TLSExportedAuthenticator struct { ServerFinished string } -func NewTLSExportedAuthenticator(obj js.Value) *TLSExportedAuthenticator { - if obj.IsUndefined() { +func NewTLSExportedAuthenticator(cf js.Value) *TLSExportedAuthenticator { + if cf.IsUndefined() { return nil } return &TLSExportedAuthenticator{ - ClientFinished: jsutil.MaybeString(obj.Get("clientFinished")), - ClientHandshake: jsutil.MaybeString(obj.Get("clientHandshake")), - ServerHandshake: jsutil.MaybeString(obj.Get("serverHandshake")), - ServerFinished: jsutil.MaybeString(obj.Get("serverFinished")), + ClientFinished: jsutil.MaybeString(cf.Get("clientFinished")), + ClientHandshake: jsutil.MaybeString(cf.Get("clientHandshake")), + ServerHandshake: jsutil.MaybeString(cf.Get("serverHandshake")), + ServerFinished: jsutil.MaybeString(cf.Get("serverFinished")), } } type Properties struct { Longitude string Latitude string - TlsCipher string + TLSCipher string Continent string Asn int ClientAcceptEncoding string Country string TLSClientAuth *TLSClientAuth TLSExportedAuthenticator *TLSExportedAuthenticator - TlsVersion string + TLSVersion string Colo string Timezone string City string @@ -131,29 +132,34 @@ type Properties struct { BotManagement *BotManagement } -func NewProperties(ctx context.Context) *Properties { - obj := cfcontext.MustExtractIncomingProperty(ctx) - return &Properties{ - Longitude: jsutil.MaybeString(obj.Get("longitude")), - Latitude: jsutil.MaybeString(obj.Get("latitude")), - TlsCipher: jsutil.MaybeString(obj.Get("tlsCipher")), - Continent: jsutil.MaybeString(obj.Get("continent")), - Asn: obj.Get("asn").Int(), - ClientAcceptEncoding: jsutil.MaybeString(obj.Get("clientAcceptEncoding")), - Country: jsutil.MaybeString(obj.Get("country")), - TLSClientAuth: NewTLSClientAuth(obj.Get("tlsClientAuth")), - TLSExportedAuthenticator: NewTLSExportedAuthenticator(obj.Get("tlsExportedAuthenticator")), - TlsVersion: obj.Get("tlsVersion").String(), - Colo: obj.Get("colo").String(), - Timezone: obj.Get("timezone").String(), - City: jsutil.MaybeString(obj.Get("city")), - VerifiedBotCategory: jsutil.MaybeString(obj.Get("verifiedBotCategory")), - RequestPriority: jsutil.MaybeString(obj.Get("requestPriority")), - HttpProtocol: obj.Get("httpProtocol").String(), - Region: jsutil.MaybeString(obj.Get("region")), - RegionCode: jsutil.MaybeString(obj.Get("regionCode")), - AsOrganization: obj.Get("asOrganization").String(), - PostalCode: jsutil.MaybeString(obj.Get("postalCode")), - BotManagement: NewBotManagement(obj.Get("botManagement")), +func NewProperties(ctx context.Context) (*Properties, error) { + obj := runtimecontext.MustExtractTriggerObj(ctx) + cf := obj.Get("cf") + if cf.IsUndefined() { + return nil, errors.New("runtime is not cloudflare") } + + return &Properties{ + Longitude: jsutil.MaybeString(cf.Get("longitude")), + Latitude: jsutil.MaybeString(cf.Get("latitude")), + TLSCipher: jsutil.MaybeString(cf.Get("tlsCipher")), + Continent: jsutil.MaybeString(cf.Get("continent")), + Asn: cf.Get("asn").Int(), + ClientAcceptEncoding: jsutil.MaybeString(cf.Get("clientAcceptEncoding")), + Country: jsutil.MaybeString(cf.Get("country")), + TLSClientAuth: NewTLSClientAuth(cf.Get("tlsClientAuth")), + TLSExportedAuthenticator: NewTLSExportedAuthenticator(cf.Get("tlsExportedAuthenticator")), + TLSVersion: cf.Get("tlsVersion").String(), + Colo: cf.Get("colo").String(), + Timezone: cf.Get("timezone").String(), + City: jsutil.MaybeString(cf.Get("city")), + VerifiedBotCategory: jsutil.MaybeString(cf.Get("verifiedBotCategory")), + RequestPriority: jsutil.MaybeString(cf.Get("requestPriority")), + HttpProtocol: cf.Get("httpProtocol").String(), + Region: jsutil.MaybeString(cf.Get("region")), + RegionCode: jsutil.MaybeString(cf.Get("regionCode")), + AsOrganization: cf.Get("asOrganization").String(), + PostalCode: jsutil.MaybeString(cf.Get("postalCode")), + BotManagement: NewBotManagement(cf.Get("botManagement")), + }, nil } From 86f9f1cf26d3fa5d95e03f0c20bcf08ca722fea8 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Tue, 23 Jan 2024 12:53:32 +0900 Subject: [PATCH 12/13] R: fix illegal invocation error --- cloudflare/fetch/bind.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cloudflare/fetch/bind.go b/cloudflare/fetch/bind.go index 9207cdb..afc6ea1 100644 --- a/cloudflare/fetch/bind.go +++ b/cloudflare/fetch/bind.go @@ -15,7 +15,8 @@ func fetch(namespace js.Value, req *http.Request, init *RequestInit) (*http.Resp if namespace.IsUndefined() { return nil, errors.New("fetch function not found") } - promise := namespace.Call("fetch", + fetchObj := namespace.Get("fetch") + promise := fetchObj.Invoke( // The Request object to fetch. // Docs: https://developers.cloudflare.com/workers/runtime-apis/request jshttp.ToJSRequest(req), @@ -23,9 +24,11 @@ func fetch(namespace js.Value, req *http.Request, init *RequestInit) (*http.Resp // Docs: https://developers.cloudflare.com/workers/runtime-apis/request#requestinit init.ToJS(), ) + jsRes, err := jsutil.AwaitPromise(promise) if err != nil { return nil, err } + return jshttp.ToResponse(jsRes) } From eac1510668732998b2578c2d20b066391c608545 Mon Sep 17 00:00:00 2001 From: aki-0421 <118268728+aki-0421@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:01:33 +0900 Subject: [PATCH 13/13] R: merge pkg --- _examples/incoming/go.mod | 2 +- _examples/incoming/main.go | 4 +- cloudflare/fetch/property.go | 158 ++++++++++++++++++++++++++++++ cloudflare/incoming/property.go | 165 -------------------------------- 4 files changed, 161 insertions(+), 168 deletions(-) delete mode 100644 cloudflare/incoming/property.go diff --git a/_examples/incoming/go.mod b/_examples/incoming/go.mod index d698bb5..d54651d 100644 --- a/_examples/incoming/go.mod +++ b/_examples/incoming/go.mod @@ -1,4 +1,4 @@ -module github.com/syumai/workers/_examples/hello +module github.com/syumai/workers/_examples/incoming go 1.21.3 diff --git a/_examples/incoming/main.go b/_examples/incoming/main.go index 5ac0f2f..21ac872 100644 --- a/_examples/incoming/main.go +++ b/_examples/incoming/main.go @@ -5,12 +5,12 @@ import ( "net/http" "github.com/syumai/workers" - "github.com/syumai/workers/cloudflare/incoming" + "github.com/syumai/workers/cloudflare/fetch" ) func main() { handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { - p, err := incoming.NewProperties(req.Context()) + p, err := fetch.NewIncomingProperties(req.Context()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return diff --git a/cloudflare/fetch/property.go b/cloudflare/fetch/property.go index 73fab4b..9343785 100644 --- a/cloudflare/fetch/property.go +++ b/cloudflare/fetch/property.go @@ -1,9 +1,12 @@ package fetch import ( + "context" + "errors" "syscall/js" "github.com/syumai/workers/internal/jsutil" + "github.com/syumai/workers/internal/runtimecontext" ) // RedirectMode represents the redirect mode of a fetch() request. @@ -45,3 +48,158 @@ func (init *RequestInit) ToJS() js.Value { type RequestInitCF struct { /* TODO: implement */ } + +type IncomingBotManagementJsDetection struct { + Passed bool +} + +func NewIncomingBotManagementJsDetection(cf js.Value) *IncomingBotManagementJsDetection { + if cf.IsUndefined() { + return nil + } + return &IncomingBotManagementJsDetection{ + Passed: cf.Get("passed").Bool(), + } +} + +type IncomingBotManagement struct { + CorporateProxy bool + VerifiedBot bool + JsDetection *IncomingBotManagementJsDetection + StaticResource bool + Score int +} + +func NewIncomingBotManagement(cf js.Value) *IncomingBotManagement { + if cf.IsUndefined() { + return nil + } + return &IncomingBotManagement{ + CorporateProxy: cf.Get("corporateProxy").Bool(), + VerifiedBot: cf.Get("verifiedBot").Bool(), + JsDetection: NewIncomingBotManagementJsDetection(cf.Get("jsDetection")), + StaticResource: cf.Get("staticResource").Bool(), + Score: cf.Get("score").Int(), + } +} + +type IncomingTLSClientAuth struct { + CertIssuerDNLegacy string + CertIssuerSKI string + CertSubjectDNRFC2253 string + CertSubjectDNLegacy string + CertFingerprintSHA256 string + CertNotBefore string + CertSKI string + CertSerial string + CertIssuerDN string + CertVerified string + CertNotAfter string + CertSubjectDN string + CertPresented string + CertRevoked string + CertIssuerSerial string + CertIssuerDNRFC2253 string + CertFingerprintSHA1 string +} + +func NewIncomingTLSClientAuth(cf js.Value) *IncomingTLSClientAuth { + if cf.IsUndefined() { + return nil + } + return &IncomingTLSClientAuth{ + CertIssuerDNLegacy: jsutil.MaybeString(cf.Get("certIssuerDNLegacy")), + CertIssuerSKI: jsutil.MaybeString(cf.Get("certIssuerSKI")), + CertSubjectDNRFC2253: jsutil.MaybeString(cf.Get("certSubjectDNRFC2253")), + CertSubjectDNLegacy: jsutil.MaybeString(cf.Get("certSubjectDNLegacy")), + CertFingerprintSHA256: jsutil.MaybeString(cf.Get("certFingerprintSHA256")), + CertNotBefore: jsutil.MaybeString(cf.Get("certNotBefore")), + CertSKI: jsutil.MaybeString(cf.Get("certSKI")), + CertSerial: jsutil.MaybeString(cf.Get("certSerial")), + CertIssuerDN: jsutil.MaybeString(cf.Get("certIssuerDN")), + CertVerified: jsutil.MaybeString(cf.Get("certVerified")), + CertNotAfter: jsutil.MaybeString(cf.Get("certNotAfter")), + CertSubjectDN: jsutil.MaybeString(cf.Get("certSubjectDN")), + CertPresented: jsutil.MaybeString(cf.Get("certPresented")), + CertRevoked: jsutil.MaybeString(cf.Get("certRevoked")), + CertIssuerSerial: jsutil.MaybeString(cf.Get("certIssuerSerial")), + CertIssuerDNRFC2253: jsutil.MaybeString(cf.Get("certIssuerDNRFC2253")), + CertFingerprintSHA1: jsutil.MaybeString(cf.Get("certFingerprintSHA1")), + } +} + +type IncomingTLSExportedAuthenticator struct { + ClientFinished string + ClientHandshake string + ServerHandshake string + ServerFinished string +} + +func NewIncomingTLSExportedAuthenticator(cf js.Value) *IncomingTLSExportedAuthenticator { + if cf.IsUndefined() { + return nil + } + return &IncomingTLSExportedAuthenticator{ + ClientFinished: jsutil.MaybeString(cf.Get("clientFinished")), + ClientHandshake: jsutil.MaybeString(cf.Get("clientHandshake")), + ServerHandshake: jsutil.MaybeString(cf.Get("serverHandshake")), + ServerFinished: jsutil.MaybeString(cf.Get("serverFinished")), + } +} + +type IncomingProperties struct { + Longitude string + Latitude string + TLSCipher string + Continent string + Asn int + ClientAcceptEncoding string + Country string + TLSClientAuth *IncomingTLSClientAuth + TLSExportedAuthenticator *IncomingTLSExportedAuthenticator + TLSVersion string + Colo string + Timezone string + City string + VerifiedBotCategory string + // EdgeRequestKeepAliveStatus int + RequestPriority string + HttpProtocol string + Region string + RegionCode string + AsOrganization string + PostalCode string + BotManagement *IncomingBotManagement +} + +func NewIncomingProperties(ctx context.Context) (*IncomingProperties, error) { + obj := runtimecontext.MustExtractTriggerObj(ctx) + cf := obj.Get("cf") + if cf.IsUndefined() { + return nil, errors.New("runtime is not cloudflare") + } + + return &IncomingProperties{ + Longitude: jsutil.MaybeString(cf.Get("longitude")), + Latitude: jsutil.MaybeString(cf.Get("latitude")), + TLSCipher: jsutil.MaybeString(cf.Get("tlsCipher")), + Continent: jsutil.MaybeString(cf.Get("continent")), + Asn: cf.Get("asn").Int(), + ClientAcceptEncoding: jsutil.MaybeString(cf.Get("clientAcceptEncoding")), + Country: jsutil.MaybeString(cf.Get("country")), + TLSClientAuth: NewIncomingTLSClientAuth(cf.Get("tlsClientAuth")), + TLSExportedAuthenticator: NewIncomingTLSExportedAuthenticator(cf.Get("tlsExportedAuthenticator")), + TLSVersion: cf.Get("tlsVersion").String(), + Colo: cf.Get("colo").String(), + Timezone: cf.Get("timezone").String(), + City: jsutil.MaybeString(cf.Get("city")), + VerifiedBotCategory: jsutil.MaybeString(cf.Get("verifiedBotCategory")), + RequestPriority: jsutil.MaybeString(cf.Get("requestPriority")), + HttpProtocol: cf.Get("httpProtocol").String(), + Region: jsutil.MaybeString(cf.Get("region")), + RegionCode: jsutil.MaybeString(cf.Get("regionCode")), + AsOrganization: cf.Get("asOrganization").String(), + PostalCode: jsutil.MaybeString(cf.Get("postalCode")), + BotManagement: NewIncomingBotManagement(cf.Get("botManagement")), + }, nil +} diff --git a/cloudflare/incoming/property.go b/cloudflare/incoming/property.go deleted file mode 100644 index a15b2e3..0000000 --- a/cloudflare/incoming/property.go +++ /dev/null @@ -1,165 +0,0 @@ -package incoming - -import ( - "context" - "errors" - "syscall/js" - - "github.com/syumai/workers/internal/jsutil" - "github.com/syumai/workers/internal/runtimecontext" -) - -type BotManagementJsDetection struct { - Passed bool -} - -func NewBotManagementJsDetection(cf js.Value) *BotManagementJsDetection { - if cf.IsUndefined() { - return nil - } - return &BotManagementJsDetection{ - Passed: cf.Get("passed").Bool(), - } -} - -type BotManagement struct { - CorporateProxy bool - VerifiedBot bool - JsDetection *BotManagementJsDetection - StaticResource bool - Score int -} - -func NewBotManagement(cf js.Value) *BotManagement { - if cf.IsUndefined() { - return nil - } - return &BotManagement{ - CorporateProxy: cf.Get("corporateProxy").Bool(), - VerifiedBot: cf.Get("verifiedBot").Bool(), - JsDetection: NewBotManagementJsDetection(cf.Get("jsDetection")), - StaticResource: cf.Get("staticResource").Bool(), - Score: cf.Get("score").Int(), - } -} - -type TLSClientAuth struct { - CertIssuerDNLegacy string - CertIssuerSKI string - CertSubjectDNRFC2253 string - CertSubjectDNLegacy string - CertFingerprintSHA256 string - CertNotBefore string - CertSKI string - CertSerial string - CertIssuerDN string - CertVerified string - CertNotAfter string - CertSubjectDN string - CertPresented string - CertRevoked string - CertIssuerSerial string - CertIssuerDNRFC2253 string - CertFingerprintSHA1 string -} - -func NewTLSClientAuth(cf js.Value) *TLSClientAuth { - if cf.IsUndefined() { - return nil - } - return &TLSClientAuth{ - CertIssuerDNLegacy: jsutil.MaybeString(cf.Get("certIssuerDNLegacy")), - CertIssuerSKI: jsutil.MaybeString(cf.Get("certIssuerSKI")), - CertSubjectDNRFC2253: jsutil.MaybeString(cf.Get("certSubjectDNRFC2253")), - CertSubjectDNLegacy: jsutil.MaybeString(cf.Get("certSubjectDNLegacy")), - CertFingerprintSHA256: jsutil.MaybeString(cf.Get("certFingerprintSHA256")), - CertNotBefore: jsutil.MaybeString(cf.Get("certNotBefore")), - CertSKI: jsutil.MaybeString(cf.Get("certSKI")), - CertSerial: jsutil.MaybeString(cf.Get("certSerial")), - CertIssuerDN: jsutil.MaybeString(cf.Get("certIssuerDN")), - CertVerified: jsutil.MaybeString(cf.Get("certVerified")), - CertNotAfter: jsutil.MaybeString(cf.Get("certNotAfter")), - CertSubjectDN: jsutil.MaybeString(cf.Get("certSubjectDN")), - CertPresented: jsutil.MaybeString(cf.Get("certPresented")), - CertRevoked: jsutil.MaybeString(cf.Get("certRevoked")), - CertIssuerSerial: jsutil.MaybeString(cf.Get("certIssuerSerial")), - CertIssuerDNRFC2253: jsutil.MaybeString(cf.Get("certIssuerDNRFC2253")), - CertFingerprintSHA1: jsutil.MaybeString(cf.Get("certFingerprintSHA1")), - } -} - -type TLSExportedAuthenticator struct { - ClientFinished string - ClientHandshake string - ServerHandshake string - ServerFinished string -} - -func NewTLSExportedAuthenticator(cf js.Value) *TLSExportedAuthenticator { - if cf.IsUndefined() { - return nil - } - return &TLSExportedAuthenticator{ - ClientFinished: jsutil.MaybeString(cf.Get("clientFinished")), - ClientHandshake: jsutil.MaybeString(cf.Get("clientHandshake")), - ServerHandshake: jsutil.MaybeString(cf.Get("serverHandshake")), - ServerFinished: jsutil.MaybeString(cf.Get("serverFinished")), - } -} - -type Properties struct { - Longitude string - Latitude string - TLSCipher string - Continent string - Asn int - ClientAcceptEncoding string - Country string - TLSClientAuth *TLSClientAuth - TLSExportedAuthenticator *TLSExportedAuthenticator - TLSVersion string - Colo string - Timezone string - City string - VerifiedBotCategory string - // EdgeRequestKeepAliveStatus int - RequestPriority string - HttpProtocol string - Region string - RegionCode string - AsOrganization string - PostalCode string - BotManagement *BotManagement -} - -func NewProperties(ctx context.Context) (*Properties, error) { - obj := runtimecontext.MustExtractTriggerObj(ctx) - cf := obj.Get("cf") - if cf.IsUndefined() { - return nil, errors.New("runtime is not cloudflare") - } - - return &Properties{ - Longitude: jsutil.MaybeString(cf.Get("longitude")), - Latitude: jsutil.MaybeString(cf.Get("latitude")), - TLSCipher: jsutil.MaybeString(cf.Get("tlsCipher")), - Continent: jsutil.MaybeString(cf.Get("continent")), - Asn: cf.Get("asn").Int(), - ClientAcceptEncoding: jsutil.MaybeString(cf.Get("clientAcceptEncoding")), - Country: jsutil.MaybeString(cf.Get("country")), - TLSClientAuth: NewTLSClientAuth(cf.Get("tlsClientAuth")), - TLSExportedAuthenticator: NewTLSExportedAuthenticator(cf.Get("tlsExportedAuthenticator")), - TLSVersion: cf.Get("tlsVersion").String(), - Colo: cf.Get("colo").String(), - Timezone: cf.Get("timezone").String(), - City: jsutil.MaybeString(cf.Get("city")), - VerifiedBotCategory: jsutil.MaybeString(cf.Get("verifiedBotCategory")), - RequestPriority: jsutil.MaybeString(cf.Get("requestPriority")), - HttpProtocol: cf.Get("httpProtocol").String(), - Region: jsutil.MaybeString(cf.Get("region")), - RegionCode: jsutil.MaybeString(cf.Get("regionCode")), - AsOrganization: cf.Get("asOrganization").String(), - PostalCode: jsutil.MaybeString(cf.Get("postalCode")), - BotManagement: NewBotManagement(cf.Get("botManagement")), - }, nil -}