From a165c4ee1ac2aa5dc1aef496c643907377416555 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 17 Apr 2025 13:39:04 +0700 Subject: [PATCH 01/51] add module (php_server directive) based workers --- caddy/caddy.go | 97 ++++++++++++++++++++++++++++++++++++++++++++-- context.go | 3 ++ frankenphp.go | 7 +++- options.go | 7 ++-- request_options.go | 9 +++++ worker.go | 2 + 6 files changed, 116 insertions(+), 9 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 501af3ed2e..5d0ca50edc 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -30,6 +30,9 @@ const defaultDocumentRoot = "public" var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") +// moduleWorkers is a package-level variable to store workers that can be accessed by both FrankenPHPModule and FrankenPHPApp +var moduleWorkers []workerConfig + func init() { caddy.RegisterModule(FrankenPHPApp{}) caddy.RegisterModule(FrankenPHPModule{}) @@ -55,6 +58,8 @@ type workerConfig struct { Env map[string]string `json:"env,omitempty"` // Directories to watch for file changes Watch []string `json:"watch,omitempty"` + // ModuleID identifies which module created this worker + ModuleID string `json:"module_id,omitempty"` } type FrankenPHPApp struct { @@ -84,6 +89,7 @@ func (f FrankenPHPApp) CaddyModule() caddy.ModuleInfo { // Provision sets up the module. func (f *FrankenPHPApp) Provision(ctx caddy.Context) error { f.logger = ctx.Logger() + f.logger.Info("FrankenPHPApp provisioning 🐘") if httpApp, err := ctx.AppIfConfigured("http"); err == nil { if httpApp.(*caddyhttp.App).Metrics != nil { @@ -108,8 +114,14 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithPhpIni(f.PhpIni), frankenphp.WithMaxWaitTime(f.MaxWaitTime), } + // Add workers from FrankenPHPApp configuration for _, w := range f.Workers { - opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) + opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) + } + + // Add workers from shared location (added by FrankenPHPModule) + for _, w := range moduleWorkers { + opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) } frankenphp.Shutdown() @@ -135,6 +147,9 @@ func (f *FrankenPHPApp) Stop() error { f.NumThreads = 0 f.MaxWaitTime = 0 + // reset shared workers + moduleWorkers = nil + return nil } @@ -341,6 +356,8 @@ type FrankenPHPModule struct { ResolveRootSymlink *bool `json:"resolve_root_symlink,omitempty"` // Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables. Env map[string]string `json:"env,omitempty"` + // Workers configures the worker scripts to start. + Workers []workerConfig `json:"workers,omitempty"` resolvedDocumentRoot string preparedEnv frankenphp.PreparedEnv @@ -359,6 +376,7 @@ func (FrankenPHPModule) CaddyModule() caddy.ModuleInfo { // Provision sets up the module. func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { f.logger = ctx.Logger() + f.logger.Info("FrankenPHPModule provisioning 🐘") if f.Root == "" { if frankenphp.EmbeddedAppPath == "" { @@ -412,6 +430,15 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } } + if len(f.Workers) > 0 { + // Tag workers with a unique module ID based on the module's memory address + moduleID := fmt.Sprintf("%p", f) + for i := range f.Workers { + f.Workers[i].ModuleID = moduleID + } + moduleWorkers = append(moduleWorkers, f.Workers...) + } + return nil } @@ -422,7 +449,7 @@ func needReplacement(s string) bool { // ServeHTTP implements caddyhttp.MiddlewareHandler. // TODO: Expose TLS versions as env vars, as Apache's mod_ssl: https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/reverseproxy/fastcgi/fastcgi.go#L298 -func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error { +func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error { origReq := r.Context().Value(caddyhttp.OriginalRequestCtxKey).(http.Request) repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) @@ -447,6 +474,7 @@ func (f FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ ca frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), + frankenphp.WithModuleID(fmt.Sprintf("%p", f)), ) if err != nil { @@ -466,6 +494,66 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { for d.NextBlock(0) { switch d.Val() { + case "worker": + wc := workerConfig{} + if d.NextArg() { + wc.FileName = d.Val() + } + + if d.NextArg() { + v, err := strconv.Atoi(d.Val()) + if err != nil { + return err + } + wc.Num = v + } + + for d.NextBlock(1) { + switch d.Val() { + case "name": + if !d.NextArg() { + return d.ArgErr() + } + wc.Name = d.Val() + case "file": + if !d.NextArg() { + return d.ArgErr() + } + wc.FileName = d.Val() + case "num": + if !d.NextArg() { + return d.ArgErr() + } + v, err := strconv.Atoi(d.Val()) + if err != nil { + return err + } + wc.Num = v + case "env": + args := d.RemainingArgs() + if len(args) != 2 { + return d.ArgErr() + } + if wc.Env == nil { + wc.Env = make(map[string]string) + } + wc.Env[args[0]] = args[1] + case "watch": + if !d.NextArg() { + wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") + } else { + wc.Watch = append(wc.Watch, d.Val()) + } + default: + return fmt.Errorf("unknown worker subdirective: %s", d.Val()) + } + } + + if wc.FileName == "" { + return errors.New(`the "file" argument must be specified`) + } + + f.Workers = append(f.Workers, wc) case "root": if !d.NextArg() { return d.ArgErr() @@ -505,7 +593,7 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { f.ResolveRootSymlink = &v default: - allowedDirectives := "root, split, env, resolve_root_symlink" + allowedDirectives := "root, split, env, resolve_root_symlink, worker" return wrongSubDirectiveError("php or php_server", allowedDirectives, d.Val()) } } @@ -516,7 +604,7 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // parseCaddyfile unmarshals tokens from h into a new Middleware. func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { - m := FrankenPHPModule{} + m := &FrankenPHPModule{} err := m.UnmarshalCaddyfile(h.Dispenser) return m, err @@ -753,6 +841,7 @@ func parsePhpServer(h httpcaddyfile.Helper) ([]httpcaddyfile.ConfigValue, error) // using the php directive syntax dispenser.Next() // consume the directive name err = phpsrv.UnmarshalCaddyfile(dispenser) + if err != nil { return nil, err } diff --git a/context.go b/context.go index cdbeab1529..7b6bf218d2 100644 --- a/context.go +++ b/context.go @@ -31,6 +31,9 @@ type frankenPHPContext struct { done chan interface{} startedAt time.Time + + // The module ID that created this request + moduleID string } // fromContext extracts the frankenPHPContext from a context. diff --git a/frankenphp.go b/frankenphp.go index 2446935642..9ca2bf2e58 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -406,8 +406,11 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error // Detect if a worker is available to handle this request if worker, ok := workers[fc.scriptFilename]; ok { - worker.handleRequest(fc) - return nil + // can handle with a global worker, or a module worker from the matching module + if worker.moduleID == "" || worker.moduleID == fc.moduleID { + worker.handleRequest(fc) + return nil + } } // If no worker was availabe send the request to non-worker threads diff --git a/options.go b/options.go index c5d2488539..da6e00931f 100644 --- a/options.go +++ b/options.go @@ -28,6 +28,7 @@ type workerOpt struct { num int env PreparedEnv watch []string + moduleID string } // WithNumThreads configures the number of PHP threads to start. @@ -55,10 +56,10 @@ func WithMetrics(m Metrics) Option { } } -// WithWorkers configures the PHP workers to start. -func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string) Option { +// WithWorkers configures the PHP workers to start, moduleID is used to identify the worker for a specific domain +func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID string) Option { return func(o *opt) error { - o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch}) + o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch, moduleID}) return nil } diff --git a/request_options.go b/request_options.go index 4e2387730d..8a1bad9b4c 100644 --- a/request_options.go +++ b/request_options.go @@ -123,3 +123,12 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { return nil } } + +// WithModuleID sets the module ID associated with the current request +func WithModuleID(moduleID string) RequestOption { + return func(o *frankenPHPContext) error { + o.moduleID = moduleID + + return nil + } +} diff --git a/worker.go b/worker.go index b0880ebbb1..c3f787dd67 100644 --- a/worker.go +++ b/worker.go @@ -20,6 +20,7 @@ type worker struct { requestChan chan *frankenPHPContext threads []*phpThread threadMutex sync.RWMutex + moduleID string } var ( @@ -81,6 +82,7 @@ func newWorker(o workerOpt) (*worker, error) { num: o.num, env: o.env, requestChan: make(chan *frankenPHPContext), + moduleID: o.moduleID, } workers[absFileName] = w From 61bbef492c14bae79343ff8330298c464ca6124d Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 09:01:28 +0700 Subject: [PATCH 02/51] refactor moduleID to uintptr for faster comparisons --- caddy/caddy.go | 13 ++++++------- context.go | 2 +- frankenphp.go | 2 +- options.go | 4 ++-- request_options.go | 2 +- worker.go | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 5d0ca50edc..d264568b31 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -12,6 +12,7 @@ import ( "strconv" "strings" "time" + "unsafe" "github.com/dunglas/frankenphp/internal/fastabs" @@ -59,7 +60,7 @@ type workerConfig struct { // Directories to watch for file changes Watch []string `json:"watch,omitempty"` // ModuleID identifies which module created this worker - ModuleID string `json:"module_id,omitempty"` + ModuleID uintptr `json:"module_id,omitempty"` } type FrankenPHPApp struct { @@ -119,7 +120,7 @@ func (f *FrankenPHPApp) Start() error { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) } - // Add workers from shared location (added by FrankenPHPModule) + // Add workers from FrankenPHPModule configurations for _, w := range moduleWorkers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) } @@ -147,7 +148,7 @@ func (f *FrankenPHPApp) Stop() error { f.NumThreads = 0 f.MaxWaitTime = 0 - // reset shared workers + // reset moduleWorkers moduleWorkers = nil return nil @@ -376,7 +377,6 @@ func (FrankenPHPModule) CaddyModule() caddy.ModuleInfo { // Provision sets up the module. func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { f.logger = ctx.Logger() - f.logger.Info("FrankenPHPModule provisioning 🐘") if f.Root == "" { if frankenphp.EmbeddedAppPath == "" { @@ -432,9 +432,8 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { if len(f.Workers) > 0 { // Tag workers with a unique module ID based on the module's memory address - moduleID := fmt.Sprintf("%p", f) for i := range f.Workers { - f.Workers[i].ModuleID = moduleID + f.Workers[i].ModuleID = uintptr(unsafe.Pointer(f)) } moduleWorkers = append(moduleWorkers, f.Workers...) } @@ -474,7 +473,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), - frankenphp.WithModuleID(fmt.Sprintf("%p", f)), + frankenphp.WithModuleID(uintptr(unsafe.Pointer(f))), ) if err != nil { diff --git a/context.go b/context.go index 7b6bf218d2..efe25c41ec 100644 --- a/context.go +++ b/context.go @@ -33,7 +33,7 @@ type frankenPHPContext struct { startedAt time.Time // The module ID that created this request - moduleID string + moduleID uintptr } // fromContext extracts the frankenPHPContext from a context. diff --git a/frankenphp.go b/frankenphp.go index 9ca2bf2e58..2557286801 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -407,7 +407,7 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error // Detect if a worker is available to handle this request if worker, ok := workers[fc.scriptFilename]; ok { // can handle with a global worker, or a module worker from the matching module - if worker.moduleID == "" || worker.moduleID == fc.moduleID { + if worker.moduleID == 0 || worker.moduleID == fc.moduleID { worker.handleRequest(fc) return nil } diff --git a/options.go b/options.go index da6e00931f..3a3040f999 100644 --- a/options.go +++ b/options.go @@ -28,7 +28,7 @@ type workerOpt struct { num int env PreparedEnv watch []string - moduleID string + moduleID uintptr } // WithNumThreads configures the number of PHP threads to start. @@ -57,7 +57,7 @@ func WithMetrics(m Metrics) Option { } // WithWorkers configures the PHP workers to start, moduleID is used to identify the worker for a specific domain -func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID string) Option { +func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID uintptr) Option { return func(o *opt) error { o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch, moduleID}) diff --git a/request_options.go b/request_options.go index 8a1bad9b4c..494fd23435 100644 --- a/request_options.go +++ b/request_options.go @@ -125,7 +125,7 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { } // WithModuleID sets the module ID associated with the current request -func WithModuleID(moduleID string) RequestOption { +func WithModuleID(moduleID uintptr) RequestOption { return func(o *frankenPHPContext) error { o.moduleID = moduleID diff --git a/worker.go b/worker.go index c3f787dd67..061d3fd95b 100644 --- a/worker.go +++ b/worker.go @@ -20,7 +20,7 @@ type worker struct { requestChan chan *frankenPHPContext threads []*phpThread threadMutex sync.RWMutex - moduleID string + moduleID uintptr } var ( From 7fffbc2c1ccef8014ceb023a1a4a61c59228bf32 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 11:23:24 +0700 Subject: [PATCH 03/51] let workers inherit environment variables and root from php_server --- caddy/caddy.go | 112 +++++++++++++++++++++++++++++++------------------ frankenphp.go | 2 +- 2 files changed, 72 insertions(+), 42 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index d264568b31..bcaadc207f 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -90,7 +90,6 @@ func (f FrankenPHPApp) CaddyModule() caddy.ModuleInfo { // Provision sets up the module. func (f *FrankenPHPApp) Provision(ctx caddy.Context) error { f.logger = ctx.Logger() - f.logger.Info("FrankenPHPApp provisioning 🐘") if httpApp, err := ctx.AppIfConfigured("http"); err == nil { if httpApp.(*caddyhttp.App).Metrics != nil { @@ -431,7 +430,6 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } if len(f.Workers) > 0 { - // Tag workers with a unique module ID based on the module's memory address for i := range f.Workers { f.Workers[i].ModuleID = uintptr(unsafe.Pointer(f)) } @@ -489,11 +487,67 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c // UnmarshalCaddyfile implements caddyfile.Unmarshaler. func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { - // when adding a new directive, also update the allowedDirectives error message + // First pass: Parse all directives except "worker" for d.Next() { for d.NextBlock(0) { switch d.Val() { + case "root": + if !d.NextArg() { + return d.ArgErr() + } + f.Root = d.Val() + + case "split": + f.SplitPath = d.RemainingArgs() + if len(f.SplitPath) == 0 { + return d.ArgErr() + } + + case "env": + args := d.RemainingArgs() + if len(args) != 2 { + return d.ArgErr() + } + if f.Env == nil { + f.Env = make(map[string]string) + f.preparedEnv = make(frankenphp.PreparedEnv) + } + f.Env[args[0]] = args[1] + f.preparedEnv[args[0]+"\x00"] = args[1] + + case "resolve_root_symlink": + if !d.NextArg() { + continue + } + v, err := strconv.ParseBool(d.Val()) + if err != nil { + return err + } + if d.NextArg() { + return d.ArgErr() + } + f.ResolveRootSymlink = &v + case "worker": + for d.NextBlock(1) { + } + for d.NextArg() { + } + // Skip "worker" blocks in the first pass + continue + + default: + allowedDirectives := "root, split, env, resolve_root_symlink, worker" + return wrongSubDirectiveError("php or php_server", allowedDirectives, d.Val()) + } + } + } + + // Second pass: Parse only "worker" blocks + d.Reset() + for d.Next() { + for d.NextBlock(0) { + if d.Val() == "worker" { wc := workerConfig{} if d.NextArg() { wc.FileName = d.Val() @@ -552,48 +606,24 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { return errors.New(`the "file" argument must be specified`) } - f.Workers = append(f.Workers, wc) - case "root": - if !d.NextArg() { - return d.ArgErr() - } - f.Root = d.Val() - - case "split": - f.SplitPath = d.RemainingArgs() - if len(f.SplitPath) == 0 { - return d.ArgErr() - } - - case "env": - args := d.RemainingArgs() - if len(args) != 2 { - return d.ArgErr() - } - if f.Env == nil { - f.Env = make(map[string]string) - f.preparedEnv = make(frankenphp.PreparedEnv) - } - f.Env[args[0]] = args[1] - f.preparedEnv[args[0]+"\x00"] = args[1] - - case "resolve_root_symlink": - if !d.NextArg() { - continue + // Inherit environment variables from the parent php_server directive + if !filepath.IsAbs(wc.FileName) && f.Root != "" { + wc.FileName = filepath.Join(f.Root, wc.FileName) } - v, err := strconv.ParseBool(d.Val()) - if err != nil { - return err - } - if d.NextArg() { - return d.ArgErr() + if f.Env != nil { + if wc.Env == nil { + wc.Env = make(map[string]string) + } + for k, v := range f.Env { + // Only set if not already defined in the worker + if _, exists := wc.Env[k]; !exists { + wc.Env[k] = v + } + } } - f.ResolveRootSymlink = &v - default: - allowedDirectives := "root, split, env, resolve_root_symlink, worker" - return wrongSubDirectiveError("php or php_server", allowedDirectives, d.Val()) + f.Workers = append(f.Workers, wc) } } } diff --git a/frankenphp.go b/frankenphp.go index 2557286801..4de99bba8f 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -413,7 +413,7 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error } } - // If no worker was availabe send the request to non-worker threads + // If no worker was available send the request to non-worker threads handleRequestWithRegularPHPThreads(fc) return nil From 60c3e12366fb529c5eab835b9f61bd23b2b26922 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 11:49:40 +0700 Subject: [PATCH 04/51] caddy can shift FrankenPHPModules in memory for some godforsaken reason, can't rely on them staying the same --- caddy/caddy.go | 17 ++++++++++++----- context.go | 2 +- frankenphp.go | 3 ++- options.go | 4 ++-- request_options.go | 2 +- worker.go | 2 +- 6 files changed, 19 insertions(+), 11 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index bcaadc207f..40fefcb661 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -4,6 +4,8 @@ package caddy import ( + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -12,7 +14,6 @@ import ( "strconv" "strings" "time" - "unsafe" "github.com/dunglas/frankenphp/internal/fastabs" @@ -60,7 +61,7 @@ type workerConfig struct { // Directories to watch for file changes Watch []string `json:"watch,omitempty"` // ModuleID identifies which module created this worker - ModuleID uintptr `json:"module_id,omitempty"` + ModuleID string `json:"module_id,omitempty"` } type FrankenPHPApp struct { @@ -356,6 +357,8 @@ type FrankenPHPModule struct { ResolveRootSymlink *bool `json:"resolve_root_symlink,omitempty"` // Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables. Env map[string]string `json:"env,omitempty"` + // ModuleID is the module ID that created this request. + ModuleID string `json:"-"` // Workers configures the worker scripts to start. Workers []workerConfig `json:"workers,omitempty"` @@ -429,9 +432,13 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } } + data := []byte(f.Root + strings.Join(f.SplitPath, ",") + time.Now().String()) + hash := sha256.Sum256(data) + f.ModuleID = hex.EncodeToString(hash[:8]) + if len(f.Workers) > 0 { - for i := range f.Workers { - f.Workers[i].ModuleID = uintptr(unsafe.Pointer(f)) + for _, w := range f.Workers { + w.ModuleID = f.ModuleID } moduleWorkers = append(moduleWorkers, f.Workers...) } @@ -471,7 +478,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), - frankenphp.WithModuleID(uintptr(unsafe.Pointer(f))), + frankenphp.WithModuleID(f.ModuleID), ) if err != nil { diff --git a/context.go b/context.go index efe25c41ec..7b6bf218d2 100644 --- a/context.go +++ b/context.go @@ -33,7 +33,7 @@ type frankenPHPContext struct { startedAt time.Time // The module ID that created this request - moduleID uintptr + moduleID string } // fromContext extracts the frankenPHPContext from a context. diff --git a/frankenphp.go b/frankenphp.go index 4de99bba8f..15607738f5 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -407,10 +407,11 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error // Detect if a worker is available to handle this request if worker, ok := workers[fc.scriptFilename]; ok { // can handle with a global worker, or a module worker from the matching module - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { + if worker.moduleID == "" || worker.moduleID == fc.moduleID { worker.handleRequest(fc) return nil } + fc.logger.Warn(fmt.Sprintf("Module ID mismatch: %s != %s", worker.moduleID, fc.moduleID)) } // If no worker was available send the request to non-worker threads diff --git a/options.go b/options.go index 3a3040f999..da6e00931f 100644 --- a/options.go +++ b/options.go @@ -28,7 +28,7 @@ type workerOpt struct { num int env PreparedEnv watch []string - moduleID uintptr + moduleID string } // WithNumThreads configures the number of PHP threads to start. @@ -57,7 +57,7 @@ func WithMetrics(m Metrics) Option { } // WithWorkers configures the PHP workers to start, moduleID is used to identify the worker for a specific domain -func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID uintptr) Option { +func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID string) Option { return func(o *opt) error { o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch, moduleID}) diff --git a/request_options.go b/request_options.go index 494fd23435..8a1bad9b4c 100644 --- a/request_options.go +++ b/request_options.go @@ -125,7 +125,7 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { } // WithModuleID sets the module ID associated with the current request -func WithModuleID(moduleID uintptr) RequestOption { +func WithModuleID(moduleID string) RequestOption { return func(o *frankenPHPContext) error { o.moduleID = moduleID diff --git a/worker.go b/worker.go index 061d3fd95b..c3f787dd67 100644 --- a/worker.go +++ b/worker.go @@ -20,7 +20,7 @@ type worker struct { requestChan chan *frankenPHPContext threads []*phpThread threadMutex sync.RWMutex - moduleID uintptr + moduleID string } var ( From 97913f822af74d81f6d66618c7c4acb03ef2ad70 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 12:42:02 +0700 Subject: [PATCH 05/51] remove debugging statement --- frankenphp.go | 1 - 1 file changed, 1 deletion(-) diff --git a/frankenphp.go b/frankenphp.go index 15607738f5..2950b23f8b 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -411,7 +411,6 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error worker.handleRequest(fc) return nil } - fc.logger.Warn(fmt.Sprintf("Module ID mismatch: %s != %s", worker.moduleID, fc.moduleID)) } // If no worker was available send the request to non-worker threads From a22cd1925479e7a3281c17fb7eec7271830af9cf Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Fri, 18 Apr 2025 14:57:50 +0700 Subject: [PATCH 06/51] fix tests --- frankenphp_test.go | 2 +- phpmainthread_test.go | 4 ++-- scaling_test.go | 2 +- worker_test.go | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frankenphp_test.go b/frankenphp_test.go index efd226d85f..b438b522c1 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -65,7 +65,7 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * initOpts := []frankenphp.Option{frankenphp.WithLogger(opts.logger)} if opts.workerScript != "" { - initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch)) + initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch, "")) } initOpts = append(initOpts, opts.initOpts...) if opts.phpIni != nil { diff --git a/phpmainthread_test.go b/phpmainthread_test.go index 7639c8259c..26c744fe04 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -94,8 +94,8 @@ func TestTransitionThreadsWhileDoingRequests(t *testing.T) { assert.NoError(t, Init( WithNumThreads(numThreads), - WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}), - WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}), + WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}, ""), + WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}, ""), WithLogger(zap.NewNop()), )) diff --git a/scaling_test.go b/scaling_test.go index 8429dd8b75..824ccf8779 100644 --- a/scaling_test.go +++ b/scaling_test.go @@ -36,7 +36,7 @@ func TestScaleAWorkerThreadUpAndDown(t *testing.T) { assert.NoError(t, Init( WithNumThreads(2), WithMaxThreads(3), - WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}), + WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}, ""), WithLogger(zap.NewNop()), )) diff --git a/worker_test.go b/worker_test.go index f3b9a9a7e6..cb612c709f 100644 --- a/worker_test.go +++ b/worker_test.go @@ -119,8 +119,8 @@ func TestWorkerGetOpt(t *testing.T) { func ExampleServeHTTP_workers() { if err := frankenphp.Init( - frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}), - frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}), + frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}, ""), + frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}, ""), ); err != nil { panic(err) } From a4016df922411d6d5cffe1781e59d43dfa91d3ec Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 19 Apr 2025 20:54:32 +0700 Subject: [PATCH 07/51] refactor moduleID to uint64 for faster comparisons --- caddy/caddy.go | 34 +++++++++++++++++++++------------- context.go | 2 +- frankenphp.go | 4 ++-- frankenphp_test.go | 2 +- options.go | 4 ++-- phpmainthread_test.go | 4 ++-- request_options.go | 2 +- scaling_test.go | 2 +- worker.go | 2 +- worker_test.go | 4 ++-- 10 files changed, 34 insertions(+), 26 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 40fefcb661..4d83d39f7c 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -5,7 +5,7 @@ package caddy import ( "crypto/sha256" - "encoding/hex" + "encoding/binary" "encoding/json" "errors" "fmt" @@ -32,8 +32,11 @@ const defaultDocumentRoot = "public" var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") -// moduleWorkers is a package-level variable to store workers that can be accessed by both FrankenPHPModule and FrankenPHPApp -var moduleWorkers []workerConfig +// sharedState is a package-level variable to store information that can be accessed by both FrankenPHPModule and FrankenPHPApp +var sharedState struct { + ModuleIDs []uint64 + Workers []workerConfig +} func init() { caddy.RegisterModule(FrankenPHPApp{}) @@ -61,7 +64,7 @@ type workerConfig struct { // Directories to watch for file changes Watch []string `json:"watch,omitempty"` // ModuleID identifies which module created this worker - ModuleID string `json:"module_id,omitempty"` + ModuleID uint64 `json:"module_id,omitempty"` } type FrankenPHPApp struct { @@ -121,7 +124,7 @@ func (f *FrankenPHPApp) Start() error { } // Add workers from FrankenPHPModule configurations - for _, w := range moduleWorkers { + for _, w := range sharedState.Workers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) } @@ -143,13 +146,13 @@ func (f *FrankenPHPApp) Stop() error { frankenphp.DrainWorkers() } - // reset configuration so it doesn't bleed into later tests + // reset the configuration so it doesn't bleed into later tests f.Workers = nil f.NumThreads = 0 f.MaxWaitTime = 0 // reset moduleWorkers - moduleWorkers = nil + sharedState.Workers = nil return nil } @@ -358,7 +361,7 @@ type FrankenPHPModule struct { // Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables. Env map[string]string `json:"env,omitempty"` // ModuleID is the module ID that created this request. - ModuleID string `json:"-"` + ModuleID uint64 `json:"-"` // Workers configures the worker scripts to start. Workers []workerConfig `json:"workers,omitempty"` @@ -432,15 +435,20 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } } - data := []byte(f.Root + strings.Join(f.SplitPath, ",") + time.Now().String()) - hash := sha256.Sum256(data) - f.ModuleID = hex.EncodeToString(hash[:8]) - if len(f.Workers) > 0 { + envString := "" + for k, v := range f.Env { + envString += k + "=" + v + "," + } + data := []byte(f.Root + envString) + hash := sha256.Sum256(data) + f.ModuleID = binary.LittleEndian.Uint64(hash[:8]) + for _, w := range f.Workers { w.ModuleID = f.ModuleID } - moduleWorkers = append(moduleWorkers, f.Workers...) + sharedState.Workers = append(sharedState.Workers, f.Workers...) + f.logger.Warn(fmt.Sprintf("Initialized FrankenPHP module %d with %d workers", f.ModuleID, len(f.Workers))) } return nil diff --git a/context.go b/context.go index 7b6bf218d2..d6819cfede 100644 --- a/context.go +++ b/context.go @@ -33,7 +33,7 @@ type frankenPHPContext struct { startedAt time.Time // The module ID that created this request - moduleID string + moduleID uint64 } // fromContext extracts the frankenPHPContext from a context. diff --git a/frankenphp.go b/frankenphp.go index 2950b23f8b..24e6f0a6eb 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -407,13 +407,13 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error // Detect if a worker is available to handle this request if worker, ok := workers[fc.scriptFilename]; ok { // can handle with a global worker, or a module worker from the matching module - if worker.moduleID == "" || worker.moduleID == fc.moduleID { + if worker.moduleID == 0 || worker.moduleID == fc.moduleID { worker.handleRequest(fc) return nil } } - // If no worker was available send the request to non-worker threads + // If no worker was available, send the request to non-worker threads handleRequestWithRegularPHPThreads(fc) return nil diff --git a/frankenphp_test.go b/frankenphp_test.go index b438b522c1..ca08245d32 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -65,7 +65,7 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * initOpts := []frankenphp.Option{frankenphp.WithLogger(opts.logger)} if opts.workerScript != "" { - initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch, "")) + initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch, 0)) } initOpts = append(initOpts, opts.initOpts...) if opts.phpIni != nil { diff --git a/options.go b/options.go index da6e00931f..998ef3455a 100644 --- a/options.go +++ b/options.go @@ -28,7 +28,7 @@ type workerOpt struct { num int env PreparedEnv watch []string - moduleID string + moduleID uint64 } // WithNumThreads configures the number of PHP threads to start. @@ -57,7 +57,7 @@ func WithMetrics(m Metrics) Option { } // WithWorkers configures the PHP workers to start, moduleID is used to identify the worker for a specific domain -func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID string) Option { +func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID uint64) Option { return func(o *opt) error { o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch, moduleID}) diff --git a/phpmainthread_test.go b/phpmainthread_test.go index 26c744fe04..d1a1b7e5a9 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -94,8 +94,8 @@ func TestTransitionThreadsWhileDoingRequests(t *testing.T) { assert.NoError(t, Init( WithNumThreads(numThreads), - WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}, ""), - WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}, ""), + WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}, 0), + WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}, 0), WithLogger(zap.NewNop()), )) diff --git a/request_options.go b/request_options.go index 8a1bad9b4c..e5a5550fac 100644 --- a/request_options.go +++ b/request_options.go @@ -125,7 +125,7 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { } // WithModuleID sets the module ID associated with the current request -func WithModuleID(moduleID string) RequestOption { +func WithModuleID(moduleID uint64) RequestOption { return func(o *frankenPHPContext) error { o.moduleID = moduleID diff --git a/scaling_test.go b/scaling_test.go index 824ccf8779..0026b2313b 100644 --- a/scaling_test.go +++ b/scaling_test.go @@ -36,7 +36,7 @@ func TestScaleAWorkerThreadUpAndDown(t *testing.T) { assert.NoError(t, Init( WithNumThreads(2), WithMaxThreads(3), - WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}, ""), + WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}, 0), WithLogger(zap.NewNop()), )) diff --git a/worker.go b/worker.go index c3f787dd67..998285ac71 100644 --- a/worker.go +++ b/worker.go @@ -20,7 +20,7 @@ type worker struct { requestChan chan *frankenPHPContext threads []*phpThread threadMutex sync.RWMutex - moduleID string + moduleID uint64 } var ( diff --git a/worker_test.go b/worker_test.go index cb612c709f..50cf07863d 100644 --- a/worker_test.go +++ b/worker_test.go @@ -119,8 +119,8 @@ func TestWorkerGetOpt(t *testing.T) { func ExampleServeHTTP_workers() { if err := frankenphp.Init( - frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}, ""), - frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}, ""), + frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}, 0), + frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}, 0), ); err != nil { panic(err) } From a21d3f479e0118339aec8b8ad1f27ed07f4ed74b Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 19 Apr 2025 22:06:06 +0700 Subject: [PATCH 08/51] actually allow multiple workers per script filename --- caddy/caddy.go | 7 +++++-- frankenphp.go | 23 +++++++++++++++----- phpmainthread_test.go | 6 +++--- scaling.go | 15 +++++++++++-- scaling_test.go | 2 +- worker.go | 49 +++++++++++++++++++++++++++---------------- 6 files changed, 71 insertions(+), 31 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 4d83d39f7c..2771dfb7da 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -9,6 +9,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/davecgh/go-spew/spew" "net/http" "path/filepath" "strconv" @@ -121,11 +122,13 @@ func (f *FrankenPHPApp) Start() error { // Add workers from FrankenPHPApp configuration for _, w := range f.Workers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) + caddy.Log().Warn(fmt.Sprintf("Starting FrankenPHP with worker: %s", spew.Sdump(w))) } // Add workers from FrankenPHPModule configurations for _, w := range sharedState.Workers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) + caddy.Log().Warn(fmt.Sprintf("Starting FrankenPHP with worker: %s", spew.Sdump(w))) } frankenphp.Shutdown() @@ -444,8 +447,8 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { hash := sha256.Sum256(data) f.ModuleID = binary.LittleEndian.Uint64(hash[:8]) - for _, w := range f.Workers { - w.ModuleID = f.ModuleID + for i := range f.Workers { + f.Workers[i].ModuleID = f.ModuleID } sharedState.Workers = append(sharedState.Workers, f.Workers...) f.logger.Warn(fmt.Sprintf("Initialized FrankenPHP module %d with %d workers", f.ModuleID, len(f.Workers))) diff --git a/frankenphp.go b/frankenphp.go index 24e6f0a6eb..93ed965349 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -32,6 +32,7 @@ import ( "bytes" "errors" "fmt" + "github.com/davecgh/go-spew/spew" "io" "net/http" "os" @@ -405,11 +406,23 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error } // Detect if a worker is available to handle this request - if worker, ok := workers[fc.scriptFilename]; ok { - // can handle with a global worker, or a module worker from the matching module - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - worker.handleRequest(fc) - return nil + if workersList, ok := workers[fc.scriptFilename]; ok { + workersString := "" + for _, worker := range workersList { + envString := "" + for k, v := range worker.env { + envString += k + "=" + v + "," + } + workersString += strconv.FormatUint(worker.moduleID, 10) + ":" + envString + "\n" + } + fc.logger.Info(fmt.Sprintf("Available workers: %s", workersString)) + // Look for a worker with matching moduleID or a global worker (moduleID == 0) + for _, worker := range workersList { + if worker.moduleID == 0 || worker.moduleID == fc.moduleID { + fc.logger.Warn(fmt.Sprintf("Handled %d by worker %d with env: %s", fc.moduleID, worker.moduleID, spew.Sdump(worker.env))) + worker.handleRequest(fc) + return nil + } } } diff --git a/phpmainthread_test.go b/phpmainthread_test.go index d1a1b7e5a9..09343d02c1 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -179,7 +179,7 @@ func TestFinishBootingAWorkerScript(t *testing.T) { func getDummyWorker(fileName string) *worker { if workers == nil { - workers = make(map[string]*worker) + workers = make(map[string][]*worker) } worker, _ := newWorker(workerOpt{ fileName: testDataPath + "/" + fileName, @@ -211,9 +211,9 @@ func allPossibleTransitions(worker1Path string, worker2Path string) []func(*phpT thread.boot() } }, - func(thread *phpThread) { convertToWorkerThread(thread, workers[worker1Path]) }, + func(thread *phpThread) { convertToWorkerThread(thread, workers[worker1Path][0]) }, convertToInactiveThread, - func(thread *phpThread) { convertToWorkerThread(thread, workers[worker2Path]) }, + func(thread *phpThread) { convertToWorkerThread(thread, workers[worker2Path][0]) }, convertToInactiveThread, } } diff --git a/scaling.go b/scaling.go index a5ceb673b7..9087c5272f 100644 --- a/scaling.go +++ b/scaling.go @@ -160,8 +160,19 @@ func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, } // if the request has been stalled long enough, scale - if worker, ok := workers[fc.scriptFilename]; ok { - scaleWorkerThread(worker) + if workersList, ok := workers[fc.scriptFilename]; ok { + // Look for a worker with matching moduleID or a global worker (moduleID == 0) + workerFound := false + for _, worker := range workersList { + if worker.moduleID == 0 || worker.moduleID == fc.moduleID { + scaleWorkerThread(worker) + workerFound = true + break + } + } + if !workerFound { + scaleRegularThread() + } } else { scaleRegularThread() } diff --git a/scaling_test.go b/scaling_test.go index 0026b2313b..0b6a6deeb5 100644 --- a/scaling_test.go +++ b/scaling_test.go @@ -43,7 +43,7 @@ func TestScaleAWorkerThreadUpAndDown(t *testing.T) { autoScaledThread := phpThreads[2] // scale up - scaleWorkerThread(workers[workerPath]) + scaleWorkerThread(workers[workerPath][0]) assert.Equal(t, stateReady, autoScaledThread.state.get()) // on down-scale, the thread will be marked as inactive diff --git a/worker.go b/worker.go index 998285ac71..b93c261cfb 100644 --- a/worker.go +++ b/worker.go @@ -4,6 +4,7 @@ package frankenphp import "C" import ( "fmt" + "sort" "sync" "time" @@ -24,12 +25,12 @@ type worker struct { } var ( - workers map[string]*worker + workers map[string][]*worker watcherIsEnabled bool ) func initWorkers(opt []workerOpt) error { - workers = make(map[string]*worker, len(opt)) + workers = make(map[string][]*worker, len(opt)) workersReady := sync.WaitGroup{} directoriesToWatch := getDirectoriesToWatch(opt) watcherIsEnabled = len(directoriesToWatch) > 0 @@ -84,7 +85,17 @@ func newWorker(o workerOpt) (*worker, error) { requestChan: make(chan *frankenPHPContext), moduleID: o.moduleID, } - workers[absFileName] = w + + // Check if we already have workers for this filename + if _, ok := workers[absFileName]; !ok { + workers[absFileName] = make([]*worker, 0) + } + workers[absFileName] = append(workers[absFileName], w) + + // Sort workers by descending moduleID, this way FrankenPHPApp::ServeHTTP will prefer a module-specific worker over a global one + sort.Slice(workers[absFileName], func(i, j int) bool { + return workers[absFileName][i].moduleID > workers[absFileName][j].moduleID + }) return w, nil } @@ -97,23 +108,25 @@ func DrainWorkers() { func drainWorkerThreads() []*phpThread { ready := sync.WaitGroup{} drainedThreads := make([]*phpThread, 0) - for _, worker := range workers { - worker.threadMutex.RLock() - ready.Add(len(worker.threads)) - for _, thread := range worker.threads { - if !thread.state.requestSafeStateChange(stateRestarting) { - // no state change allowed == thread is shutting down - // we'll proceed to restart all other threads anyways - continue + for _, workersList := range workers { + for _, worker := range workersList { + worker.threadMutex.RLock() + ready.Add(len(worker.threads)) + for _, thread := range worker.threads { + if !thread.state.requestSafeStateChange(stateRestarting) { + // no state change allowed == thread is shutting down + // we'll proceed to restart all other threads anyways + continue + } + close(thread.drainChan) + drainedThreads = append(drainedThreads, thread) + go func(thread *phpThread) { + thread.state.waitFor(stateYielding) + ready.Done() + }(thread) } - close(thread.drainChan) - drainedThreads = append(drainedThreads, thread) - go func(thread *phpThread) { - thread.state.waitFor(stateYielding) - ready.Done() - }(thread) + worker.threadMutex.RUnlock() } - worker.threadMutex.RUnlock() } ready.Wait() From 7718a8e1bc4c5e4e5d9233252da3fe41e9d2a991 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 19 Apr 2025 22:10:14 +0700 Subject: [PATCH 09/51] remove logging --- caddy/caddy.go | 4 ---- frankenphp.go | 13 +------------ 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 2771dfb7da..d2288e525e 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/davecgh/go-spew/spew" "net/http" "path/filepath" "strconv" @@ -122,13 +121,11 @@ func (f *FrankenPHPApp) Start() error { // Add workers from FrankenPHPApp configuration for _, w := range f.Workers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) - caddy.Log().Warn(fmt.Sprintf("Starting FrankenPHP with worker: %s", spew.Sdump(w))) } // Add workers from FrankenPHPModule configurations for _, w := range sharedState.Workers { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) - caddy.Log().Warn(fmt.Sprintf("Starting FrankenPHP with worker: %s", spew.Sdump(w))) } frankenphp.Shutdown() @@ -451,7 +448,6 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { f.Workers[i].ModuleID = f.ModuleID } sharedState.Workers = append(sharedState.Workers, f.Workers...) - f.logger.Warn(fmt.Sprintf("Initialized FrankenPHP module %d with %d workers", f.ModuleID, len(f.Workers))) } return nil diff --git a/frankenphp.go b/frankenphp.go index 93ed965349..abbcfbb667 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -32,7 +32,6 @@ import ( "bytes" "errors" "fmt" - "github.com/davecgh/go-spew/spew" "io" "net/http" "os" @@ -406,20 +405,10 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error } // Detect if a worker is available to handle this request + // Look for a worker with matching moduleID or a global worker (moduleID == 0) if workersList, ok := workers[fc.scriptFilename]; ok { - workersString := "" - for _, worker := range workersList { - envString := "" - for k, v := range worker.env { - envString += k + "=" + v + "," - } - workersString += strconv.FormatUint(worker.moduleID, 10) + ":" + envString + "\n" - } - fc.logger.Info(fmt.Sprintf("Available workers: %s", workersString)) - // Look for a worker with matching moduleID or a global worker (moduleID == 0) for _, worker := range workersList { if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - fc.logger.Warn(fmt.Sprintf("Handled %d by worker %d with env: %s", fc.moduleID, worker.moduleID, spew.Sdump(worker.env))) worker.handleRequest(fc) return nil } From c7172d22c42e528935b1459092bc81047e98d7cd Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 19 Apr 2025 23:40:49 +0700 Subject: [PATCH 10/51] utility function --- scaling.go | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/scaling.go b/scaling.go index 9087c5272f..af5e7e9065 100644 --- a/scaling.go +++ b/scaling.go @@ -130,6 +130,19 @@ func scaleRegularThread() { autoScaledThreads = append(autoScaledThreads, thread) } +func getWorker(fc *frankenPHPContext) *worker { + // if the request has been stalled long enough, scale + if workersList, ok := workers[fc.scriptFilename]; ok { + // Look for a worker with matching moduleID or a global worker (moduleID == 0) + for _, worker := range workersList { + if worker.moduleID == 0 || worker.moduleID == fc.moduleID { + return worker + } + } + } + return nil +} + func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, done chan struct{}) { for { scalingMu.Lock() @@ -160,19 +173,8 @@ func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, } // if the request has been stalled long enough, scale - if workersList, ok := workers[fc.scriptFilename]; ok { - // Look for a worker with matching moduleID or a global worker (moduleID == 0) - workerFound := false - for _, worker := range workersList { - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - scaleWorkerThread(worker) - workerFound = true - break - } - } - if !workerFound { - scaleRegularThread() - } + if worker := getWorker(fc); worker != nil { + scaleWorkerThread(worker) } else { scaleRegularThread() } From f955187686d9c4a7a03cfb314f95aee4743f8faa Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 20 Apr 2025 00:32:29 +0700 Subject: [PATCH 11/51] reuse existing worker with same filename and environment when calling newWorker with a filepath that already has a suitable worker, simply add number of threads --- worker.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/worker.go b/worker.go index b93c261cfb..36e639c918 100644 --- a/worker.go +++ b/worker.go @@ -37,12 +37,16 @@ func initWorkers(opt []workerOpt) error { for _, o := range opt { worker, err := newWorker(o) - worker.threads = make([]*phpThread, 0, o.num) - workersReady.Add(o.num) if err != nil { return err } - for i := 0; i < worker.num; i++ { + if worker.threads == nil { + worker.threads = make([]*phpThread, 0, o.num) + } else { + worker.num += o.num + } + workersReady.Add(o.num) + for i := 0; i < o.num; i++ { thread := getInactivePHPThread() convertToWorkerThread(thread, worker) go func() { @@ -72,6 +76,18 @@ func newWorker(o workerOpt) (*worker, error) { return nil, fmt.Errorf("worker filename is invalid %q: %w", o.fileName, err) } + // Check if a worker with the same fileName and moduleID already exists + if existingWorkers, ok := workers[absFileName]; ok { + for _, existingWorker := range existingWorkers { + if existingWorker.moduleID == o.moduleID { + if o.moduleID == 0 { + return nil, fmt.Errorf("cannot add a multiple global workers with the same filename: %s", absFileName) + } + return existingWorker, nil + } + } + } + if o.env == nil { o.env = make(PreparedEnv, 1) } From e362fd33554ac13d8290d4e87907aa50f2e8c36f Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 20 Apr 2025 00:38:51 +0700 Subject: [PATCH 12/51] no cleanup happens between tests, so restore old global worker overwriting logic --- worker.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/worker.go b/worker.go index 36e639c918..68a11990e5 100644 --- a/worker.go +++ b/worker.go @@ -79,10 +79,7 @@ func newWorker(o workerOpt) (*worker, error) { // Check if a worker with the same fileName and moduleID already exists if existingWorkers, ok := workers[absFileName]; ok { for _, existingWorker := range existingWorkers { - if existingWorker.moduleID == o.moduleID { - if o.moduleID == 0 { - return nil, fmt.Errorf("cannot add a multiple global workers with the same filename: %s", absFileName) - } + if existingWorker.moduleID == o.moduleID && o.moduleID != 0 { return existingWorker, nil } } @@ -105,6 +102,14 @@ func newWorker(o workerOpt) (*worker, error) { // Check if we already have workers for this filename if _, ok := workers[absFileName]; !ok { workers[absFileName] = make([]*worker, 0) + } else { + // check if a global worker already exists and overwrite it instead of appending + for i, existingWorker := range workers[absFileName] { + if existingWorker.moduleID == 0 && o.moduleID == 0 { + workers[absFileName][i] = w + return w, nil + } + } } workers[absFileName] = append(workers[absFileName], w) From 00d819ff506b1c817b864d0cc9c7a2e639ee33fb Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 20 Apr 2025 11:02:33 +0700 Subject: [PATCH 13/51] add test, use getWorker(ForContext) function in frankenphp.go as well --- caddy/caddy_test.go | 54 ++++++++++++++++++++++++++++++++++++ frankenphp.go | 16 ++++------- scaling.go | 15 +--------- testdata/worker-with-env.php | 11 ++++++++ worker.go | 12 ++++++++ 5 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 testdata/worker-with-env.php diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 76282fc2bd..7e76b13835 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -6,6 +6,7 @@ import ( "net/http" "os" "path/filepath" + "strconv" "strings" "sync" "sync/atomic" @@ -119,6 +120,59 @@ func TestWorker(t *testing.T) { wg.Wait() } +func TestGlobalAndLocalWorker(t *testing.T) { + var wg sync.WaitGroup + testPortNum, _ := strconv.Atoi(testPort) + testPortTwo := strconv.Itoa(testPortNum + 1) + tester := caddytest.NewTester(t) + tester.InitServer(` + { + skip_install_trust + admin localhost:2999 + + frankenphp { + worker { + file ../testdata/worker-with-env.php + num 1 + env APP_ENV global + } + } + } + + http://localhost:`+testPort+` { + route { + php { + root ../testdata + worker { + file worker-with-env.php + num 2 + env APP_ENV local + } + } + } + } + + http://localhost:`+testPortTwo+` { + route { + php { + root ../testdata + } + } + } + `, "caddyfile") + + for i := 0; i < 100; i++ { + wg.Add(1) + + go func(i int) { + tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=local") + tester.AssertGetResponse("http://localhost:"+testPortTwo+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=global") + wg.Done() + }(i) + } + wg.Wait() +} + func TestEnv(t *testing.T) { tester := caddytest.NewTester(t) tester.InitServer(` diff --git a/frankenphp.go b/frankenphp.go index abbcfbb667..dbb2c812a0 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -405,19 +405,13 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error } // Detect if a worker is available to handle this request - // Look for a worker with matching moduleID or a global worker (moduleID == 0) - if workersList, ok := workers[fc.scriptFilename]; ok { - for _, worker := range workersList { - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - worker.handleRequest(fc) - return nil - } - } + if worker := getWorkerForContext(fc); worker != nil { + worker.handleRequest(fc) + } else { + // If no worker was available, send the request to non-worker threads + handleRequestWithRegularPHPThreads(fc) } - // If no worker was available, send the request to non-worker threads - handleRequestWithRegularPHPThreads(fc) - return nil } diff --git a/scaling.go b/scaling.go index af5e7e9065..3c71e5b9eb 100644 --- a/scaling.go +++ b/scaling.go @@ -130,19 +130,6 @@ func scaleRegularThread() { autoScaledThreads = append(autoScaledThreads, thread) } -func getWorker(fc *frankenPHPContext) *worker { - // if the request has been stalled long enough, scale - if workersList, ok := workers[fc.scriptFilename]; ok { - // Look for a worker with matching moduleID or a global worker (moduleID == 0) - for _, worker := range workersList { - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - return worker - } - } - } - return nil -} - func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, done chan struct{}) { for { scalingMu.Lock() @@ -173,7 +160,7 @@ func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, } // if the request has been stalled long enough, scale - if worker := getWorker(fc); worker != nil { + if worker := getWorkerForContext(fc); worker != nil { scaleWorkerThread(worker) } else { scaleRegularThread() diff --git a/testdata/worker-with-env.php b/testdata/worker-with-env.php new file mode 100644 index 0000000000..5570c35533 --- /dev/null +++ b/testdata/worker-with-env.php @@ -0,0 +1,11 @@ + Date: Sun, 20 Apr 2025 16:22:38 +0700 Subject: [PATCH 14/51] bring error on second global worker with the same filename again --- phpmainthread_test.go | 3 +++ worker.go | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/phpmainthread_test.go b/phpmainthread_test.go index 09343d02c1..d1c5d0dbb6 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -32,6 +32,7 @@ func TestStartAndStopTheMainThreadWithOneInactiveThread(t *testing.T) { } func TestTransitionRegularThreadToWorkerThread(t *testing.T) { + workers = nil logger = zap.NewNop() _, err := initPHPThreads(1, 1, nil) assert.NoError(t, err) @@ -56,6 +57,7 @@ func TestTransitionRegularThreadToWorkerThread(t *testing.T) { } func TestTransitionAThreadBetween2DifferentWorkers(t *testing.T) { + workers = nil logger = zap.NewNop() _, err := initPHPThreads(1, 1, nil) assert.NoError(t, err) @@ -156,6 +158,7 @@ func TestAllCommonHeadersAreCorrect(t *testing.T) { } } func TestFinishBootingAWorkerScript(t *testing.T) { + workers = nil logger = zap.NewNop() _, err := initPHPThreads(1, 1, nil) assert.NoError(t, err) diff --git a/worker.go b/worker.go index 5c39c4a8af..9a4ed34654 100644 --- a/worker.go +++ b/worker.go @@ -91,7 +91,10 @@ func newWorker(o workerOpt) (*worker, error) { // Check if a worker with the same fileName and moduleID already exists if existingWorkers, ok := workers[absFileName]; ok { for _, existingWorker := range existingWorkers { - if existingWorker.moduleID == o.moduleID && o.moduleID != 0 { + if existingWorker.moduleID == o.moduleID { + if o.moduleID == 0 { + return nil, fmt.Errorf("cannot add multiple global workers with the same filename: %s", absFileName) + } return existingWorker, nil } } From 0b22d513300988542eba54834b935c634853df91 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 10:51:41 +0700 Subject: [PATCH 15/51] refactor to using name instead of moduleID --- caddy/caddy.go | 61 ++++++++++++++++++------------- caddy/caddy_test.go | 2 +- context.go | 15 +++++--- frankenphp.go | 21 ++++++++--- frankenphp_test.go | 2 +- options.go | 7 ++-- phpmainthread_test.go | 10 ++--- request_options.go | 6 +-- scaling.go | 2 +- scaling_test.go | 4 +- worker.go | 85 ++++++++++++++----------------------------- worker_test.go | 4 +- 12 files changed, 106 insertions(+), 113 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index d2288e525e..d98f716e0b 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -4,11 +4,10 @@ package caddy import ( - "crypto/sha256" - "encoding/binary" "encoding/json" "errors" "fmt" + "github.com/davecgh/go-spew/spew" "net/http" "path/filepath" "strconv" @@ -53,7 +52,7 @@ func init() { } type workerConfig struct { - // Name for the worker + // Name for the worker. Default: the filename for FrankenPHPApp workers, filename + environment variables for FrankenPHPModule workers. Name string `json:"name,omitempty"` // FileName sets the path to the worker script. FileName string `json:"file_name,omitempty"` @@ -63,8 +62,6 @@ type workerConfig struct { Env map[string]string `json:"env,omitempty"` // Directories to watch for file changes Watch []string `json:"watch,omitempty"` - // ModuleID identifies which module created this worker - ModuleID uint64 `json:"module_id,omitempty"` } type FrankenPHPApp struct { @@ -119,13 +116,8 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithMaxWaitTime(f.MaxWaitTime), } // Add workers from FrankenPHPApp configuration - for _, w := range f.Workers { - opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) - } - - // Add workers from FrankenPHPModule configurations - for _, w := range sharedState.Workers { - opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch, w.ModuleID)) + for _, w := range append(f.Workers, sharedState.Workers...) { + opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) } frankenphp.Shutdown() @@ -133,6 +125,8 @@ func (f *FrankenPHPApp) Start() error { return err } + caddy.Log().Warn(fmt.Sprintf("FrankenPHPApp started with workers: %s", spew.Sdump(append(f.Workers, sharedState.Workers...)))) + return nil } @@ -360,8 +354,6 @@ type FrankenPHPModule struct { ResolveRootSymlink *bool `json:"resolve_root_symlink,omitempty"` // Env sets an extra environment variable to the given value. Can be specified more than once for multiple environment variables. Env map[string]string `json:"env,omitempty"` - // ModuleID is the module ID that created this request. - ModuleID uint64 `json:"-"` // Workers configures the worker scripts to start. Workers []workerConfig `json:"workers,omitempty"` @@ -436,17 +428,6 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } if len(f.Workers) > 0 { - envString := "" - for k, v := range f.Env { - envString += k + "=" + v + "," - } - data := []byte(f.Root + envString) - hash := sha256.Sum256(data) - f.ModuleID = binary.LittleEndian.Uint64(hash[:8]) - - for i := range f.Workers { - f.Workers[i].ModuleID = f.ModuleID - } sharedState.Workers = append(sharedState.Workers, f.Workers...) } @@ -479,13 +460,20 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } } + workerNames := make([]string, len(f.Workers)) + for i, w := range f.Workers { + workerNames[i] = w.Name + } + + caddy.Log().Info(fmt.Sprintf("ServeHTTP module has workers: %s", spew.Sdump(f.Workers))) + fr, err := frankenphp.NewRequestWithContext( r, documentRootOption, frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), - frankenphp.WithModuleID(f.ModuleID), + frankenphp.WithWorkerNames(workerNames), ) if err != nil { @@ -637,11 +625,32 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } + if wc.Name == "" { + name, _ := fastabs.FastAbs(wc.FileName) + if name == "" { + name = wc.FileName + } + wc.Name = name + + if len(wc.Env) > 0 { + envString := "" + for k, v := range wc.Env { + envString += k + "=" + v + "," + } + wc.Name += "#" + envString + } + } + if !strings.HasPrefix(wc.Name, "m#") { + wc.Name = "m#" + wc.Name + } + f.Workers = append(f.Workers, wc) } } } + caddy.Log().Warn(fmt.Sprintf("FrankenPHPModule UnmarshalCaddyfile with workers: %s", spew.Sdump(f.Workers))) + return nil } diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 7e76b13835..2a30b807bc 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -161,7 +161,7 @@ func TestGlobalAndLocalWorker(t *testing.T) { } `, "caddyfile") - for i := 0; i < 100; i++ { + for i := 0; i < 2; i++ { wg.Add(1) go func(i int) { diff --git a/context.go b/context.go index d6819cfede..9ddaa0e08c 100644 --- a/context.go +++ b/context.go @@ -23,6 +23,7 @@ type frankenPHPContext struct { pathInfo string scriptName string scriptFilename string + workerNames []string // Whether the request is already closed by us isDone bool @@ -31,9 +32,6 @@ type frankenPHPContext struct { done chan interface{} startedAt time.Time - - // The module ID that created this request - moduleID uint64 } // fromContext extracts the frankenPHPContext from a context. @@ -42,8 +40,7 @@ func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) { return } -// NewRequestWithContext creates a new FrankenPHP request context. -func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { +func newFrankenPHPContext(r *http.Request, opts ...RequestOption) (*frankenPHPContext, error) { fc := &frankenPHPContext{ done: make(chan interface{}), startedAt: time.Now(), @@ -94,7 +91,15 @@ func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Reques // SCRIPT_FILENAME is the absolute path of SCRIPT_NAME fc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName) + return fc, nil +} +// NewRequestWithContext creates a new FrankenPHP request context. +func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { + fc, err2 := newFrankenPHPContext(r, opts...) + if err2 != nil { + return nil, err2 + } c := context.WithValue(r.Context(), contextKey, fc) return r.WithContext(c), nil diff --git a/frankenphp.go b/frankenphp.go index dbb2c812a0..91fa899669 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -32,6 +32,7 @@ import ( "bytes" "errors" "fmt" + "github.com/davecgh/go-spew/spew" "io" "net/http" "os" @@ -292,6 +293,8 @@ func Init(options ...Option) error { return err } + logger.Warn(fmt.Sprintf("FrankenPHP initialised workers: %s", spew.Sdump(opt.workers))) + initAutoScaling(mainThread) if c := logger.Check(zapcore.InfoLevel, "FrankenPHP started 🐘"); c != nil { @@ -404,14 +407,20 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error return nil } - // Detect if a worker is available to handle this request - if worker := getWorkerForContext(fc); worker != nil { - worker.handleRequest(fc) - } else { - // If no worker was available, send the request to non-worker threads - handleRequestWithRegularPHPThreads(fc) + workerNames := append(fc.workerNames, "") + fc.logger.Warn(fmt.Sprintf("ServeHTTP Worker Names: %s", spew.Sdump(workerNames))) + for _, workerName := range workerNames { + // Detect if a worker is available to handle this request + workername := workerName + fc.scriptFilename + if worker := getWorkerForName(workername); worker != nil { + fc.logger.Info(fmt.Sprintf("Found worker: %s", workername)) + worker.handleRequest(fc) + return nil + } } + // If no worker was available, send the request to non-worker threads + handleRequestWithRegularPHPThreads(fc) return nil } diff --git a/frankenphp_test.go b/frankenphp_test.go index ca08245d32..efd226d85f 100644 --- a/frankenphp_test.go +++ b/frankenphp_test.go @@ -65,7 +65,7 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), * initOpts := []frankenphp.Option{frankenphp.WithLogger(opts.logger)} if opts.workerScript != "" { - initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch, 0)) + initOpts = append(initOpts, frankenphp.WithWorkers("workerName", testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch)) } initOpts = append(initOpts, opts.initOpts...) if opts.phpIni != nil { diff --git a/options.go b/options.go index 998ef3455a..1018e350ce 100644 --- a/options.go +++ b/options.go @@ -28,7 +28,6 @@ type workerOpt struct { num int env PreparedEnv watch []string - moduleID uint64 } // WithNumThreads configures the number of PHP threads to start. @@ -56,10 +55,10 @@ func WithMetrics(m Metrics) Option { } } -// WithWorkers configures the PHP workers to start, moduleID is used to identify the worker for a specific domain -func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string, moduleID uint64) Option { +// WithWorkers configures the PHP workers to start +func WithWorkers(name string, fileName string, num int, env map[string]string, watch []string) Option { return func(o *opt) error { - o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch, moduleID}) + o.workers = append(o.workers, workerOpt{name, fileName, num, PrepareEnv(env), watch}) return nil } diff --git a/phpmainthread_test.go b/phpmainthread_test.go index d1c5d0dbb6..27a58e1a31 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -96,8 +96,8 @@ func TestTransitionThreadsWhileDoingRequests(t *testing.T) { assert.NoError(t, Init( WithNumThreads(numThreads), - WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}, 0), - WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}, 0), + WithWorkers(worker1Name, worker1Path, 1, map[string]string{"ENV1": "foo"}, []string{}), + WithWorkers(worker2Name, worker2Path, 1, map[string]string{"ENV1": "foo"}, []string{}), WithLogger(zap.NewNop()), )) @@ -182,7 +182,7 @@ func TestFinishBootingAWorkerScript(t *testing.T) { func getDummyWorker(fileName string) *worker { if workers == nil { - workers = make(map[string][]*worker) + workers = make(map[string]*worker) } worker, _ := newWorker(workerOpt{ fileName: testDataPath + "/" + fileName, @@ -214,9 +214,9 @@ func allPossibleTransitions(worker1Path string, worker2Path string) []func(*phpT thread.boot() } }, - func(thread *phpThread) { convertToWorkerThread(thread, workers[worker1Path][0]) }, + func(thread *phpThread) { convertToWorkerThread(thread, workers[worker1Path]) }, convertToInactiveThread, - func(thread *phpThread) { convertToWorkerThread(thread, workers[worker2Path][0]) }, + func(thread *phpThread) { convertToWorkerThread(thread, workers[worker2Path]) }, convertToInactiveThread, } } diff --git a/request_options.go b/request_options.go index e5a5550fac..e1901cebbd 100644 --- a/request_options.go +++ b/request_options.go @@ -124,10 +124,10 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { } } -// WithModuleID sets the module ID associated with the current request -func WithModuleID(moduleID uint64) RequestOption { +// WithRequestLogger sets the logger associated with the current request +func WithWorkerNames(names []string) RequestOption { return func(o *frankenPHPContext) error { - o.moduleID = moduleID + o.workerNames = names return nil } diff --git a/scaling.go b/scaling.go index 3c71e5b9eb..3d0c852af2 100644 --- a/scaling.go +++ b/scaling.go @@ -160,7 +160,7 @@ func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, } // if the request has been stalled long enough, scale - if worker := getWorkerForContext(fc); worker != nil { + if worker := getWorkerForName(fc.scriptFilename); worker != nil { scaleWorkerThread(worker) } else { scaleRegularThread() diff --git a/scaling_test.go b/scaling_test.go index 0b6a6deeb5..8429dd8b75 100644 --- a/scaling_test.go +++ b/scaling_test.go @@ -36,14 +36,14 @@ func TestScaleAWorkerThreadUpAndDown(t *testing.T) { assert.NoError(t, Init( WithNumThreads(2), WithMaxThreads(3), - WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}, 0), + WithWorkers(workerName, workerPath, 1, map[string]string{}, []string{}), WithLogger(zap.NewNop()), )) autoScaledThread := phpThreads[2] // scale up - scaleWorkerThread(workers[workerPath][0]) + scaleWorkerThread(workers[workerPath]) assert.Equal(t, stateReady, autoScaledThread.state.get()) // on down-scale, the thread will be marked as inactive diff --git a/worker.go b/worker.go index 9a4ed34654..69067b8bba 100644 --- a/worker.go +++ b/worker.go @@ -4,7 +4,7 @@ package frankenphp import "C" import ( "fmt" - "sort" + "strings" "sync" "time" @@ -25,12 +25,12 @@ type worker struct { } var ( - workers map[string][]*worker + workers map[string]*worker watcherIsEnabled bool ) func initWorkers(opt []workerOpt) error { - workers = make(map[string][]*worker, len(opt)) + workers = make(map[string]*worker, len(opt)) workersReady := sync.WaitGroup{} directoriesToWatch := getDirectoriesToWatch(opt) watcherIsEnabled = len(directoriesToWatch) > 0 @@ -70,14 +70,9 @@ func initWorkers(opt []workerOpt) error { return nil } -func getWorkerForContext(fc *frankenPHPContext) *worker { - if workersList, ok := workers[fc.scriptFilename]; ok { - // Look for a worker with matching moduleID or a global worker (moduleID == 0) - for _, worker := range workersList { - if worker.moduleID == 0 || worker.moduleID == fc.moduleID { - return worker - } - } +func getWorkerForName(name string) *worker { + if wrk, ok := workers[name]; ok { + return wrk } return nil } @@ -88,16 +83,12 @@ func newWorker(o workerOpt) (*worker, error) { return nil, fmt.Errorf("worker filename is invalid %q: %w", o.fileName, err) } - // Check if a worker with the same fileName and moduleID already exists - if existingWorkers, ok := workers[absFileName]; ok { - for _, existingWorker := range existingWorkers { - if existingWorker.moduleID == o.moduleID { - if o.moduleID == 0 { - return nil, fmt.Errorf("cannot add multiple global workers with the same filename: %s", absFileName) - } - return existingWorker, nil - } - } + key := absFileName + if strings.HasPrefix(o.name, "m#") { + key = o.name + absFileName + } + if wrk := getWorkerForName(key); wrk != nil { + return wrk, nil } if o.env == nil { @@ -111,27 +102,9 @@ func newWorker(o workerOpt) (*worker, error) { num: o.num, env: o.env, requestChan: make(chan *frankenPHPContext), - moduleID: o.moduleID, } - // Check if we already have workers for this filename - if _, ok := workers[absFileName]; !ok { - workers[absFileName] = make([]*worker, 0) - } else { - // check if a global worker already exists and overwrite it instead of appending - for i, existingWorker := range workers[absFileName] { - if existingWorker.moduleID == 0 && o.moduleID == 0 { - workers[absFileName][i] = w - return w, nil - } - } - } - workers[absFileName] = append(workers[absFileName], w) - - // Sort workers by descending moduleID, this way FrankenPHPApp::ServeHTTP will prefer a module-specific worker over a global one - sort.Slice(workers[absFileName], func(i, j int) bool { - return workers[absFileName][i].moduleID > workers[absFileName][j].moduleID - }) + workers[key] = w return w, nil } @@ -144,25 +117,23 @@ func DrainWorkers() { func drainWorkerThreads() []*phpThread { ready := sync.WaitGroup{} drainedThreads := make([]*phpThread, 0) - for _, workersList := range workers { - for _, worker := range workersList { - worker.threadMutex.RLock() - ready.Add(len(worker.threads)) - for _, thread := range worker.threads { - if !thread.state.requestSafeStateChange(stateRestarting) { - // no state change allowed == thread is shutting down - // we'll proceed to restart all other threads anyways - continue - } - close(thread.drainChan) - drainedThreads = append(drainedThreads, thread) - go func(thread *phpThread) { - thread.state.waitFor(stateYielding) - ready.Done() - }(thread) + for _, worker := range workers { + worker.threadMutex.RLock() + ready.Add(len(worker.threads)) + for _, thread := range worker.threads { + if !thread.state.requestSafeStateChange(stateRestarting) { + // no state change allowed == thread is shutting down + // we'll proceed to restart all other threads anyways + continue } - worker.threadMutex.RUnlock() + close(thread.drainChan) + drainedThreads = append(drainedThreads, thread) + go func(thread *phpThread) { + thread.state.waitFor(stateYielding) + ready.Done() + }(thread) } + worker.threadMutex.RUnlock() } ready.Wait() diff --git a/worker_test.go b/worker_test.go index 50cf07863d..f3b9a9a7e6 100644 --- a/worker_test.go +++ b/worker_test.go @@ -119,8 +119,8 @@ func TestWorkerGetOpt(t *testing.T) { func ExampleServeHTTP_workers() { if err := frankenphp.Init( - frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}, 0), - frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}, 0), + frankenphp.WithWorkers("worker1", "worker1.php", 4, map[string]string{"ENV1": "foo"}, []string{}), + frankenphp.WithWorkers("worker1", "worker2.php", 2, map[string]string{"ENV2": "bar"}, []string{}), ); err != nil { panic(err) } From c6bcacfbf1ef82179a710051fdd1c39ac2c7df58 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 18:21:19 +0700 Subject: [PATCH 16/51] nicer name --- caddy/caddy.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index d98f716e0b..196eb168fd 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -625,22 +625,17 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } - if wc.Name == "" { - name, _ := fastabs.FastAbs(wc.FileName) - if name == "" { - name = wc.FileName - } - wc.Name = name - + if wc.Name == "" && len(wc.Env) > 0 { if len(wc.Env) > 0 { envString := "" for k, v := range wc.Env { envString += k + "=" + v + "," } - wc.Name += "#" + envString + envString = strings.TrimSuffix(envString, ",") + wc.Name += "env:" + envString + "_" } } - if !strings.HasPrefix(wc.Name, "m#") { + if wc.Name != "" && !strings.HasPrefix(wc.Name, "m#") { wc.Name = "m#" + wc.Name } From 53795c74885eb7127e1a9aed9a61cf931d930d43 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 18:32:06 +0700 Subject: [PATCH 17/51] nicer name --- caddy/caddy.go | 9 +-------- frankenphp.go | 10 ++-------- worker.go | 2 +- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 196eb168fd..89708165f1 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -7,7 +7,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/davecgh/go-spew/spew" "net/http" "path/filepath" "strconv" @@ -125,8 +124,6 @@ func (f *FrankenPHPApp) Start() error { return err } - caddy.Log().Warn(fmt.Sprintf("FrankenPHPApp started with workers: %s", spew.Sdump(append(f.Workers, sharedState.Workers...)))) - return nil } @@ -465,8 +462,6 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c workerNames[i] = w.Name } - caddy.Log().Info(fmt.Sprintf("ServeHTTP module has workers: %s", spew.Sdump(f.Workers))) - fr, err := frankenphp.NewRequestWithContext( r, documentRootOption, @@ -632,7 +627,7 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { envString += k + "=" + v + "," } envString = strings.TrimSuffix(envString, ",") - wc.Name += "env:" + envString + "_" + wc.Name += "env:" + envString + "_" + wc.FileName } } if wc.Name != "" && !strings.HasPrefix(wc.Name, "m#") { @@ -644,8 +639,6 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } - caddy.Log().Warn(fmt.Sprintf("FrankenPHPModule UnmarshalCaddyfile with workers: %s", spew.Sdump(f.Workers))) - return nil } diff --git a/frankenphp.go b/frankenphp.go index 91fa899669..af52379d4a 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -32,7 +32,6 @@ import ( "bytes" "errors" "fmt" - "github.com/davecgh/go-spew/spew" "io" "net/http" "os" @@ -293,8 +292,6 @@ func Init(options ...Option) error { return err } - logger.Warn(fmt.Sprintf("FrankenPHP initialised workers: %s", spew.Sdump(opt.workers))) - initAutoScaling(mainThread) if c := logger.Check(zapcore.InfoLevel, "FrankenPHP started 🐘"); c != nil { @@ -407,13 +404,10 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error return nil } - workerNames := append(fc.workerNames, "") - fc.logger.Warn(fmt.Sprintf("ServeHTTP Worker Names: %s", spew.Sdump(workerNames))) + workerNames := append(fc.workerNames, fc.scriptFilename) for _, workerName := range workerNames { // Detect if a worker is available to handle this request - workername := workerName + fc.scriptFilename - if worker := getWorkerForName(workername); worker != nil { - fc.logger.Info(fmt.Sprintf("Found worker: %s", workername)) + if worker := getWorkerForName(workerName); worker != nil { worker.handleRequest(fc) return nil } diff --git a/worker.go b/worker.go index 69067b8bba..298d912537 100644 --- a/worker.go +++ b/worker.go @@ -85,7 +85,7 @@ func newWorker(o workerOpt) (*worker, error) { key := absFileName if strings.HasPrefix(o.name, "m#") { - key = o.name + absFileName + key = o.name } if wrk := getWorkerForName(key); wrk != nil { return wrk, nil From 958537e8d47f5a70ef1e603af219e9c4aa2fb139 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 19:02:39 +0700 Subject: [PATCH 18/51] add more tests --- caddy/caddy.go | 219 ++++++++++++++++++-------------------------- caddy/caddy_test.go | 78 +++++++++++++++- worker.go | 1 - 3 files changed, 161 insertions(+), 137 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 89708165f1..a167b63954 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -51,7 +51,7 @@ func init() { } type workerConfig struct { - // Name for the worker. Default: the filename for FrankenPHPApp workers, filename + environment variables for FrankenPHPModule workers. + // Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "m#" for FrankenPHPModule workers. Name string `json:"name,omitempty"` // FileName sets the path to the worker script. FileName string `json:"file_name,omitempty"` @@ -148,6 +148,86 @@ func (f *FrankenPHPApp) Stop() error { return nil } +func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) { + wc := workerConfig{} + if d.NextArg() { + wc.FileName = d.Val() + } + + if d.NextArg() { + if d.Val() == "watch" { + wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") + } else { + v, err := strconv.Atoi(d.Val()) + if err != nil { + return wc, err + } + + wc.Num = v + } + } + + if d.NextArg() { + return wc, errors.New("FrankenPHP: too many 'worker' arguments: " + d.Val()) + } + + for d.NextBlock(1) { + v := d.Val() + switch v { + case "name": + if !d.NextArg() { + return wc, d.ArgErr() + } + wc.Name = d.Val() + case "file": + if !d.NextArg() { + return wc, d.ArgErr() + } + wc.FileName = d.Val() + case "num": + if !d.NextArg() { + return wc, d.ArgErr() + } + + v, err := strconv.Atoi(d.Val()) + if err != nil { + return wc, err + } + + wc.Num = v + case "env": + args := d.RemainingArgs() + if len(args) != 2 { + return wc, d.ArgErr() + } + if wc.Env == nil { + wc.Env = make(map[string]string) + } + wc.Env[args[0]] = args[1] + case "watch": + if !d.NextArg() { + // the default if the watch directory is left empty: + wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") + } else { + wc.Watch = append(wc.Watch, d.Val()) + } + default: + allowedDirectives := "name, file, num, env, watch" + return wc, wrongSubDirectiveError("worker", allowedDirectives, v) + } + } + + if wc.FileName == "" { + return wc, errors.New(`the "file" argument must be specified`) + } + + if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) { + wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName) + } + + return wc, nil +} + // UnmarshalCaddyfile implements caddyfile.Unmarshaler. func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { @@ -229,82 +309,10 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } case "worker": - wc := workerConfig{} - if d.NextArg() { - wc.FileName = d.Val() - } - - if d.NextArg() { - if d.Val() == "watch" { - wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") - } else { - v, err := strconv.Atoi(d.Val()) - if err != nil { - return err - } - - wc.Num = v - } - } - - if d.NextArg() { - return errors.New("FrankenPHP: too many 'worker' arguments: " + d.Val()) - } - - for d.NextBlock(1) { - v := d.Val() - switch v { - case "name": - if !d.NextArg() { - return d.ArgErr() - } - wc.Name = d.Val() - case "file": - if !d.NextArg() { - return d.ArgErr() - } - wc.FileName = d.Val() - case "num": - if !d.NextArg() { - return d.ArgErr() - } - - v, err := strconv.Atoi(d.Val()) - if err != nil { - return err - } - - wc.Num = v - case "env": - args := d.RemainingArgs() - if len(args) != 2 { - return d.ArgErr() - } - if wc.Env == nil { - wc.Env = make(map[string]string) - } - wc.Env[args[0]] = args[1] - case "watch": - if !d.NextArg() { - // the default if the watch directory is left empty: - wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") - } else { - wc.Watch = append(wc.Watch, d.Val()) - } - default: - allowedDirectives := "name, file, num, env, watch" - return wrongSubDirectiveError("worker", allowedDirectives, v) - } - } - - if wc.FileName == "" { - return errors.New(`the "file" argument must be specified`) - } - - if frankenphp.EmbeddedAppPath != "" && filepath.IsLocal(wc.FileName) { - wc.FileName = filepath.Join(frankenphp.EmbeddedAppPath, wc.FileName) + wc, err := parseWorkerConfig(d) + if err != nil { + return err } - if wc.Name == "" { // let worker initialization validate if the FileName is valid or not name, _ := fastabs.FastAbs(wc.FileName) @@ -545,62 +553,9 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { for d.Next() { for d.NextBlock(0) { if d.Val() == "worker" { - wc := workerConfig{} - if d.NextArg() { - wc.FileName = d.Val() - } - - if d.NextArg() { - v, err := strconv.Atoi(d.Val()) - if err != nil { - return err - } - wc.Num = v - } - - for d.NextBlock(1) { - switch d.Val() { - case "name": - if !d.NextArg() { - return d.ArgErr() - } - wc.Name = d.Val() - case "file": - if !d.NextArg() { - return d.ArgErr() - } - wc.FileName = d.Val() - case "num": - if !d.NextArg() { - return d.ArgErr() - } - v, err := strconv.Atoi(d.Val()) - if err != nil { - return err - } - wc.Num = v - case "env": - args := d.RemainingArgs() - if len(args) != 2 { - return d.ArgErr() - } - if wc.Env == nil { - wc.Env = make(map[string]string) - } - wc.Env[args[0]] = args[1] - case "watch": - if !d.NextArg() { - wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") - } else { - wc.Watch = append(wc.Watch, d.Val()) - } - default: - return fmt.Errorf("unknown worker subdirective: %s", d.Val()) - } - } - - if wc.FileName == "" { - return errors.New(`the "file" argument must be specified`) + wc, err := parseWorkerConfig(d) + if err != nil { + return err } // Inherit environment variables from the parent php_server directive diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 2a30b807bc..abccbcf5d5 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -120,7 +120,7 @@ func TestWorker(t *testing.T) { wg.Wait() } -func TestGlobalAndLocalWorker(t *testing.T) { +func TestGlobalAndModuleWorker(t *testing.T) { var wg sync.WaitGroup testPortNum, _ := strconv.Atoi(testPort) testPortTwo := strconv.Itoa(testPortNum + 1) @@ -146,7 +146,7 @@ func TestGlobalAndLocalWorker(t *testing.T) { worker { file worker-with-env.php num 2 - env APP_ENV local + env APP_ENV module } } } @@ -161,11 +161,11 @@ func TestGlobalAndLocalWorker(t *testing.T) { } `, "caddyfile") - for i := 0; i < 2; i++ { + for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { - tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=local") + tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=module") tester.AssertGetResponse("http://localhost:"+testPortTwo+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=global") wg.Done() }(i) @@ -173,6 +173,76 @@ func TestGlobalAndLocalWorker(t *testing.T) { wg.Wait() } +func TestNamedModuleWorkers(t *testing.T) { + var wg sync.WaitGroup + testPortNum, _ := strconv.Atoi(testPort) + testPortTwo := strconv.Itoa(testPortNum + 1) + testPortThree := strconv.Itoa(testPortNum + 2) + tester := caddytest.NewTester(t) + tester.InitServer(` + { + skip_install_trust + admin localhost:2999 + + frankenphp { + worker { + file ../testdata/worker-with-env.php + num 1 + env APP_ENV global + } + } + } + + http://localhost:`+testPort+` { + route { + php { + root ../testdata + worker { + file worker-with-env.php + num 2 + env APP_ENV one + name module1 + } + } + } + } + + http://localhost:`+testPortTwo+` { + route { + php { + root ../testdata + worker { + file worker-with-env.php + num 1 + env APP_ENV two + name module2 + } + } + } + } + + http://localhost:`+testPortThree+` { + route { + php { + root ../testdata + } + } + } + `, "caddyfile") + + for i := 0; i < 10; i++ { + wg.Add(1) + + go func(i int) { + tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=one") + tester.AssertGetResponse("http://localhost:"+testPortTwo+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=two") + tester.AssertGetResponse("http://localhost:"+testPortThree+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=global") + wg.Done() + }(i) + } + wg.Wait() +} + func TestEnv(t *testing.T) { tester := caddytest.NewTester(t) tester.InitServer(` diff --git a/worker.go b/worker.go index 298d912537..8ebf9e22b0 100644 --- a/worker.go +++ b/worker.go @@ -103,7 +103,6 @@ func newWorker(o workerOpt) (*worker, error) { env: o.env, requestChan: make(chan *frankenPHPContext), } - workers[key] = w return w, nil From 6c3922999ddb0ead36dcc3c420a3aeb02028b6e5 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 19:42:17 +0700 Subject: [PATCH 19/51] remove test case already covered by previous test --- caddy/caddy_test.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index abccbcf5d5..3996a56574 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -177,7 +177,6 @@ func TestNamedModuleWorkers(t *testing.T) { var wg sync.WaitGroup testPortNum, _ := strconv.Atoi(testPort) testPortTwo := strconv.Itoa(testPortNum + 1) - testPortThree := strconv.Itoa(testPortNum + 2) tester := caddytest.NewTester(t) tester.InitServer(` { @@ -220,14 +219,6 @@ func TestNamedModuleWorkers(t *testing.T) { } } } - - http://localhost:`+testPortThree+` { - route { - php { - root ../testdata - } - } - } `, "caddyfile") for i := 0; i < 10; i++ { @@ -236,7 +227,6 @@ func TestNamedModuleWorkers(t *testing.T) { go func(i int) { tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=one") tester.AssertGetResponse("http://localhost:"+testPortTwo+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=two") - tester.AssertGetResponse("http://localhost:"+testPortThree+"/worker-with-env.php", http.StatusOK, "Worker has APP_ENV=global") wg.Done() }(i) } From e19b7b213fddbf494f20a2329d2a3f79bb60860e Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 23:12:47 +0700 Subject: [PATCH 20/51] revert back to single variable, moduleIDs no longer relevant --- caddy/caddy.go | 15 +++++---------- worker.go | 1 - 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index a167b63954..0e940941e7 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -30,11 +30,8 @@ const defaultDocumentRoot = "public" var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") -// sharedState is a package-level variable to store information that can be accessed by both FrankenPHPModule and FrankenPHPApp -var sharedState struct { - ModuleIDs []uint64 - Workers []workerConfig -} +// FrankenPHPModule instances register their workers and FrankenPHPApp reads them at Start() time +var moduleWorkers = make([]workerConfig, 0) func init() { caddy.RegisterModule(FrankenPHPApp{}) @@ -115,7 +112,7 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithMaxWaitTime(f.MaxWaitTime), } // Add workers from FrankenPHPApp configuration - for _, w := range append(f.Workers, sharedState.Workers...) { + for _, w := range append(f.Workers, moduleWorkers...) { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) } @@ -141,9 +138,7 @@ func (f *FrankenPHPApp) Stop() error { f.Workers = nil f.NumThreads = 0 f.MaxWaitTime = 0 - - // reset moduleWorkers - sharedState.Workers = nil + moduleWorkers = nil return nil } @@ -433,7 +428,7 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } if len(f.Workers) > 0 { - sharedState.Workers = append(sharedState.Workers, f.Workers...) + moduleWorkers = append(moduleWorkers, f.Workers...) } return nil diff --git a/worker.go b/worker.go index 8ebf9e22b0..0ace2e4b77 100644 --- a/worker.go +++ b/worker.go @@ -21,7 +21,6 @@ type worker struct { requestChan chan *frankenPHPContext threads []*phpThread threadMutex sync.RWMutex - moduleID uint64 } var ( From 2ff18baee6fd02ce79f69d015566a0f3212181af Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Mon, 21 Apr 2025 23:14:29 +0700 Subject: [PATCH 21/51] update comment --- caddy/caddy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 0e940941e7..ef5569080c 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -111,7 +111,7 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithPhpIni(f.PhpIni), frankenphp.WithMaxWaitTime(f.MaxWaitTime), } - // Add workers from FrankenPHPApp configuration + // Add workers from FrankenPHPApp and FrankenPHPModule configurations for _, w := range append(f.Workers, moduleWorkers...) { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) } From 5fc1edfe2aa296a483c467a8ade698c6bf03c3d0 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 22 Apr 2025 12:03:27 +0700 Subject: [PATCH 22/51] figure out the worker to use in FrankenPHPModule::ServeHTTP --- caddy/caddy.go | 44 ++++++++++++++++++++++++++++++++------------ caddy/caddy_test.go | 10 ++-------- context.go | 19 +++++++++++++------ frankenphp.go | 15 ++++++++------- request_options.go | 6 +++--- 5 files changed, 58 insertions(+), 36 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index ef5569080c..8cd6a57335 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -427,10 +427,6 @@ func (f *FrankenPHPModule) Provision(ctx caddy.Context) error { } } - if len(f.Workers) > 0 { - moduleWorkers = append(moduleWorkers, f.Workers...) - } - return nil } @@ -460,20 +456,30 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } } - workerNames := make([]string, len(f.Workers)) - for i, w := range f.Workers { - workerNames[i] = w.Name - } - - fr, err := frankenphp.NewRequestWithContext( + filename, fc, err := frankenphp.NewFrankenPHPContext( r, documentRootOption, frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), - frankenphp.WithWorkerNames(workerNames), ) + if err != nil { + return caddyhttp.Error(http.StatusInternalServerError, err) + } + + workerName := "" + for _, w := range f.Workers { + if p, _ := fastabs.FastAbs(w.FileName); p == filename { + workerName = w.Name + } + } + err = frankenphp.WithModuleWorker(workerName)(fc) + if err != nil { + return caddyhttp.Error(http.StatusInternalServerError, err) + } + + fr, err := frankenphp.NewRequestWithExistingContext(r, fc) if err != nil { return caddyhttp.Error(http.StatusInternalServerError, err) } @@ -577,14 +583,28 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { envString += k + "=" + v + "," } envString = strings.TrimSuffix(envString, ",") - wc.Name += "env:" + envString + "_" + wc.FileName + wc.Name += "env:" + envString } } if wc.Name != "" && !strings.HasPrefix(wc.Name, "m#") { wc.Name = "m#" + wc.Name } + // Check if a worker with this filename already exists in this module + for _, existingWorker := range f.Workers { + if existingWorker.FileName == wc.FileName { + return fmt.Errorf("workers must not have duplicate filenames: %s", wc.FileName) + } + } + // Check if a worker with this name already exists + for _, existingWorker := range moduleWorkers { + if existingWorker.Name == wc.Name { + return fmt.Errorf("workers must not have duplicate names: %s", wc.Name) + } + } + f.Workers = append(f.Workers, wc) + moduleWorkers = append(moduleWorkers, f.Workers...) } } } diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 3996a56574..8e48b82ff4 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -161,7 +161,7 @@ func TestGlobalAndModuleWorker(t *testing.T) { } `, "caddyfile") - for i := 0; i < 10; i++ { + for i := 0; i < 2; i++ { wg.Add(1) go func(i int) { @@ -183,13 +183,7 @@ func TestNamedModuleWorkers(t *testing.T) { skip_install_trust admin localhost:2999 - frankenphp { - worker { - file ../testdata/worker-with-env.php - num 1 - env APP_ENV global - } - } + frankenphp } http://localhost:`+testPort+` { diff --git a/context.go b/context.go index 9ddaa0e08c..ae52befea5 100644 --- a/context.go +++ b/context.go @@ -23,7 +23,7 @@ type frankenPHPContext struct { pathInfo string scriptName string scriptFilename string - workerNames []string + workerName string // Whether the request is already closed by us isDone bool @@ -40,7 +40,7 @@ func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) { return } -func newFrankenPHPContext(r *http.Request, opts ...RequestOption) (*frankenPHPContext, error) { +func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *frankenPHPContext, error) { fc := &frankenPHPContext{ done: make(chan interface{}), startedAt: time.Now(), @@ -48,7 +48,7 @@ func newFrankenPHPContext(r *http.Request, opts ...RequestOption) (*frankenPHPCo } for _, o := range opts { if err := o(fc); err != nil { - return nil, err + return "", nil, err } } @@ -62,7 +62,7 @@ func newFrankenPHPContext(r *http.Request, opts ...RequestOption) (*frankenPHPCo } else { var err error if fc.documentRoot, err = os.Getwd(); err != nil { - return nil, err + return "", nil, err } } } @@ -91,12 +91,12 @@ func newFrankenPHPContext(r *http.Request, opts ...RequestOption) (*frankenPHPCo // SCRIPT_FILENAME is the absolute path of SCRIPT_NAME fc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName) - return fc, nil + return fc.scriptFilename, fc, nil } // NewRequestWithContext creates a new FrankenPHP request context. func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { - fc, err2 := newFrankenPHPContext(r, opts...) + _, fc, err2 := NewFrankenPHPContext(r, opts...) if err2 != nil { return nil, err2 } @@ -105,6 +105,13 @@ func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Reques return r.WithContext(c), nil } +// NewRequestWithExistingContext wraps an http request with an existing FrankenPHP request context. +func NewRequestWithExistingContext(r *http.Request, fc *frankenPHPContext) (*http.Request, error) { + c := context.WithValue(r.Context(), contextKey, fc) + + return r.WithContext(c), nil +} + func newDummyContext(requestPath string, opts ...RequestOption) (*frankenPHPContext, error) { r, err := http.NewRequest(http.MethodGet, requestPath, nil) if err != nil { diff --git a/frankenphp.go b/frankenphp.go index af52379d4a..0edaae7084 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -404,13 +404,14 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error return nil } - workerNames := append(fc.workerNames, fc.scriptFilename) - for _, workerName := range workerNames { - // Detect if a worker is available to handle this request - if worker := getWorkerForName(workerName); worker != nil { - worker.handleRequest(fc) - return nil - } + workerName := fc.workerName + if workerName == "" { + workerName = fc.scriptFilename + } + // Detect if a worker is available to handle this request + if worker := getWorkerForName(workerName); worker != nil { + worker.handleRequest(fc) + return nil } // If no worker was available, send the request to non-worker threads diff --git a/request_options.go b/request_options.go index e1901cebbd..ef7ce9012b 100644 --- a/request_options.go +++ b/request_options.go @@ -124,10 +124,10 @@ func WithRequestLogger(logger *zap.Logger) RequestOption { } } -// WithRequestLogger sets the logger associated with the current request -func WithWorkerNames(names []string) RequestOption { +// WithModuleWorker sets the worker that should handle the request +func WithModuleWorker(name string) RequestOption { return func(o *frankenPHPContext) error { - o.workerNames = names + o.workerName = name return nil } From 2c2f677d29369a3e4e637caa631226d0ed2559b3 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 22 Apr 2025 12:48:56 +0700 Subject: [PATCH 23/51] add caddy/config_tests, add --retry 5 to download --- build-static.sh | 5 +- caddy/config_test.go | 88 ++++++++++++++++++++++++++++++++++++ testdata/worker-with-env.php | 7 +-- 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 caddy/config_test.go diff --git a/build-static.sh b/build-static.sh index 930b0781a3..58b4b6dd0e 100755 --- a/build-static.sh +++ b/build-static.sh @@ -46,10 +46,9 @@ if [ -z "${SPC_OPT_BUILD_ARGS}" ]; then fi # init spc download additional args if [ -z "${SPC_OPT_DOWNLOAD_ARGS}" ]; then + SPC_OPT_DOWNLOAD_ARGS="--ignore-cache-sources=php-src --retry 5" if [ "${SPC_LIBC}" = "musl" ]; then - SPC_OPT_DOWNLOAD_ARGS="--prefer-pre-built --ignore-cache-sources=php-src" - else - SPC_OPT_DOWNLOAD_ARGS="--ignore-cache-sources=php-src" + SPC_OPT_DOWNLOAD_ARGS="${SPC_OPT_DOWNLOAD_ARGS} --prefer-pre-built" fi fi # if we need debug symbols, disable strip diff --git a/caddy/config_test.go b/caddy/config_test.go new file mode 100644 index 0000000000..7cca5ccd6d --- /dev/null +++ b/caddy/config_test.go @@ -0,0 +1,88 @@ +package caddy + +import ( + "testing" + + "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" + "github.com/stretchr/testify/require" +) + +// resetModuleWorkers resets the moduleWorkers slice for testing +func resetModuleWorkers() { + moduleWorkers = make([]workerConfig, 0) +} + +func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { + // Create a test configuration with duplicate worker filenames + configWithDuplicateFilenames := ` + { + php { + worker { + file worker-with-env.php + num 1 + } + worker { + file worker-with-env.php + num 2 + } + } + }` + + // Parse the configuration + d := caddyfile.NewTestDispenser(configWithDuplicateFilenames) + module := &FrankenPHPModule{} + + // Unmarshal the configuration + err := module.UnmarshalCaddyfile(d) + + // Verify that an error was returned + require.Error(t, err, "Expected an error when two workers in the same module have the same filename") + require.Contains(t, err.Error(), "workers must not have duplicate filenames", "Error message should mention duplicate filenames") + resetModuleWorkers() +} + +func TestModuleWorkersDuplicateNameFail(t *testing.T) { + // Create a test configuration with a worker name + configWithWorkerName1 := ` + { + php_server { + worker { + name test-worker + file ../testdata/worker-with-env.php + num 1 + } + } + }` + + // Parse the first configuration + d1 := caddyfile.NewTestDispenser(configWithWorkerName1) + module1 := &FrankenPHPModule{} + + // Unmarshal the first configuration + err := module1.UnmarshalCaddyfile(d1) + require.NoError(t, err, "First module should be configured without errors") + + // Create a second test configuration with the same worker name + configWithWorkerName2 := ` + { + php_server { + worker { + name test-worker + file ../testdata/worker-with-env.php + num 1 + } + } + }` + + // Parse the second configuration + d2 := caddyfile.NewTestDispenser(configWithWorkerName2) + module2 := &FrankenPHPModule{} + + // Unmarshal the second configuration + err = module2.UnmarshalCaddyfile(d2) + + // Verify that an error was returned + require.Error(t, err, "Expected an error when two workers have the same name") + require.Contains(t, err.Error(), "workers must not have duplicate names", "Error message should mention duplicate names") + resetModuleWorkers() +} diff --git a/testdata/worker-with-env.php b/testdata/worker-with-env.php index 5570c35533..a999957e16 100644 --- a/testdata/worker-with-env.php +++ b/testdata/worker-with-env.php @@ -1,11 +1,8 @@  Date: Tue, 22 Apr 2025 14:23:18 +0700 Subject: [PATCH 24/51] add caddy/config_tests --- caddy/admin_test.go | 3 + caddy/caddy.go | 9 +- caddy/caddy_test.go | 3 + caddy/config_test.go | 191 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 202 insertions(+), 4 deletions(-) diff --git a/caddy/admin_test.go b/caddy/admin_test.go index 4a970ffda2..4164d297ef 100644 --- a/caddy/admin_test.go +++ b/caddy/admin_test.go @@ -1,3 +1,6 @@ +//go:build !nocaddy +// +build !nocaddy + package caddy_test import ( diff --git a/caddy/caddy.go b/caddy/caddy.go index 8cd6a57335..8ceaf2180e 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -576,17 +576,20 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } - if wc.Name == "" && len(wc.Env) > 0 { + if wc.Name == "" { if len(wc.Env) > 0 { envString := "" for k, v := range wc.Env { envString += k + "=" + v + "," } envString = strings.TrimSuffix(envString, ",") + // Environment is required in order not to collide with other FrankenPHPModules + // Filename is required to avoid collisions with other workers in this module wc.Name += "env:" + envString } + wc.Name += "_" + wc.FileName } - if wc.Name != "" && !strings.HasPrefix(wc.Name, "m#") { + if !strings.HasPrefix(wc.Name, "m#") { wc.Name = "m#" + wc.Name } @@ -604,7 +607,7 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } f.Workers = append(f.Workers, wc) - moduleWorkers = append(moduleWorkers, f.Workers...) + moduleWorkers = append(moduleWorkers, wc) } } } diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 8e48b82ff4..6518a46193 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -1,3 +1,6 @@ +//go:build !nocaddy +// +build !nocaddy + package caddy_test import ( diff --git a/caddy/config_test.go b/caddy/config_test.go index 7cca5ccd6d..7ad20b5e3c 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -1,4 +1,7 @@ -package caddy +//go:build !noconfig +// +build !noconfig + +package caddy import ( "testing" @@ -86,3 +89,189 @@ func TestModuleWorkersDuplicateNameFail(t *testing.T) { require.Contains(t, err.Error(), "workers must not have duplicate names", "Error message should mention duplicate names") resetModuleWorkers() } + +func TestModuleWorkersWithDifferentFilenames(t *testing.T) { + // Create a test configuration with different worker filenames + configWithDifferentFilenames := ` + { + php { + worker ../testdata/worker-with-env.php + worker ../testdata/worker-with-counter.php + } + }` + + // Parse the configuration + d := caddyfile.NewTestDispenser(configWithDifferentFilenames) + module := &FrankenPHPModule{} + + // Unmarshal the configuration + err := module.UnmarshalCaddyfile(d) + + // Verify that no error was returned + require.NoError(t, err, "Expected no error when two workers in the same module have different filenames") + + // Verify that both workers were added to the module + require.Len(t, module.Workers, 2, "Expected two workers to be added to the module") + require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "First worker should have the correct filename") + require.Equal(t, "../testdata/worker-with-counter.php", module.Workers[1].FileName, "Second worker should have the correct filename") + + resetModuleWorkers() +} + +func TestModuleWorkersDifferentNamesSucceed(t *testing.T) { + // Create a test configuration with a worker name + configWithWorkerName1 := ` + { + php_server { + worker { + name test-worker-1 + file ../testdata/worker-with-env.php + num 1 + } + } + }` + + // Parse the first configuration + d1 := caddyfile.NewTestDispenser(configWithWorkerName1) + module1 := &FrankenPHPModule{} + + // Unmarshal the first configuration + err := module1.UnmarshalCaddyfile(d1) + require.NoError(t, err, "First module should be configured without errors") + + // Create a second test configuration with a different worker name + configWithWorkerName2 := ` + { + php_server { + worker { + name test-worker-2 + file ../testdata/worker-with-env.php + num 1 + } + } + }` + + // Parse the second configuration + d2 := caddyfile.NewTestDispenser(configWithWorkerName2) + module2 := &FrankenPHPModule{} + + // Unmarshal the second configuration + err = module2.UnmarshalCaddyfile(d2) + + // Verify that no error was returned + require.NoError(t, err, "Expected no error when two workers have different names") + + // Verify that both workers were added to moduleWorkers + require.Len(t, moduleWorkers, 2, "Expected two workers to be added to moduleWorkers") + require.Equal(t, "m#test-worker-1", moduleWorkers[0].Name, "First worker should have the correct name") + require.Equal(t, "m#test-worker-2", moduleWorkers[1].Name, "Second worker should have the correct name") + + resetModuleWorkers() +} + +func TestModuleWorkerWithEnvironmentVariables(t *testing.T) { + // Create a test configuration with environment variables + configWithEnv := ` + { + php { + worker { + file ../testdata/worker-with-env.php + num 1 + env APP_ENV production + env DEBUG true + } + } + }` + + // Parse the configuration + d := caddyfile.NewTestDispenser(configWithEnv) + module := &FrankenPHPModule{} + + // Unmarshal the configuration + err := module.UnmarshalCaddyfile(d) + + // Verify that no error was returned + require.NoError(t, err, "Expected no error when configuring a worker with environment variables") + + // Verify that the worker was added to the module + require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") + require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") + + // Verify that the environment variables were set correctly + require.Len(t, module.Workers[0].Env, 2, "Expected two environment variables") + require.Equal(t, "production", module.Workers[0].Env["APP_ENV"], "APP_ENV should be set to production") + require.Equal(t, "true", module.Workers[0].Env["DEBUG"], "DEBUG should be set to true") + + resetModuleWorkers() +} + +func TestModuleWorkerWithWatchConfiguration(t *testing.T) { + // Create a test configuration with watch directories + configWithWatch := ` + { + php { + worker { + file ../testdata/worker-with-env.php + num 1 + watch + watch ./src/**/*.php + watch ./config/**/*.yaml + } + } + }` + + // Parse the configuration + d := caddyfile.NewTestDispenser(configWithWatch) + module := &FrankenPHPModule{} + + // Unmarshal the configuration + err := module.UnmarshalCaddyfile(d) + + // Verify that no error was returned + require.NoError(t, err, "Expected no error when configuring a worker with watch directories") + + // Verify that the worker was added to the module + require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") + require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") + + // Verify that the watch directories were set correctly + require.Len(t, module.Workers[0].Watch, 3, "Expected three watch patterns") + require.Equal(t, "./**/*.{php,yaml,yml,twig,env}", module.Workers[0].Watch[0], "First watch pattern should be the default") + require.Equal(t, "./src/**/*.php", module.Workers[0].Watch[1], "Second watch pattern should match the configuration") + require.Equal(t, "./config/**/*.yaml", module.Workers[0].Watch[2], "Third watch pattern should match the configuration") + + resetModuleWorkers() +} + +func TestModuleWorkerWithCustomName(t *testing.T) { + // Create a test configuration with a custom worker name + configWithCustomName := ` + { + php { + worker { + file ../testdata/worker-with-env.php + num 1 + name custom-worker-name + } + } + }` + + // Parse the configuration + d := caddyfile.NewTestDispenser(configWithCustomName) + module := &FrankenPHPModule{} + + // Unmarshal the configuration + err := module.UnmarshalCaddyfile(d) + + // Verify that no error was returned + require.NoError(t, err, "Expected no error when configuring a worker with a custom name") + + // Verify that the worker was added to the module + require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") + require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") + + // Verify that the worker was added to moduleWorkers with the m# prefix + require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") + + resetModuleWorkers() +} From af18d046b265a2bac55f384510699a54a803f17c Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 22 Apr 2025 15:43:24 +0700 Subject: [PATCH 25/51] sum up logic a bit, put worker thread addition into moduleWorkers parsing, before workers are actually created --- caddy/caddy.go | 57 +++++++++++++++++++++++++++++++++++++------- caddy/caddy_test.go | 2 +- caddy/config_test.go | 8 ++++--- worker.go | 2 -- 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 8ceaf2180e..fe3e156aed 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -9,6 +9,7 @@ import ( "fmt" "net/http" "path/filepath" + "sort" "strconv" "strings" "time" @@ -491,6 +492,30 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c return nil } +func getEnvString(env map[string]string) string { + // 1. Create a slice of keys from the map + keys := make([]string, 0, len(env)) + for k := range env { + keys = append(keys, k) + } + + // 2. Sort the keys alphabetically + sort.Strings(keys) + + // 3. Build the string using sorted keys + var builder strings.Builder + for i, k := range keys { + v := env[k] // Get value from the original map using the sorted key + if i > 0 { + } + builder.WriteString(k) + builder.WriteString("=") + builder.WriteString(v) + builder.WriteString(",") + } + return strings.TrimSuffix(builder.String(), ",") +} + // UnmarshalCaddyfile implements caddyfile.Unmarshaler. func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // First pass: Parse all directives except "worker" @@ -576,17 +601,14 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } + envString := getEnvString(wc.Env) + if wc.Name == "" { if len(wc.Env) > 0 { - envString := "" - for k, v := range wc.Env { - envString += k + "=" + v + "," - } - envString = strings.TrimSuffix(envString, ",") // Environment is required in order not to collide with other FrankenPHPModules - // Filename is required to avoid collisions with other workers in this module wc.Name += "env:" + envString } + // Filename is required to avoid collisions with other workers in this module wc.Name += "_" + wc.FileName } if !strings.HasPrefix(wc.Name, "m#") { @@ -599,10 +621,27 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { return fmt.Errorf("workers must not have duplicate filenames: %s", wc.FileName) } } - // Check if a worker with this name already exists - for _, existingWorker := range moduleWorkers { + // Check if a worker with this name and a different environment or filename already exists + for i, existingWorker := range moduleWorkers { if existingWorker.Name == wc.Name { - return fmt.Errorf("workers must not have duplicate names: %s", wc.Name) + efs, _ := fastabs.FastAbs(existingWorker.FileName) + wcfs, _ := fastabs.FastAbs(wc.FileName) + if efs != wcfs { + return fmt.Errorf("module workers with different filenames must not have duplicate names: %s", wc.Name) + } + if len(existingWorker.Env) != len(wc.Env) { + // If lengths are different, the maps are definitely different + return fmt.Errorf("module workers with different environments must not have duplicate names: %s", wc.Name) + } + // If lengths are the same, iterate and compare key-value pairs + if getEnvString(existingWorker.Env) != envString { + return fmt.Errorf("module workers with different environments must not have duplicate names: %s", wc.Name) + } + // If we reach this point, the maps are equal. + // Increase the number of threads for this worker and skip adding it to the moduleWorkers again + moduleWorkers[i].Num += wc.Num + f.Workers = append(f.Workers, wc) + return nil } } diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 6518a46193..c31fd505a6 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -164,7 +164,7 @@ func TestGlobalAndModuleWorker(t *testing.T) { } `, "caddyfile") - for i := 0; i < 2; i++ { + for i := 0; i < 10; i++ { wg.Add(1) go func(i int) { diff --git a/caddy/config_test.go b/caddy/config_test.go index 7ad20b5e3c..cb225dce6c 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -44,11 +44,12 @@ func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { resetModuleWorkers() } -func TestModuleWorkersDuplicateNameFail(t *testing.T) { +func TestModuleWorkersDuplicateNameWithDifferentEnvironmentsFail(t *testing.T) { // Create a test configuration with a worker name configWithWorkerName1 := ` { php_server { + env APP_ENV something worker { name test-worker file ../testdata/worker-with-env.php @@ -70,6 +71,7 @@ func TestModuleWorkersDuplicateNameFail(t *testing.T) { { php_server { worker { + env APP_ENV mismatch name test-worker file ../testdata/worker-with-env.php num 1 @@ -85,8 +87,8 @@ func TestModuleWorkersDuplicateNameFail(t *testing.T) { err = module2.UnmarshalCaddyfile(d2) // Verify that an error was returned - require.Error(t, err, "Expected an error when two workers have the same name") - require.Contains(t, err.Error(), "workers must not have duplicate names", "Error message should mention duplicate names") + require.Error(t, err, "Expected an error when two workers have the same name, but different environments") + require.Contains(t, err.Error(), "module workers with different environments must not have duplicate names", "Error message should mention duplicate names") resetModuleWorkers() } diff --git a/worker.go b/worker.go index 0ace2e4b77..3c74609708 100644 --- a/worker.go +++ b/worker.go @@ -41,8 +41,6 @@ func initWorkers(opt []workerOpt) error { } if worker.threads == nil { worker.threads = make([]*phpThread, 0, o.num) - } else { - worker.num += o.num } workersReady.Add(o.num) for i := 0; i < o.num; i++ { From dd5dc9bea0a406a07ca5f38c63aedc2531c8a67b Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Wed, 23 Apr 2025 09:10:22 +0700 Subject: [PATCH 26/51] implement suggestions as far as possible --- context.go | 18 +++++++++--------- frankenphp.go | 6 +----- scaling.go | 2 +- worker.go | 16 +++++++--------- 4 files changed, 18 insertions(+), 24 deletions(-) diff --git a/context.go b/context.go index ae52befea5..a239549eac 100644 --- a/context.go +++ b/context.go @@ -40,6 +40,7 @@ func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) { return } +// NewFrankenPHPContext parses out the correct filename and context to pass to NewRequestWithExistingContext func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *frankenPHPContext, error) { fc := &frankenPHPContext{ done: make(chan interface{}), @@ -94,22 +95,21 @@ func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *fran return fc.scriptFilename, fc, nil } +// NewRequestWithExistingContext wraps an http request with an existing FrankenPHP request context. +func NewRequestWithExistingContext(r *http.Request, fc *frankenPHPContext) *http.Request { + c := context.WithValue(r.Context(), contextKey, fc) + + return r.WithContext(c) +} + // NewRequestWithContext creates a new FrankenPHP request context. func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { _, fc, err2 := NewFrankenPHPContext(r, opts...) if err2 != nil { return nil, err2 } - c := context.WithValue(r.Context(), contextKey, fc) - - return r.WithContext(c), nil -} - -// NewRequestWithExistingContext wraps an http request with an existing FrankenPHP request context. -func NewRequestWithExistingContext(r *http.Request, fc *frankenPHPContext) (*http.Request, error) { - c := context.WithValue(r.Context(), contextKey, fc) - return r.WithContext(c), nil + return NewRequestWithExistingContext(r, fc), nil } func newDummyContext(requestPath string, opts ...RequestOption) (*frankenPHPContext, error) { diff --git a/frankenphp.go b/frankenphp.go index 0edaae7084..e0c5de1b0b 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -404,12 +404,8 @@ func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) error return nil } - workerName := fc.workerName - if workerName == "" { - workerName = fc.scriptFilename - } // Detect if a worker is available to handle this request - if worker := getWorkerForName(workerName); worker != nil { + if worker, ok := workers[getWorkerKey(fc.workerName, fc.scriptFilename)]; ok { worker.handleRequest(fc) return nil } diff --git a/scaling.go b/scaling.go index 3d0c852af2..4775937b9d 100644 --- a/scaling.go +++ b/scaling.go @@ -160,7 +160,7 @@ func startUpscalingThreads(maxScaledThreads int, scale chan *frankenPHPContext, } // if the request has been stalled long enough, scale - if worker := getWorkerForName(fc.scriptFilename); worker != nil { + if worker, ok := workers[getWorkerKey(fc.workerName, fc.scriptFilename)]; ok { scaleWorkerThread(worker) } else { scaleRegularThread() diff --git a/worker.go b/worker.go index 3c74609708..7c2f6c1ee0 100644 --- a/worker.go +++ b/worker.go @@ -67,11 +67,12 @@ func initWorkers(opt []workerOpt) error { return nil } -func getWorkerForName(name string) *worker { - if wrk, ok := workers[name]; ok { - return wrk +func getWorkerKey(name string, filename string) string { + key := filename + if strings.HasPrefix(name, "m#") { + key = name } - return nil + return key } func newWorker(o workerOpt) (*worker, error) { @@ -80,11 +81,8 @@ func newWorker(o workerOpt) (*worker, error) { return nil, fmt.Errorf("worker filename is invalid %q: %w", o.fileName, err) } - key := absFileName - if strings.HasPrefix(o.name, "m#") { - key = o.name - } - if wrk := getWorkerForName(key); wrk != nil { + key := getWorkerKey(o.name, absFileName) + if wrk, ok := workers[key]; ok { return wrk, nil } From c4937ac172a69e72bd90abeacf1e281df27e21d8 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Wed, 23 Apr 2025 09:16:28 +0700 Subject: [PATCH 27/51] fixup --- caddy/caddy.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index fe3e156aed..5eb689ab41 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -480,10 +480,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c return caddyhttp.Error(http.StatusInternalServerError, err) } - fr, err := frankenphp.NewRequestWithExistingContext(r, fc) - if err != nil { - return caddyhttp.Error(http.StatusInternalServerError, err) - } + fr := frankenphp.NewRequestWithExistingContext(r, fc) if err = frankenphp.ServeHTTP(w, fr); err != nil { return caddyhttp.Error(http.StatusInternalServerError, err) From 401d25d0aab9e7bb7a83f417c71bb53004c15a27 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Wed, 23 Apr 2025 14:09:28 +0700 Subject: [PATCH 28/51] remove tags --- caddy/admin_test.go | 3 --- caddy/caddy_test.go | 3 --- caddy/config_test.go | 5 +---- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/caddy/admin_test.go b/caddy/admin_test.go index 4164d297ef..4a970ffda2 100644 --- a/caddy/admin_test.go +++ b/caddy/admin_test.go @@ -1,6 +1,3 @@ -//go:build !nocaddy -// +build !nocaddy - package caddy_test import ( diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index c31fd505a6..5c358d6683 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -1,6 +1,3 @@ -//go:build !nocaddy -// +build !nocaddy - package caddy_test import ( diff --git a/caddy/config_test.go b/caddy/config_test.go index cb225dce6c..54d1aa962b 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -1,7 +1,4 @@ -//go:build !noconfig -// +build !noconfig - -package caddy +package caddy import ( "testing" From a4443615934f509b7b6af02a35e91cf57ab3cf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Fri, 18 Apr 2025 14:22:58 +0200 Subject: [PATCH 29/51] feat: download the mostly static binary when possible (#1467) * feat: download the mostly static binary when possible * cs --- install.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 6b76a87c8c..2151d31fbc 100755 --- a/install.sh +++ b/install.sh @@ -11,6 +11,7 @@ DEST=${BIN_DIR}/frankenphp OS=$(uname -s) ARCH=$(uname -m) +GNU="" if type "tput" >/dev/null 2>&1; then bold=$(tput bold || true) @@ -31,6 +32,11 @@ Linux*) THE_ARCH_BIN="" ;; esac + + if getconf GNU_LIBC_VERSION >/dev/null 2>&1; then + THE_ARCH_BIN="${THE_ARCH_BIN}-gnu" + GNU=" (glibc)" + fi ;; Darwin*) case ${ARCH} in @@ -58,7 +64,7 @@ fi SUDO="" -echo "📦 Downloading ${bold}FrankenPHP${normal} for ${OS} (${ARCH}):" +echo "📦 Downloading ${bold}FrankenPHP${normal} for ${OS}${GNU} (${ARCH}):" # check if $DEST is writable and suppress an error message touch "${DEST}" 2>/dev/null From 6ebea60f365b873a90f2b581a7f410b7314bc6e2 Mon Sep 17 00:00:00 2001 From: Indra Gunawan Date: Tue, 22 Apr 2025 17:27:29 +0800 Subject: [PATCH 30/51] docs: remove wildcard matcher from root directive (#1513) --- caddy/caddy_test.go | 4 +- docs/cn/config.md | 4 +- docs/cn/laravel.md | 2 +- docs/config.md | 4 +- docs/fr/config.md | 6 +- docs/fr/laravel.md | 4 +- docs/laravel.md | 2 +- docs/ru/config.md | 24 +-- docs/ru/laravel.md | 2 +- docs/tr/config.md | 326 +++++++++++++++++------------------ docs/tr/laravel.md | 148 ++++++++-------- testdata/Caddyfile | 2 +- testdata/benchmark.Caddyfile | 2 +- 13 files changed, 265 insertions(+), 265 deletions(-) diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 5c358d6683..159d514848 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -388,7 +388,7 @@ func TestPHPServerDirective(t *testing.T) { } localhost:`+testPort+` { - root * ../testdata + root ../testdata php_server } `, "caddyfile") @@ -412,7 +412,7 @@ func TestPHPServerDirectiveDisableFileServer(t *testing.T) { } localhost:`+testPort+` { - root * ../testdata + root ../testdata php_server { file_server off } diff --git a/docs/cn/config.md b/docs/cn/config.md index ba27cd5c11..870af359ba 100644 --- a/docs/cn/config.md +++ b/docs/cn/config.md @@ -81,12 +81,12 @@ localhost { } app.example.com { - root * /path/to/app/public + root /path/to/app/public php_server } other.example.com { - root * /path/to/other/public + root /path/to/other/public php_server } # ... diff --git a/docs/cn/laravel.md b/docs/cn/laravel.md index db47fe2a5a..d35a2a0fe5 100644 --- a/docs/cn/laravel.md +++ b/docs/cn/laravel.md @@ -27,7 +27,7 @@ docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp # 服务器的域名 localhost { # 将 webroot 设置为 public/ 目录 - root * public/ + root public/ # 启用压缩(可选) encode zstd br gzip # 执行当前目录中的 PHP 文件并提供资产 diff --git a/docs/config.md b/docs/config.md index fd81a2b656..f0b46d83bf 100644 --- a/docs/config.md +++ b/docs/config.md @@ -89,12 +89,12 @@ You can also define multiple workers if you serve multiple apps on the same serv } app.example.com { - root * /path/to/app/public + root /path/to/app/public php_server } other.example.com { - root * /path/to/other/public + root /path/to/other/public php_server } diff --git a/docs/fr/config.md b/docs/fr/config.md index 232efbb0f9..740be3a01c 100644 --- a/docs/fr/config.md +++ b/docs/fr/config.md @@ -53,7 +53,7 @@ En option, le nombre de threads à créer et les [workers](worker.md) à démarr num_threads # Définit le nombre de threads PHP à démarrer. Par défaut : 2x le nombre de CPUs disponibles. max_threads # Limite le nombre de threads PHP supplémentaires qui peuvent être démarrés au moment de l'exécution. Valeur par défaut : num_threads. Peut être mis à 'auto'. max_wait_time # Définit le temps maximum pendant lequel une requête peut attendre un thread PHP libre avant d'être interrompue. Valeur par défaut : désactivé. - php_ini Définit une directive php.ini. Peut être utilisé plusieurs fois pour définir plusieurs directives. + php_ini Définit une directive php.ini. Peut être utilisé plusieurs fois pour définir plusieurs directives. worker { file # Définit le chemin vers le script worker. num # Définit le nombre de threads PHP à démarrer, par défaut 2x le nombre de CPUs disponibles. @@ -90,12 +90,12 @@ Vous pouvez aussi définir plusieurs workers si vous servez plusieurs applicatio } app.example.com { - root * /path/to/app/public + root /path/to/app/public php_server } other.example.com { - root * /path/to/other/public + root /path/to/other/public php_server } diff --git a/docs/fr/laravel.md b/docs/fr/laravel.md index 7fbdfad0e0..f96d0c8c75 100644 --- a/docs/fr/laravel.md +++ b/docs/fr/laravel.md @@ -27,7 +27,7 @@ Vous pouvez également exécuter vos projets Laravel avec FrankenPHP depuis votr # Le nom de domaine de votre serveur localhost { # Définir le répertoire racine sur le dossier public/ - root * public/ + root public/ # Autoriser la compression (optionnel) encode zstd br gzip # Exécuter les scripts PHP du dossier public/ et servir les assets @@ -108,7 +108,7 @@ Suivez ces étapes pour empaqueter votre application Laravel en tant que binaire # Installez les dépendances RUN composer install --ignore-platform-reqs --no-dev -a - # Construire le binaire statique + # Construire le binaire statique WORKDIR /go/src/app/ RUN EMBED=dist/app/ ./build-static.sh ``` diff --git a/docs/laravel.md b/docs/laravel.md index d20450f182..1a240c9d23 100644 --- a/docs/laravel.md +++ b/docs/laravel.md @@ -27,7 +27,7 @@ Alternatively, you can run your Laravel projects with FrankenPHP from your local # The domain name of your server localhost { # Set the webroot to the public/ directory - root * public/ + root public/ # Enable compression (optional) encode zstd br gzip # Execute PHP files from the public/ directory and serve assets diff --git a/docs/ru/config.md b/docs/ru/config.md index d1f948a305..941406501f 100644 --- a/docs/ru/config.md +++ b/docs/ru/config.md @@ -2,7 +2,7 @@ FrankenPHP, Caddy, а также модули Mercure и Vulcain могут быть настроены с использованием [конфигурационных форматов, поддерживаемых Caddy](https://caddyserver.com/docs/getting-started#your-first-config). -В [Docker-образах](docker.md) файл `Caddyfile` находится по пути `/etc/caddy/Caddyfile`. +В [Docker-образах](docker.md) файл `Caddyfile` находится по пути `/etc/caddy/Caddyfile`. Статический бинарный файл будет искать `Caddyfile` в директории запуска. PHP можно настроить [с помощью файла `php.ini`](https://www.php.net/manual/en/configuration.file.php). @@ -86,12 +86,12 @@ localhost { } app.example.com { - root * /path/to/app/public + root /path/to/app/public php_server } other.example.com { - root * /path/to/other/public + root /path/to/other/public php_server } @@ -152,7 +152,7 @@ php_server [] { } ``` -Если директория для `watch` не указана, по умолчанию будет использоваться путь `./**/*.{php,yaml,yml,twig,env}`, +Если директория для `watch` не указана, по умолчанию будет использоваться путь `./**/*.{php,yaml,yml,twig,env}`, который отслеживает все файлы с расширениями `.php`, `.yaml`, `.yml`, `.twig` и `.env` в директории, где был запущен процесс FrankenPHP, и во всех её поддиректориях. Вы также можете указать одну или несколько директорий с использованием [шаблона имён файлов](https://pkg.go.dev/path/filepath#Match): ```caddyfile @@ -169,12 +169,12 @@ php_server [] { } ``` -* Шаблон `**` указывает на рекурсивное отслеживание. -* Директории могут быть указаны относительно директории запуска FrankenPHP. -* Если у вас определено несколько workers, все они будут перезапущены при изменении файлов. +* Шаблон `**` указывает на рекурсивное отслеживание. +* Директории могут быть указаны относительно директории запуска FrankenPHP. +* Если у вас определено несколько workers, все они будут перезапущены при изменении файлов. * Избегайте отслеживания файлов, создаваемых во время выполнения (например, логов), так как это может вызвать нежелательные перезапуски. -Механизм отслеживания файлов основан на [e-dant/watcher](https://github.com/e-dant/watcher). +Механизм отслеживания файлов основан на [e-dant/watcher](https://github.com/e-dant/watcher). ### Полный дуплекс (HTTP/1) @@ -192,7 +192,7 @@ php_server [] { > [!CAUTION] > -> Включение этой опции может привести к зависанию устаревших HTTP/1.x клиентов, которые не поддерживают полный дуплекс. +> Включение этой опции может привести к зависанию устаревших HTTP/1.x клиентов, которые не поддерживают полный дуплекс. > Настройка также доступна через переменную окружения `CADDY_GLOBAL_OPTIONS`: ```sh @@ -207,8 +207,8 @@ CADDY_GLOBAL_OPTIONS="servers { Следующие переменные окружения могут быть использованы для добавления директив в `Caddyfile` без его изменения: -* `SERVER_NAME`: изменение [адресов для прослушивания](https://caddyserver.com/docs/caddyfile/concepts#addresses); предоставленные хостнеймы также будут использованы для генерации TLS-сертификата. -* `CADDY_GLOBAL_OPTIONS`: добавление [глобальных опций](https://caddyserver.com/docs/caddyfile/options). +* `SERVER_NAME`: изменение [адресов для прослушивания](https://caddyserver.com/docs/caddyfile/concepts#addresses); предоставленные хостнеймы также будут использованы для генерации TLS-сертификата. +* `CADDY_GLOBAL_OPTIONS`: добавление [глобальных опций](https://caddyserver.com/docs/caddyfile/options). * `FRANKENPHP_CONFIG`: добавление конфигурации в директиву `frankenphp`. Как и для FPM и CLI SAPIs, переменные окружения по умолчанию доступны в суперглобальной переменной `$_SERVER`. @@ -217,7 +217,7 @@ CADDY_GLOBAL_OPTIONS="servers { ## Конфигурация PHP -Для загрузки [дополнительных конфигурационных файлов PHP](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) можно использовать переменную окружения `PHP_INI_SCAN_DIR`. +Для загрузки [дополнительных конфигурационных файлов PHP](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) можно использовать переменную окружения `PHP_INI_SCAN_DIR`. Если она установлена, PHP загрузит все файлы с расширением `.ini`, находящиеся в указанных директориях. ## Включение режима отладки diff --git a/docs/ru/laravel.md b/docs/ru/laravel.md index 053f628b25..4dda990fa8 100644 --- a/docs/ru/laravel.md +++ b/docs/ru/laravel.md @@ -27,7 +27,7 @@ docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp # Доменное имя вашего сервера localhost { # Укажите веб-корень как директорию public/ - root * public/ + root public/ # Включите сжатие (опционально) encode zstd br gzip # Выполняйте PHP-файлы из директории public/ и обслуживайте статические файлы diff --git a/docs/tr/config.md b/docs/tr/config.md index 81a8edf3a5..605cd6be0e 100644 --- a/docs/tr/config.md +++ b/docs/tr/config.md @@ -1,163 +1,163 @@ -# Konfigürasyon - -FrankenPHP, Caddy'nin yanı sıra Mercure ve Vulcain modülleri [Caddy tarafından desteklenen formatlar](https://caddyserver.com/docs/getting-started#your-first-config) kullanılarak yapılandırılabilir. - -Docker imajlarında] (docker.md), `Caddyfile` `/etc/caddy/Caddyfile` adresinde bulunur. -Statik ikili, başlatıldığı dizinde `Caddyfile` dosyasını arayacaktır. - -PHP'nin kendisi [bir `php.ini` dosyası kullanılarak yapılandırılabilir](https://www.php.net/manual/tr/configuration.file.php). - -Varsayılan olarak, Docker imajlarıyla birlikte verilen PHP ve statik ikili dosyada bulunan PHP, FrankenPHP'nin başlatıldığı dizinde ve `/usr/local/etc/php/` içinde bir `php.ini` dosyası arayacaktır. Ayrıca `.ini` ile biten tüm dosyaları `/usr/local/etc/php/conf.d/` dizininden yükleyecektir. - -Öntanımlı olarak `php.ini` dosyası yoktur, PHP projesi tarafından sağlanan resmi bir şablonu kopyalamanız gerekir. -Docker'da şablonlar imajlar içinde sağlanır: - -```dockerfile -FROM dunglas/frankenphp - -# Developement: -RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini - -# Veya production: -RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini -``` - -Docker kullanmıyorsanız, [PHP kaynak kodu](https://github.com/php/php-src/) ile birlikte verilen `php.ini-production` veya `php.ini-development` dosyalarından birini kopyalayın. - -## Caddyfile Konfigürasyonu - -FrankenPHP yürütücüsünü kaydetmek için `frankenphp` [global seçenek](https://caddyserver.com/docs/caddyfile/concepts#global-options) ayarlanmalıdır, ardından PHP uygulamanızı sunmak için site blokları içinde `php_server` veya `php` [HTTP yönergeleri](https://caddyserver.com/docs/caddyfile/concepts#directives) kullanılabilir. - -Minimal örnek: - -```caddyfile -{ - # FrankenPHP'yi aktif et - frankenphp -} - -localhost { - # Sıkıştırmayı etkinleştir (isteğe bağlı) - encode zstd br gzip - # Geçerli dizindeki PHP dosyalarını çalıştırın ve varlıkları sunun - php_server -} -``` - -İsteğe bağlı olarak, oluşturulacak iş parçacığı sayısı ve sunucuyla birlikte başlatılacak [işçi betikleri] (worker.md) global seçenek altında belirtilebilir. - -```caddyfile -{ - frankenphp { - num_threads # Başlatılacak PHP iş parçacığı sayısını ayarlar. Varsayılan: Mevcut CPU çekirdek sayısının 2 katı. - worker { - file # Çalışan komut dosyasının yolunu ayarlar. - num # Başlatılacak PHP iş parçacığı sayısını ayarlar, varsayılan değer mevcut CPU çekirdek sayısının 2 katıdır. - env # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir. - } - } -} - -# ... -``` - -Alternatif olarak, `worker` seçeneğinin tek satırlık kısa formunu kullanabilirsiniz: - -```caddyfile -{ - frankenphp { - worker - } -} - -# ... -``` - -Aynı sunucuda birden fazla uygulamaya hizmet veriyorsanız birden fazla işçi de tanımlayabilirsiniz: - -```caddyfile -{ - frankenphp { - worker /path/to/app/public/index.php - worker /path/to/other/public/index.php - } -} - -app.example.com { - root * /path/to/app/public - php_server -} - -other.example.com { - root * /path/to/other/public - php_server -} - -# ... -``` - -Genellikle ihtiyacınız olan şey `php_server` yönergesini kullanmaktır, -ancak tam kontrole ihtiyacınız varsa, daha düşük seviyeli `php` yönergesini kullanabilirsiniz: - -php_server` yönergesini kullanmak bu yapılandırmay ile aynıdır: - -```caddyfile -route { - # Dizin istekleri için sondaki eğik çizgiyi, diğer adıyla taksim işaretini ekleyin - @canonicalPath { - file {path}/index.php - not path */ - } - redir @canonicalPath {path}/ 308 - # İstenen dosya mevcut değilse, dizin dosyalarını deneyin - @indexFiles file { - try_files {path} {path}/index.php index.php - split_path .php - } - rewrite @indexFiles {http.matchers.file.relative} - # FrankenPHP! - @phpFiles path *.php - php @phpFiles - file_server -} -``` - -php_server` ve `php` yönergeleri aşağıdaki seçeneklere sahiptir: - -```caddyfile -php_server [] { - root # Sitenin kök klasörünü ayarlar. Öntanımlı: `root` yönergesi. - split_path # URI'yi iki parçaya bölmek için alt dizgeleri ayarlar. İlk eşleşen alt dizge "yol bilgisini" yoldan ayırmak için kullanılır. İlk parça eşleşen alt dizeyle sonlandırılır ve gerçek kaynak (CGI betiği) adı olarak kabul edilir. İkinci parça betiğin kullanması için PATH_INFO olarak ayarlanacaktır. Varsayılan: `.php` - resolve_root_symlink false # Varsa, sembolik bir bağlantıyı değerlendirerek `root` dizininin gerçek değerine çözümlenmesini devre dışı bırakır (varsayılan olarak etkindir). - env # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir. -} -``` - -## Ortam Değişkenleri - -Aşağıdaki ortam değişkenleri `Caddyfile` içinde değişiklik yapmadan Caddy yönergelerini entegre etmek için kullanılabilir: - -* `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır -* `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options) -* `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin - -FPM ve CLI SAPI'lerinde olduğu gibi, ortam değişkenleri varsayılan olarak `$_SERVER` süper globalinde gösterilir. - -[`variables_order`'a ait PHP yönergesinin](https://www.php.net/manual/en/ini.core.php#ini.variables-order) `S` değeri bu yönergede `E`'nin başka bir yere yerleştirilmesinden bağımsız olarak her zaman `ES` ile eş değerdir. - -## PHP konfigürasyonu - -Ek olarak [PHP yapılandırma dosyalarını](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) yüklemek için -`PHP_INI_SCAN_DIR` ortam değişkeni kullanılabilir. -Ayarlandığında, PHP verilen dizinlerde bulunan `.ini` uzantılı tüm dosyaları yükleyecektir. - -## Hata Ayıklama Modunu Etkinleştirin - -Docker imajını kullanırken, hata ayıklama modunu etkinleştirmek için `CADDY_GLOBAL_OPTIONS` ortam değişkenini `debug` olarak ayarlayın: - -```console -docker run -v $PWD:/app/public \ - -e CADDY_GLOBAL_OPTIONS=debug \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` +# Konfigürasyon + +FrankenPHP, Caddy'nin yanı sıra Mercure ve Vulcain modülleri [Caddy tarafından desteklenen formatlar](https://caddyserver.com/docs/getting-started#your-first-config) kullanılarak yapılandırılabilir. + +Docker imajlarında] (docker.md), `Caddyfile` `/etc/caddy/Caddyfile` adresinde bulunur. +Statik ikili, başlatıldığı dizinde `Caddyfile` dosyasını arayacaktır. + +PHP'nin kendisi [bir `php.ini` dosyası kullanılarak yapılandırılabilir](https://www.php.net/manual/tr/configuration.file.php). + +Varsayılan olarak, Docker imajlarıyla birlikte verilen PHP ve statik ikili dosyada bulunan PHP, FrankenPHP'nin başlatıldığı dizinde ve `/usr/local/etc/php/` içinde bir `php.ini` dosyası arayacaktır. Ayrıca `.ini` ile biten tüm dosyaları `/usr/local/etc/php/conf.d/` dizininden yükleyecektir. + +Öntanımlı olarak `php.ini` dosyası yoktur, PHP projesi tarafından sağlanan resmi bir şablonu kopyalamanız gerekir. +Docker'da şablonlar imajlar içinde sağlanır: + +```dockerfile +FROM dunglas/frankenphp + +# Developement: +RUN cp $PHP_INI_DIR/php.ini-development $PHP_INI_DIR/php.ini + +# Veya production: +RUN cp $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini +``` + +Docker kullanmıyorsanız, [PHP kaynak kodu](https://github.com/php/php-src/) ile birlikte verilen `php.ini-production` veya `php.ini-development` dosyalarından birini kopyalayın. + +## Caddyfile Konfigürasyonu + +FrankenPHP yürütücüsünü kaydetmek için `frankenphp` [global seçenek](https://caddyserver.com/docs/caddyfile/concepts#global-options) ayarlanmalıdır, ardından PHP uygulamanızı sunmak için site blokları içinde `php_server` veya `php` [HTTP yönergeleri](https://caddyserver.com/docs/caddyfile/concepts#directives) kullanılabilir. + +Minimal örnek: + +```caddyfile +{ + # FrankenPHP'yi aktif et + frankenphp +} + +localhost { + # Sıkıştırmayı etkinleştir (isteğe bağlı) + encode zstd br gzip + # Geçerli dizindeki PHP dosyalarını çalıştırın ve varlıkları sunun + php_server +} +``` + +İsteğe bağlı olarak, oluşturulacak iş parçacığı sayısı ve sunucuyla birlikte başlatılacak [işçi betikleri] (worker.md) global seçenek altında belirtilebilir. + +```caddyfile +{ + frankenphp { + num_threads # Başlatılacak PHP iş parçacığı sayısını ayarlar. Varsayılan: Mevcut CPU çekirdek sayısının 2 katı. + worker { + file # Çalışan komut dosyasının yolunu ayarlar. + num # Başlatılacak PHP iş parçacığı sayısını ayarlar, varsayılan değer mevcut CPU çekirdek sayısının 2 katıdır. + env # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir. + } + } +} + +# ... +``` + +Alternatif olarak, `worker` seçeneğinin tek satırlık kısa formunu kullanabilirsiniz: + +```caddyfile +{ + frankenphp { + worker + } +} + +# ... +``` + +Aynı sunucuda birden fazla uygulamaya hizmet veriyorsanız birden fazla işçi de tanımlayabilirsiniz: + +```caddyfile +{ + frankenphp { + worker /path/to/app/public/index.php + worker /path/to/other/public/index.php + } +} + +app.example.com { + root /path/to/app/public + php_server +} + +other.example.com { + root /path/to/other/public + php_server +} + +# ... +``` + +Genellikle ihtiyacınız olan şey `php_server` yönergesini kullanmaktır, +ancak tam kontrole ihtiyacınız varsa, daha düşük seviyeli `php` yönergesini kullanabilirsiniz: + +php_server` yönergesini kullanmak bu yapılandırmay ile aynıdır: + +```caddyfile +route { + # Dizin istekleri için sondaki eğik çizgiyi, diğer adıyla taksim işaretini ekleyin + @canonicalPath { + file {path}/index.php + not path */ + } + redir @canonicalPath {path}/ 308 + # İstenen dosya mevcut değilse, dizin dosyalarını deneyin + @indexFiles file { + try_files {path} {path}/index.php index.php + split_path .php + } + rewrite @indexFiles {http.matchers.file.relative} + # FrankenPHP! + @phpFiles path *.php + php @phpFiles + file_server +} +``` + +php_server` ve `php` yönergeleri aşağıdaki seçeneklere sahiptir: + +```caddyfile +php_server [] { + root # Sitenin kök klasörünü ayarlar. Öntanımlı: `root` yönergesi. + split_path # URI'yi iki parçaya bölmek için alt dizgeleri ayarlar. İlk eşleşen alt dizge "yol bilgisini" yoldan ayırmak için kullanılır. İlk parça eşleşen alt dizeyle sonlandırılır ve gerçek kaynak (CGI betiği) adı olarak kabul edilir. İkinci parça betiğin kullanması için PATH_INFO olarak ayarlanacaktır. Varsayılan: `.php` + resolve_root_symlink false # Varsa, sembolik bir bağlantıyı değerlendirerek `root` dizininin gerçek değerine çözümlenmesini devre dışı bırakır (varsayılan olarak etkindir). + env # Ek bir ortam değişkenini verilen değere ayarlar. Birden fazla ortam değişkeni için birden fazla kez belirtilebilir. +} +``` + +## Ortam Değişkenleri + +Aşağıdaki ortam değişkenleri `Caddyfile` içinde değişiklik yapmadan Caddy yönergelerini entegre etmek için kullanılabilir: + +* `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır +* `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options) +* `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin + +FPM ve CLI SAPI'lerinde olduğu gibi, ortam değişkenleri varsayılan olarak `$_SERVER` süper globalinde gösterilir. + +[`variables_order`'a ait PHP yönergesinin](https://www.php.net/manual/en/ini.core.php#ini.variables-order) `S` değeri bu yönergede `E`'nin başka bir yere yerleştirilmesinden bağımsız olarak her zaman `ES` ile eş değerdir. + +## PHP konfigürasyonu + +Ek olarak [PHP yapılandırma dosyalarını](https://www.php.net/manual/en/configuration.file.php#configuration.file.scan) yüklemek için +`PHP_INI_SCAN_DIR` ortam değişkeni kullanılabilir. +Ayarlandığında, PHP verilen dizinlerde bulunan `.ini` uzantılı tüm dosyaları yükleyecektir. + +## Hata Ayıklama Modunu Etkinleştirin + +Docker imajını kullanırken, hata ayıklama modunu etkinleştirmek için `CADDY_GLOBAL_OPTIONS` ortam değişkenini `debug` olarak ayarlayın: + +```console +docker run -v $PWD:/app/public \ + -e CADDY_GLOBAL_OPTIONS=debug \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` diff --git a/docs/tr/laravel.md b/docs/tr/laravel.md index c2f822b77a..d1b7eee604 100644 --- a/docs/tr/laravel.md +++ b/docs/tr/laravel.md @@ -1,74 +1,74 @@ -# Laravel - -## Docker - -Bir [Laravel](https://laravel.com) web uygulamasını FrankenPHP ile çalıştırmak, projeyi resmi Docker imajının `/app` dizinine monte etmek kadar kolaydır. - -Bu komutu Laravel uygulamanızın ana dizininden çalıştırın: - -```console -docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp -``` - -And tadını çıkarın! - -## Yerel Kurulum - -Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çalıştırabilirsiniz: - -1. [Sisteminize karşılık gelen binary dosyayı indirin](https://github.com/dunglas/frankenphp/releases) -2. Aşağıdaki yapılandırmayı Laravel projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin: - - ```caddyfile - { - frankenphp - } - - # Sunucunuzun alan adı - localhost { - # Webroot'u public/ dizinine ayarlayın - root * public/ - # Sıkıştırmayı etkinleştir (isteğe bağlı) - encode zstd br gzip - # PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun - php_server - } - ``` - -3. FrankenPHP'yi Laravel projenizin kök dizininden başlatın: `frankenphp run` - -## Laravel Octane - -Octane, Composer paket yöneticisi aracılığıyla kurulabilir: - -```console -composer require laravel/octane -``` - -Octane'ı kurduktan sonra, Octane'ın yapılandırma dosyasını uygulamanıza yükleyecek olan `octane:install` Artisan komutunu çalıştırabilirsiniz: - -```console -php artisan octane:install --server=frankenphp -``` - -Octane sunucusu `octane:frankenphp` Artisan komutu aracılığıyla başlatılabilir. - -```console -php artisan octane:frankenphp -``` - -`octane:frankenphp` komutu aşağıdaki seçenekleri alabilir: - -* `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`) -* `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`) -* `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`) -* `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`) -* `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`) -* `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu -* `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin -* `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir) -* `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle -* `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın -* `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları - -Laravel Octane hakkında daha fazla bilgi edinmek için [Laravel Octane resmi belgelerine](https://laravel.com/docs/octane) göz atın. +# Laravel + +## Docker + +Bir [Laravel](https://laravel.com) web uygulamasını FrankenPHP ile çalıştırmak, projeyi resmi Docker imajının `/app` dizinine monte etmek kadar kolaydır. + +Bu komutu Laravel uygulamanızın ana dizininden çalıştırın: + +```console +docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp +``` + +And tadını çıkarın! + +## Yerel Kurulum + +Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çalıştırabilirsiniz: + +1. [Sisteminize karşılık gelen binary dosyayı indirin](https://github.com/dunglas/frankenphp/releases) +2. Aşağıdaki yapılandırmayı Laravel projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin: + + ```caddyfile + { + frankenphp + } + + # Sunucunuzun alan adı + localhost { + # Webroot'u public/ dizinine ayarlayın + root public/ + # Sıkıştırmayı etkinleştir (isteğe bağlı) + encode zstd br gzip + # PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun + php_server + } + ``` + +3. FrankenPHP'yi Laravel projenizin kök dizininden başlatın: `frankenphp run` + +## Laravel Octane + +Octane, Composer paket yöneticisi aracılığıyla kurulabilir: + +```console +composer require laravel/octane +``` + +Octane'ı kurduktan sonra, Octane'ın yapılandırma dosyasını uygulamanıza yükleyecek olan `octane:install` Artisan komutunu çalıştırabilirsiniz: + +```console +php artisan octane:install --server=frankenphp +``` + +Octane sunucusu `octane:frankenphp` Artisan komutu aracılığıyla başlatılabilir. + +```console +php artisan octane:frankenphp +``` + +`octane:frankenphp` komutu aşağıdaki seçenekleri alabilir: + +* `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`) +* `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`) +* `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`) +* `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`) +* `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`) +* `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu +* `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin +* `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir) +* `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle +* `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın +* `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları + +Laravel Octane hakkında daha fazla bilgi edinmek için [Laravel Octane resmi belgelerine](https://laravel.com/docs/octane) göz atın. diff --git a/testdata/Caddyfile b/testdata/Caddyfile index 03f772dece..914a097b4e 100644 --- a/testdata/Caddyfile +++ b/testdata/Caddyfile @@ -8,7 +8,7 @@ http:// { log route { - root * . + root . # Add trailing slash for directory requests @canonicalPath { file {path}/index.php diff --git a/testdata/benchmark.Caddyfile b/testdata/benchmark.Caddyfile index 65a2000690..c1067cc156 100644 --- a/testdata/benchmark.Caddyfile +++ b/testdata/benchmark.Caddyfile @@ -4,7 +4,7 @@ http:// { route { - root * . + root . encode zstd br gzip From fb4e26273b9c2546a7f368ef256486345434000b Mon Sep 17 00:00:00 2001 From: Romain Bastide Date: Tue, 22 Apr 2025 11:46:22 +0200 Subject: [PATCH 31/51] docs: update README with additional documentation links Add link to classic mode, efficiently serving large static files and monitoring FrankenPHP Signed-off-by: Romain Bastide --- docs/fr/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/fr/README.md b/docs/fr/README.md index 27bddc9fa5..0cc3853ac3 100644 --- a/docs/fr/README.md +++ b/docs/fr/README.md @@ -83,9 +83,11 @@ frankenphp php-server ## Documentation +* [Le mode classique](classic.md) * [Le mode worker](worker.md) * [Le support des Early Hints (code de statut HTTP 103)](early-hints.md) * [Temps réel](mercure.md) +* [Servir efficacement les fichiers statiques volumineux](x-sendfile.md) * [Configuration](config.md) * [Images Docker](docker.md) * [Déploiement en production](production.md) @@ -93,6 +95,7 @@ frankenphp php-server * [Créer des applications PHP **standalone**, auto-exécutables](embed.md) * [Créer un build statique](static.md) * [Compiler depuis les sources](compile.md) +* [Surveillance de FrankenPHP](metrics.md) * [Intégration Laravel](laravel.md) * [Problèmes connus](known-issues.md) * [Application de démo (Symfony) et benchmarks](https://github.com/dunglas/frankenphp-demo) From 9ff4ee2cd83ba04a9c8f58121983538fe5a7954e Mon Sep 17 00:00:00 2001 From: Indra Gunawan Date: Tue, 22 Apr 2025 19:14:13 +0800 Subject: [PATCH 32/51] ci: combine dependabot updates for one group to 1 pull-request --- .github/dependabot.yaml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index c30d0c6443..72584f8e03 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -7,6 +7,10 @@ updates: interval: weekly commit-message: prefix: chore + groups: + go-modules: + patterns: + - '*' - package-ecosystem: gomod directory: /caddy schedule: @@ -18,9 +22,17 @@ updates: ignore: - dependency-name: github.com/google/cel-go - dependency-name: github.com/quic-go/* + groups: + go-modules: + patterns: + - '*' - package-ecosystem: github-actions directory: / schedule: interval: weekly commit-message: prefix: ci + groups: + github-actions: + patterns: + - '*' From e6485326ba81f4eb00559c1d2e325f675dc7f863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 22 Apr 2025 11:43:17 +0200 Subject: [PATCH 33/51] feat: compatibility with libphp.dylib on macOS --- frankenphp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frankenphp.go b/frankenphp.go index e0c5de1b0b..fe2815cb34 100644 --- a/frankenphp.go +++ b/frankenphp.go @@ -18,7 +18,7 @@ package frankenphp // #cgo CFLAGS: -Wall -Werror // #cgo CFLAGS: -I/usr/local/include -I/usr/local/include/php -I/usr/local/include/php/main -I/usr/local/include/php/TSRM -I/usr/local/include/php/Zend -I/usr/local/include/php/ext -I/usr/local/include/php/ext/date/lib // #cgo linux CFLAGS: -D_GNU_SOURCE -// #cgo darwin LDFLAGS: -L/opt/homebrew/opt/libiconv/lib -liconv +// #cgo darwin LDFLAGS: -Wl,-rpath,/usr/local/lib -L/opt/homebrew/opt/libiconv/lib -liconv // #cgo linux LDFLAGS: -lresolv // #cgo LDFLAGS: -L/usr/local/lib -L/usr/lib -lphp -ldl -lm -lutil // #include From af743912c0cf20747af4b652c2e44722a4b0842e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 22 Apr 2025 12:05:16 +0200 Subject: [PATCH 34/51] feat: upgrade to Caddy 2.10 --- caddy/go.mod | 22 +++++++++++----------- caddy/go.sum | 44 ++++++++++++++++++++++---------------------- go.mod | 14 +++++++------- go.sum | 30 ++++++++++++++---------------- 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/caddy/go.mod b/caddy/go.mod index 4718d2117d..f1bd59acac 100644 --- a/caddy/go.mod +++ b/caddy/go.mod @@ -15,7 +15,7 @@ require ( github.com/dunglas/frankenphp v1.5.0 github.com/dunglas/mercure/caddy v0.18.4 github.com/dunglas/vulcain/caddy v1.1.1 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 @@ -100,7 +100,7 @@ require ( github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kevburnsjr/skipfilter v0.0.1 // indirect - github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/libdns/libdns v0.2.3 // indirect @@ -126,9 +126,9 @@ require ( github.com/pires/go-proxyproto v0.8.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.63.0 // indirect - github.com/prometheus/procfs v0.16.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/quic-go/quic-go v0.49.0 // indirect github.com/rs/xid v1.6.0 // indirect @@ -185,22 +185,22 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.37.0 // indirect golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4 // indirect golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.37.0 // indirect + golang.org/x/net v0.39.0 // indirect golang.org/x/oauth2 v0.26.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/term v0.31.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.10.0 // indirect golang.org/x/tools v0.31.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect google.golang.org/grpc v1.70.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/caddy/go.sum b/caddy/go.sum index 2ed7151505..5e9e19d15b 100644 --- a/caddy/go.sum +++ b/caddy/go.sum @@ -308,8 +308,8 @@ github.com/kevburnsjr/skipfilter v0.0.1 h1:EWl1lWUJfIehrKYIEkps0Cl67lCfS2pUM9iZF github.com/kevburnsjr/skipfilter v0.0.1/go.mod h1:jfaRyFOYVUtIa6IIC+0mB1qiZqhHw+DKvFowCBuijSk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -391,17 +391,17 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= -github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= @@ -612,8 +612,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= +golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4 h1:QDiVWrFJ2lyXzr3pJnIREQWR8S7jkjzuWJPJda8Ic8E= golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -645,8 +645,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -666,8 +666,8 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -691,8 +691,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -703,8 +703,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= +golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -716,8 +716,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= @@ -761,8 +761,8 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/go.mod b/go.mod index 2396a77df6..9a652bd04d 100644 --- a/go.mod +++ b/go.mod @@ -8,10 +8,10 @@ retract v1.0.0-rc.1 // Human error require ( github.com/maypok86/otter v1.2.4 - github.com/prometheus/client_golang v1.21.1 + github.com/prometheus/client_golang v1.22.0 github.com/stretchr/testify v1.10.0 go.uber.org/zap v1.27.0 - golang.org/x/net v0.37.0 + golang.org/x/net v0.39.0 ) require ( @@ -23,13 +23,13 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.63.0 // indirect - github.com/prometheus/procfs v0.16.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect - google.golang.org/protobuf v1.36.5 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index b1a18e2c2e..7921078d13 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,6 @@ github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34 github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= -github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -24,14 +22,14 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= -github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= -github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM= -github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= @@ -42,14 +40,14 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= -google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= From 34f3b25aebce7712a045e7f5047dee4213d17f64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 22 Apr 2025 17:14:42 +0200 Subject: [PATCH 35/51] feat: upgrade to Caddy 2.10 --- caddy/go.mod | 152 +++++++++---------- caddy/go.sum | 405 +++++++++++++++++++++++++-------------------------- 2 files changed, 279 insertions(+), 278 deletions(-) diff --git a/caddy/go.mod b/caddy/go.mod index f1bd59acac..6fd42731d6 100644 --- a/caddy/go.mod +++ b/caddy/go.mod @@ -1,20 +1,20 @@ module github.com/dunglas/frankenphp/caddy -go 1.23.0 +go 1.24 -toolchain go1.24.0 +toolchain go1.24.2 replace github.com/dunglas/frankenphp => ../ retract v1.0.0-rc.1 // Human error require ( - github.com/caddyserver/caddy/v2 v2.9.1 - github.com/caddyserver/certmagic v0.22.0 + github.com/caddyserver/caddy/v2 v2.10.0 + github.com/caddyserver/certmagic v0.23.0 github.com/dunglas/caddy-cbrotli v1.0.0 github.com/dunglas/frankenphp v1.5.0 github.com/dunglas/mercure/caddy v0.18.4 - github.com/dunglas/vulcain/caddy v1.1.1 + github.com/dunglas/vulcain/caddy v1.2.0 github.com/prometheus/client_golang v1.22.0 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 @@ -24,30 +24,33 @@ require ( require github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 // indirect require ( - cel.dev/expr v0.20.0 // indirect + cel.dev/expr v0.23.1 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/BurntSushi/toml v1.4.0 // indirect + github.com/BurntSushi/toml v1.5.0 // indirect + github.com/KimMachineGun/automemlimit v0.7.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Masterminds/sprig/v3 v3.3.0 // indirect github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 // indirect - github.com/MicahParks/jwkset v0.8.0 // indirect - github.com/MicahParks/keyfunc/v3 v3.3.10 // indirect + github.com/MicahParks/jwkset v0.9.5 // indirect + github.com/MicahParks/keyfunc/v3 v3.3.11 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/RoaringBitmap/roaring v1.9.4 // indirect - github.com/alecthomas/chroma/v2 v2.15.0 // indirect + github.com/alecthomas/chroma/v2 v2.17.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/bits-and-blooms/bitset v1.22.0 // indirect github.com/caddyserver/zerossl v0.1.3 // indirect + github.com/ccoveille/go-safecast v1.6.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect - github.com/coreos/go-oidc/v3 v3.12.0 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/coreos/go-oidc/v3 v3.14.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgraph-io/badger v1.6.2 // indirect @@ -56,72 +59,72 @@ require ( github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect github.com/dlclark/regexp2 v1.11.5 // indirect github.com/dolthub/maphash v0.1.0 // indirect - github.com/dunglas/httpsfv v1.0.2 // indirect + github.com/dunglas/httpsfv v1.1.0 // indirect github.com/dunglas/mercure v0.18.4 // indirect - github.com/dunglas/vulcain v1.1.1 // indirect + github.com/dunglas/vulcain v1.2.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/francoispqt/gojay v1.2.13 // indirect - github.com/fsnotify/fsnotify v1.8.0 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect + github.com/fxamacker/cbor/v2 v2.8.0 // indirect github.com/gammazero/deque v1.0.0 // indirect - github.com/getkin/kin-openapi v0.128.0 // indirect - github.com/go-chi/chi/v5 v5.2.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect - github.com/go-jose/go-jose/v4 v4.0.4 // indirect + github.com/getkin/kin-openapi v0.131.0 // indirect + github.com/go-chi/chi/v5 v5.2.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.1.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-sql-driver/mysql v1.9.0 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/swag v0.23.1 // indirect + github.com/go-sql-driver/mysql v1.9.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect - github.com/golang-jwt/jwt/v5 v5.2.1 // indirect + github.com/golang-jwt/jwt/v5 v5.2.2 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6 // indirect - github.com/google/cel-go v0.23.2 // indirect - github.com/google/certificate-transparency-go v1.3.0 // indirect + github.com/golang/snappy v1.0.0 // indirect + github.com/google/brotli/go/cbrotli v0.0.0-20250131134309-440e03642b89 // indirect + github.com/google/cel-go v0.24.1 // indirect + github.com/google/certificate-transparency-go v1.3.1 // indirect github.com/google/go-tpm v0.9.3 // indirect github.com/google/go-tspi v0.3.0 // indirect - github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect + github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect github.com/huandu/xstrings v1.5.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/invopop/yaml v0.3.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.2 // indirect + github.com/jackc/pgx/v5 v5.7.4 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kevburnsjr/skipfilter v0.0.1 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kylelemons/godebug v1.1.0 // indirect - github.com/libdns/libdns v0.2.3 // indirect - github.com/magiconair/properties v1.8.9 // indirect + github.com/libdns/libdns v1.0.0-beta.1 // indirect github.com/mailru/easyjson v0.9.0 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/maypok86/otter v1.2.4 // indirect github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect - github.com/mholt/acmez/v3 v3.1.0 // indirect - github.com/miekg/dns v1.1.63 // indirect + github.com/mholt/acmez/v3 v3.1.2 // indirect + github.com/miekg/dns v1.1.65 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-ps v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mschoch/smat v0.2.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect + github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect + github.com/onsi/ginkgo/v2 v2.23.4 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pires/go-proxyproto v0.8.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -130,26 +133,26 @@ require ( github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/quic-go/qpack v0.5.1 // indirect - github.com/quic-go/quic-go v0.49.0 // indirect + github.com/quic-go/quic-go v0.51.0 // indirect github.com/rs/xid v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.7.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sagikazarmark/locafero v0.9.0 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/slackhq/nebula v1.9.4 // indirect - github.com/smallstep/certificates v0.28.1 // indirect - github.com/smallstep/cli-utils v0.10.0 // indirect + github.com/slackhq/nebula v1.9.5 // indirect + github.com/smallstep/certificates v0.28.3 // indirect + github.com/smallstep/cli-utils v0.12.1 // indirect + github.com/smallstep/linkedca v0.23.0 // indirect github.com/smallstep/nosql v0.7.0 // indirect github.com/smallstep/pkcs7 v0.2.1 // indirect - github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc // indirect + github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492 // indirect github.com/smallstep/truststore v0.13.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/afero v1.14.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect - github.com/spf13/viper v1.19.0 // indirect + github.com/spf13/viper v1.20.1 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 // indirect @@ -161,47 +164,46 @@ require ( github.com/urfave/cli v1.22.16 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect - github.com/yuin/goldmark v1.7.8 // indirect + github.com/yuin/goldmark v1.7.10 // indirect github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc // indirect github.com/zeebo/blake3 v0.2.4 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect - go.opentelemetry.io/contrib/propagators/autoprop v0.58.0 // indirect - go.opentelemetry.io/contrib/propagators/aws v1.33.0 // indirect - go.opentelemetry.io/contrib/propagators/b3 v1.33.0 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.33.0 // indirect - go.opentelemetry.io/contrib/propagators/ot v1.33.0 // indirect - go.opentelemetry.io/otel v1.33.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 // indirect - go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.33.0 // indirect - go.opentelemetry.io/otel/trace v1.33.0 // indirect - go.opentelemetry.io/proto/otlp v1.4.0 // indirect - go.step.sm/crypto v0.57.1 // indirect - go.step.sm/linkedca v0.22.2 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect + go.opentelemetry.io/contrib/propagators/autoprop v0.60.0 // indirect + go.opentelemetry.io/contrib/propagators/aws v1.35.0 // indirect + go.opentelemetry.io/contrib/propagators/b3 v1.35.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.35.0 // indirect + go.opentelemetry.io/contrib/propagators/ot v1.35.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/sdk v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.step.sm/crypto v0.61.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect - go.uber.org/mock v0.5.0 // indirect + go.uber.org/mock v0.5.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect golang.org/x/crypto v0.37.0 // indirect - golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4 // indirect - golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect + golang.org/x/crypto/x509roots/fallback v0.0.0-20250418111936-9c1aa6af88df // indirect + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/mod v0.24.0 // indirect golang.org/x/net v0.39.0 // indirect - golang.org/x/oauth2 v0.26.0 // indirect + golang.org/x/oauth2 v0.29.0 // indirect golang.org/x/sync v0.13.0 // indirect golang.org/x/sys v0.32.0 // indirect golang.org/x/term v0.31.0 // indirect golang.org/x/text v0.24.0 // indirect - golang.org/x/time v0.10.0 // indirect - golang.org/x/tools v0.31.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect - google.golang.org/grpc v1.70.0 // indirect + golang.org/x/time v0.11.0 // indirect + golang.org/x/tools v0.32.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250421163800-61c742ae3ef0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0 // indirect + google.golang.org/grpc v1.72.0 // indirect + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect google.golang.org/protobuf v1.36.6 // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.1 // indirect diff --git a/caddy/go.sum b/caddy/go.sum index 5e9e19d15b..bf8fc9c426 100644 --- a/caddy/go.sum +++ b/caddy/go.sum @@ -1,24 +1,23 @@ -cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI= -cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw= +cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg= +cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.14.0 h1:A5C4dKV/Spdvxcl0ggWwWEzzP7AZMJSEIgrkngwhGYM= -cloud.google.com/go/auth v0.14.0/go.mod h1:CYsoRL1PdiDuqeQpZE0bP2pnPrGqFcOkI0nldEQis+A= -cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M= -cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go v0.118.3 h1:jsypSnrE/w4mJysioGdMBg4MiW/hHx/sArFpaBWHdME= +cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc= +cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU= +cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= -cloud.google.com/go/iam v1.2.2 h1:ozUSofHUGf/F4tCNy/mu9tHLTaxZFLOUiKzjcgWHGIA= -cloud.google.com/go/iam v1.2.2/go.mod h1:0Ys8ccaZHdI1dEUilwzqng/6ps2YB6vRsjIe00/+6JY= -cloud.google.com/go/kms v1.20.5 h1:aQQ8esAIVZ1atdJRxihhdxGQ64/zEbJoJnCz/ydSmKg= -cloud.google.com/go/kms v1.20.5/go.mod h1:C5A8M1sv2YWYy1AE6iSrnddSG9lRGdJq5XEdBy28Lmw= -cloud.google.com/go/longrunning v0.6.2 h1:xjDfh1pQcWPEvnfjZmwjKQEcHnpz6lHjfy7Fo0MK+hc= -cloud.google.com/go/longrunning v0.6.2/go.mod h1:k/vIs83RN4bE3YCswdXC5PFfWVILjm3hpEUlSko4PiI= +cloud.google.com/go/iam v1.4.1 h1:cFC25Nv+u5BkTR/BT1tXdoF2daiVbZ1RLx2eqfQ9RMM= +cloud.google.com/go/iam v1.4.1/go.mod h1:2vUEJpUG3Q9p2UdsyksaKpDzlwOrnMzS30isdReIcLM= +cloud.google.com/go/kms v1.21.1 h1:r1Auo+jlfJSf8B7mUnVw5K0fI7jWyoUy65bV53VjKyk= +cloud.google.com/go/kms v1.21.1/go.mod h1:s0wCyByc9LjTdCjG88toVs70U9W+cc6RKFc8zAqX7nE= +cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw= +cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= @@ -31,8 +30,11 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= +github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/KimMachineGun/automemlimit v0.7.1 h1:QcG/0iCOLChjfUweIMC3YL5Xy9C3VBeNmCZHrZfJMBw= +github.com/KimMachineGun/automemlimit v0.7.1/go.mod h1:QZxpHaGOQoYvFhv/r4u3U0JTC2ZcOwbSr11UZF46UBM= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= @@ -42,10 +44,10 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC github.com/MauriceGit/skiplist v0.0.0-20191117202105-643e379adb62/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg= github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145 h1:1yw6O62BReQ+uA1oyk9XaQTvLhcoHWmoQAgXmDFXpIY= github.com/MauriceGit/skiplist v0.0.0-20211105230623-77f5c8d3e145/go.mod h1:877WBceefKn14QwVVn4xRFUsHsZb9clICgdeTj4XsUg= -github.com/MicahParks/jwkset v0.8.0 h1:jHtclI38Gibmu17XMI6+6/UB59srp58pQVxePHRK5o8= -github.com/MicahParks/jwkset v0.8.0/go.mod h1:fVrj6TmG1aKlJEeceAz7JsXGTXEn72zP1px3us53JrA= -github.com/MicahParks/keyfunc/v3 v3.3.10 h1:JtEGE8OcNeI297AMrR4gVXivV8fyAawFUMkbwNreJRk= -github.com/MicahParks/keyfunc/v3 v3.3.10/go.mod h1:1TEt+Q3FO7Yz2zWeYO//fMxZMOiar808NqjWQQpBPtU= +github.com/MicahParks/jwkset v0.9.5 h1:/baA2n7RhO7nRIe1rx4ZX1Opeq+mwDuuWi2myDZwqnA= +github.com/MicahParks/jwkset v0.9.5/go.mod h1:U2oRhRaLgDCLjtpGL2GseNKGmZtLs/3O7p+OZaL5vo0= +github.com/MicahParks/keyfunc/v3 v3.3.11 h1:eA6wNltwdSRX2gtpTwZseBCC9nGeBkI9KxHtTyZbDbo= +github.com/MicahParks/keyfunc/v3 v3.3.11/go.mod h1:y6Ed3dMgNKTcpxbaQHD8mmrYDUZWJAxteddA6OQj+ag= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -57,8 +59,8 @@ github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhve github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= -github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= +github.com/alecthomas/chroma/v2 v2.17.0 h1:3r2Cgk+nXNICMBxIFGnTRTbQFUwMiLisW+9uos0TtUI= +github.com/alecthomas/chroma/v2 v2.17.0/go.mod h1:RVX6AvYm4VfYe/zsk7mjHueLDZor3aWCNE14TFlepBk= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= @@ -68,32 +70,32 @@ github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmO github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b h1:uUXgbcPDK3KpW29o4iy7GtuappbWT0l5NaMo9H9pJDw= github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= -github.com/aws/aws-sdk-go-v2 v1.34.0 h1:9iyL+cjifckRGEVpRKZP3eIxVlL06Qk1Tk13vreaVQU= -github.com/aws/aws-sdk-go-v2 v1.34.0/go.mod h1:JgstGg0JjWU1KpVJjD5H0y0yyAIpSdKEq556EI6yOOM= -github.com/aws/aws-sdk-go-v2/config v1.29.2 h1:JuIxOEPcSKpMB0J+khMjznG9LIhIBdmqNiEcPclnwqc= -github.com/aws/aws-sdk-go-v2/config v1.29.2/go.mod h1:HktTHregOZwNSM/e7WTfVSu9RCX+3eOv+6ij27PtaYs= -github.com/aws/aws-sdk-go-v2/credentials v1.17.55 h1:CDhKnDEaGkLA5ZszV/qw5uwN5M8rbv9Cl0JRN+PRsaM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.55/go.mod h1:kPD/vj+RB5MREDUky376+zdnjZpR+WgdBBvwrmnlmKE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.25 h1:kU7tmXNaJ07LsyN3BUgGqAmVmQtq0w6duVIHAKfp0/w= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.25/go.mod h1:OiC8+OiqrURb1wrwmr/UbOVLFSWEGxjinj5C299VQdo= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.29 h1:Ej0Rf3GMv50Qh4G4852j2djtoDb7AzQ7MuQeFHa3D70= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.29/go.mod h1:oeNTC7PwJNoM5AznVr23wxhLnuJv0ZDe5v7w0wqIs9M= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.29 h1:6e8a71X+9GfghragVevC5bZqvATtc3mAMgxpSNbgzF0= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.29/go.mod h1:c4jkZiQ+BWpNqq7VtrxjwISrLrt/VvPq3XiopkUIolI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.10 h1:hN4yJBGswmFTOVYqmbz1GBs9ZMtQe8SrYxPwrkrlRv8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.10/go.mod h1:TsxON4fEZXyrKY+D+3d2gSTyJkGORexIYab9PTf56DA= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.14 h1:IvhYu4W4wKMqN6DqtuVD7obkFflgTv1wmnZMjlSeDAA= -github.com/aws/aws-sdk-go-v2/service/kms v1.37.14/go.mod h1:yqUt1GZH4uf7HUNT2Kd7qk6P+Vi5z+C5+NjNSNRO1L4= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.12 h1:kznaW4f81mNMlREkU9w3jUuJvU5g/KsqDV43ab7Rp6s= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.12/go.mod h1:bZy9r8e0/s0P7BSDHgMLXK2KvdyRRBIQ2blKlvLt0IU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.11 h1:mUwIpAvILeKFnRx4h1dEgGEFGuV8KJ3pEScZWVFYuZA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.11/go.mod h1:JDJtD+b8HNVv71axz8+S5492KM8wTzHRFpMKQbPlYxw= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.10 h1:g9d+TOsu3ac7SgmY2dUf1qMgu/uJVTlQ4VCbH6hRxSw= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.10/go.mod h1:WZfNmntu92HO44MVZAubQaz3qCuIdeOdog2sADfU6hU= +github.com/aws/aws-sdk-go-v2 v1.36.3 h1:mJoei2CxPutQVxaATCzDUjcZEjVRdpsiiXi2o38yqWM= +github.com/aws/aws-sdk-go-v2 v1.36.3/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2/config v1.29.14 h1:f+eEi/2cKCg9pqKBoAIwRGzVb70MRKqWX4dg1BDcSJM= +github.com/aws/aws-sdk-go-v2/config v1.29.14/go.mod h1:wVPHWcIFv3WO89w0rE10gzf17ZYy+UVS1Geq8Iei34g= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67 h1:9KxtdcIA/5xPNQyZRgUSpYOE6j9Bc4+D7nZua0KGYOM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.67/go.mod h1:p3C44m+cfnbv763s52gCqrjaqyPikj9Sg47kUVaNZQQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 h1:x793wxmUWVDhshP8WW2mlnXuFrO4cOd3HLBroh1paFw= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30/go.mod h1:Jpne2tDnYiFascUEs2AWHJL9Yp7A5ZVy3TNyxaAjD6M= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 h1:ZK5jHhnrioRkUNOc+hOgQKlUL5JeC3S6JgLxtQ+Rm0Q= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34/go.mod h1:p4VfIceZokChbA9FzMbRGz5OV+lekcVtHlPKEO0gSZY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 h1:SZwFm17ZUNNg5Np0ioo/gq8Mn6u9w19Mri8DnJ15Jf0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34/go.mod h1:dFZsC0BLo346mvKQLWmoJxT+Sjp+qcVR1tRVHQGOH9Q= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 h1:dM9/92u2F1JbDaGooxTq18wmmFzbJRfXfVfy96/1CXM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15/go.mod h1:SwFBy2vjtA0vZbjjaFtfN045boopadnoVPhu4Fv66vY= +github.com/aws/aws-sdk-go-v2/service/kms v1.38.3 h1:RivOtUH3eEu6SWnUMFHKAW4MqDOzWn1vGQ3S38Y5QMg= +github.com/aws/aws-sdk-go-v2/service/kms v1.38.3/go.mod h1:cQn6tAF77Di6m4huxovNM7NVAozWTZLsDRp9t8Z/WYk= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.3 h1:1Gw+9ajCV1jogloEv1RRnvfRFia2cL6c9cuKV2Ps+G8= +github.com/aws/aws-sdk-go-v2/service/sso v1.25.3/go.mod h1:qs4a9T5EMLl/Cajiw2TcbNt2UNo/Hqlyp+GiuG4CFDI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1 h1:hXmVKytPfTy5axZ+fYbR5d0cFmC3JvwLm5kM83luako= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.30.1/go.mod h1:MlYRNmYu/fGPoxBQVvBYr9nyr948aY/WLUvwBMBJubs= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19 h1:1XuUZ8mYJw9B6lzAkXhqHlJd/XvaX32evhproijJEZY= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.19/go.mod h1:cQnB8CUnxbMU82JvlqjKR2HBOm3fe9pWorWBza6MBJ4= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -101,16 +103,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= -github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= -github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCkcs2uw7w4= +github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/caddyserver/caddy/v2 v2.9.1 h1:OEYiZ7DbCzAWVb6TNEkjRcSCRGHVoZsJinoDR/n9oaY= -github.com/caddyserver/caddy/v2 v2.9.1/go.mod h1:ImUELya2el1FDVp3ahnSO2iH1or1aHxlQEQxd/spP68= -github.com/caddyserver/certmagic v0.22.0 h1:hi2skv2jouUw9uQUEyYSTTmqPZPHgf61dOANSIVCLOw= -github.com/caddyserver/certmagic v0.22.0/go.mod h1:Vc0msarAPhOagbDc/SU6M2zbzdwVuZ0lkTh2EqtH4vs= +github.com/caddyserver/caddy/v2 v2.10.0 h1:fonubSaQKF1YANl8TXqGcn4IbIRUDdfAkpcsfI/vX5U= +github.com/caddyserver/caddy/v2 v2.10.0/go.mod h1:q+dgBS3xtIJJGYI2H5Nyh9+4BvhQQ9yCGmECv4Ubdjo= +github.com/caddyserver/certmagic v0.23.0 h1:CfpZ/50jMfG4+1J/u2LV6piJq4HOfO6ppOnOf7DkFEU= +github.com/caddyserver/certmagic v0.23.0/go.mod h1:9mEZIWqqWoI+Gf+4Trh04MOVPD0tGSxtqsxg87hAIH4= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= +github.com/ccoveille/go-safecast v1.6.1 h1:Nb9WMDR8PqhnKCVs2sCB+OqhohwO5qaXtCviZkIff5Q= +github.com/ccoveille/go-safecast v1.6.1/go.mod h1:QqwNjxQ7DAqY0C721OIO9InMk9zCwcsO7tnRuHytad8= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -127,10 +131,12 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo= -github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= +github.com/coreos/go-oidc/v3 v3.14.1 h1:9ePWwfdwC4QKRlCXsJGou56adA/owXczOzwKdOumLqk= +github.com/coreos/go-oidc/v3 v3.14.1/go.mod h1:HaZ3szPaZ0e4r6ebqvsLWlk2Tn+aejfmrfah6hnSYEU= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -160,16 +166,16 @@ github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= github.com/dunglas/caddy-cbrotli v1.0.0 h1:+WNqXBkWyMcIpXB2rVZ3nwcElUbuAzf0kPxNXU4D+u0= github.com/dunglas/caddy-cbrotli v1.0.0/go.mod h1:KZsUu3fnQBgO0o3YDoQuO3Z61dFgUncr1F8rg8acwQw= -github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0= -github.com/dunglas/httpsfv v1.0.2/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg= +github.com/dunglas/httpsfv v1.1.0 h1:Jw76nAyKWKZKFrpMMcL76y35tOpYHqQPzHQiwDvpe54= +github.com/dunglas/httpsfv v1.1.0/go.mod h1:zID2mqw9mFsnt7YC3vYQ9/cjq30q41W+1AnDwH8TiMg= github.com/dunglas/mercure v0.18.4 h1:fhi1t1LIK2EqIDAMHSMH1lpmZTUu5hLXykXbJ718vp0= github.com/dunglas/mercure v0.18.4/go.mod h1:J/WQtiI31VacQJ1CBV1pqisKzPjoxIaZ9ZUSyhctKas= github.com/dunglas/mercure/caddy v0.18.4 h1:uxG50dbnsgNaDAlHX+8Y1b62ZvEcw1eHt5LrC6as0nQ= github.com/dunglas/mercure/caddy v0.18.4/go.mod h1:187W43Uae6s+bga5NJ8p+07Avbj3UsT78wA7/+3KMEw= -github.com/dunglas/vulcain v1.1.1 h1:nWh6sEhaeSla3IVXpzxQ8tK1nEr4lM1Q/HW8EVdpIgU= -github.com/dunglas/vulcain v1.1.1/go.mod h1:5YslB+KQI6SbghCDB3zrDyGtS2WCLvu+oFBkHi6mo+w= -github.com/dunglas/vulcain/caddy v1.1.1 h1:TT90lkiqnF1rGEyWXwZwhnuTRInNmYgJsFzR9ZH8pbQ= -github.com/dunglas/vulcain/caddy v1.1.1/go.mod h1:6aXBrXh46qlJv9rIBlX5DlxzmRPJyVWpnFp8JMkpBNI= +github.com/dunglas/vulcain v1.2.0 h1:RPNYuTe0woh4bGfIMAJ3dCgJDN8VJwhDjucQiCOoUsE= +github.com/dunglas/vulcain v1.2.0/go.mod h1:LhyYeqSAEw9P65l25CIzS1sRwJxkP75Qa7p8lIHZPsc= +github.com/dunglas/vulcain/caddy v1.2.0 h1:2O2R7Hn+kkInv6mrmOk5LLDtgRdPKGlXzdFJUKrb/jE= +github.com/dunglas/vulcain/caddy v1.2.0/go.mod h1:RAbiewGNIyWCmT37C2k4O1hs4IF+QIGVVgSNQuW2FH4= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -181,43 +187,45 @@ github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiD github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= -github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= +github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU= +github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= -github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= -github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= +github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= +github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= -github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.2.1 h1:KOIHODQj58PmL80G2Eak4WdvUzjSJSm0vG72crDCqb8= +github.com/go-chi/chi/v5 v5.2.1/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= -github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY= +github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= -github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU= +github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -227,18 +235,18 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6 h1:ygfAzuHUP3wed0um8AamwtZIh022Ie5lnsWHhItj/sY= -github.com/google/brotli/go/cbrotli v0.0.0-20241111155135-4303850b01d6/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/brotli/go/cbrotli v0.0.0-20250131134309-440e03642b89 h1:uTi61Z6B5ROLqhx+kKoZ1l0+Nw5GWKpqcgjaPQQYsUs= +github.com/google/brotli/go/cbrotli v0.0.0-20250131134309-440e03642b89/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cel-go v0.23.2 h1:UdEe3CvQh3Nv+E/j9r1Y//WO0K0cSyD7/y0bzyLIMI4= -github.com/google/cel-go v0.23.2/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo= +github.com/google/cel-go v0.24.1 h1:jsBCtxG8mM5wiUJDSGUqU0K7Mtr3w7Eyv00rw4DiZxI= +github.com/google/cel-go v0.24.1/go.mod h1:Hdf9TqOaTNSFQA1ybQaRqATVoK7m/zcf7IMhGXP5zI8= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= -github.com/google/certificate-transparency-go v1.3.0 h1:+UhSNQAyA38Ed4CGfwOZeG4sJ030ELQZE4xtMFOxA7U= -github.com/google/certificate-transparency-go v1.3.0/go.mod h1:/xVlT13jyrOuJOXTW5PjCBCrHBtXUq/jT5UeW40xliQ= +github.com/google/certificate-transparency-go v1.3.1 h1:akbcTfQg0iZlANZLn0L9xOeWtyCIdeoYhKrqi5iH3Go= +github.com/google/certificate-transparency-go v1.3.1/go.mod h1:gg+UQlx6caKEDQ9EElFOujyxEQEfOiQzAt6782Bvi8k= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -248,20 +256,20 @@ github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+u github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-tpm v0.9.3 h1:+yx0/anQuGzi+ssRqeD6WpXjW2L/V0dItUayO0i9sRc= github.com/google/go-tpm v0.9.3/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= -github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= -github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= +github.com/google/go-tpm-tools v0.4.5 h1:3fhthtyMDbIZFR5/0y1hvUoZ1Kf4i1eZ7C73R4Pvd+k= +github.com/google/go-tpm-tools v0.4.5/go.mod h1:ktjTNq8yZFD6TzdBFefUfen96rF3NpYwpSb2d8bc+Y8= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= -github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 h1:b/8HpQhvKLSNzH5oTXN2WkNcMl6YB5K3FRbb+i+Ml34= +github.com/google/pprof v0.0.0-20250418163039-24c5476c6587/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4= +github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= @@ -274,12 +282,11 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= @@ -288,14 +295,12 @@ github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso= -github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= -github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= +github.com/jackc/pgx/v5 v5.7.4 h1:9wKznZrhWa2QiHL+NjTSPP6yjl3451BX3imWDnokYlg= +github.com/jackc/pgx/v5 v5.7.4/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= @@ -323,12 +328,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/libdns/libdns v0.2.3 h1:ba30K4ObwMGB/QTmqUxf3H4/GmUrCAIkMWejeGl12v8= -github.com/libdns/libdns v0.2.3/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= +github.com/libdns/libdns v1.0.0-beta.1 h1:KIf4wLfsrEpXpZ3vmc/poM8zCATXT2klbdPe6hyOBjQ= +github.com/libdns/libdns v1.0.0-beta.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= -github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= @@ -343,19 +346,17 @@ github.com/maypok86/otter v1.2.4 h1:HhW1Pq6VdJkmWwcZZq19BlEQkHtI8xgsQzBVXJU0nfc= github.com/maypok86/otter v1.2.4/go.mod h1:mKLfoI7v1HOmQMwFgX4QkRk23mX6ge3RDvjdHOWG4R4= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/acmez/v3 v3.1.0 h1:RlOx2SSZ8dIAM5GfkMe8TdaxjjkiHTGorlMUt8GeMzg= -github.com/mholt/acmez/v3 v3.1.0/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= +github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= +github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY= -github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs= +github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc= +github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc= github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -368,14 +369,20 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 h1:G7ERwszslrBzRxj//JalHPu/3yz+De2J+4aLtSRlHiY= +github.com/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037/go.mod h1:2bpvgLBZEtENV5scfDFEtB/5+1M4hkQhDQrccEJ/qGw= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 h1:bQx3WeLcUWy+RletIKwUIt4x3t8n2SxavmoclizMb8c= +github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o= +github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= +github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= +github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= +github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= +github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU= @@ -404,8 +411,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.49.0 h1:w5iJHXwHxs1QxyBv1EHKuC50GX5to8mJAxvtnttJp94= -github.com/quic-go/quic-go v0.49.0/go.mod h1:s2wDnmCdooUQBmQfpUSTCYBl1/D4FcqbULMMkASvR6s= +github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= +github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= @@ -413,10 +420,8 @@ github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= -github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k= +github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk= github.com/schollz/jsonstore v1.1.0 h1:WZBDjgezFS34CHI+myb4s8GGpir3UMpy7vWoCeO0n6E= github.com/schollz/jsonstore v1.1.0/go.mod h1:15c6+9guw8vDRyozGjN3FoILt0wpruJk9Pi66vjaZfg= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -449,23 +454,24 @@ github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5k github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/slackhq/nebula v1.9.4 h1:p06JxtXT/OBMWt2OQkY7F0phOBb42X93YWNsS1yqC9o= -github.com/slackhq/nebula v1.9.4/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= +github.com/slackhq/nebula v1.9.5 h1:ZrxcvP/lxwFglaijmiwXLuCSkybZMJnqSYI1S8DtGnY= +github.com/slackhq/nebula v1.9.5/go.mod h1:1+4q4wd3dDAjO8rKCttSb9JIVbklQhuJiBp5I0lbIsQ= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smallstep/certificates v0.28.1 h1:hLYz1It9mecJD0DqQ+qLldQnTUkanFIztuyqmxKRZkY= -github.com/smallstep/certificates v0.28.1/go.mod h1:/xlSParPTewKBdhyp/vHcoOmtwK8AbPiXdmbu6c4J3A= -github.com/smallstep/cli-utils v0.10.0 h1:CfXNvHtIN5pAzGvGP0NEUZoGFcj5epNEB6RSpSfduek= -github.com/smallstep/cli-utils v0.10.0/go.mod h1:jIeNa5ctrVg89lU5TaQKYd6o1eFxi9mtZu1sXSxpEBg= +github.com/smallstep/certificates v0.28.3 h1:rcMh1TAs8m2emP3aDJxKLkE9jriAtcFtCuj2gttnpmI= +github.com/smallstep/certificates v0.28.3/go.mod h1:P/IjGTvRCem3YZ7d1XtUxpvK/8dfFsJn7gaVLpMXbJw= +github.com/smallstep/cli-utils v0.12.1 h1:D9QvfbFqiKq3snGZ2xDcXEFrdFJ1mQfPHZMq/leerpE= +github.com/smallstep/cli-utils v0.12.1/go.mod h1:skV2Neg8qjiKPu2fphM89H9bIxNpKiiRTnX9Q6Lc+20= github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935 h1:kjYvkvS/Wdy0PVRDUAA0gGJIVSEZYhiAJtfwYgOYoGA= github.com/smallstep/go-attestation v0.4.4-0.20240109183208-413678f90935/go.mod h1:vNAduivU014fubg6ewygkAvQC0IQVXqdc8vaGl/0er4= +github.com/smallstep/linkedca v0.23.0 h1:5W/7EudlK1HcCIdZM68dJlZ7orqCCCyv6bm2l/0JmLU= +github.com/smallstep/linkedca v0.23.0/go.mod h1:7cyRM9soAYySg9ag65QwytcgGOM+4gOlkJ/YA58A9E8= github.com/smallstep/nosql v0.7.0 h1:YiWC9ZAHcrLCrayfaF+QJUv16I2bZ7KdLC3RpJcnAnE= github.com/smallstep/nosql v0.7.0/go.mod h1:H5VnKMCbeq9QA6SRY5iqPylfxLfYcLwvUff3onQ8+HU= -github.com/smallstep/pkcs7 v0.1.1/go.mod h1:dL6j5AIz9GHjVEBTXtW+QliALcgM19RtXaTeyxI+AfA= github.com/smallstep/pkcs7 v0.2.1 h1:6Kfzr/QizdIuB6LSv8y1LJdZ3aPSfTNhTLqAx9CTLfA= github.com/smallstep/pkcs7 v0.2.1/go.mod h1:RcXHsMfL+BzH8tRhmrF1NkkpebKpq3JEM66cOFxanf0= -github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc h1:gJ1mkz/iJhKnKUJit5DCFxNRWo9mxIkVm9SI8DiUugI= -github.com/smallstep/scep v0.0.0-20241223071629-a37a330173bc/go.mod h1:bENyEPpujhqigQx115AitJTc11LZmGUNk0ftgyhcNus= +github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492 h1:k23+s51sgYix4Zgbvpmy+1ZgXLjr4ZTkBTqXmpnImwA= +github.com/smallstep/scep v0.0.0-20250318231241-a25cabb69492/go.mod h1:QQhwLqCS13nhv8L5ov7NgusowENUtXdEzdytjmJHdZQ= github.com/smallstep/truststore v0.13.0 h1:90if9htAOblavbMeWlqNLnO9bsjjgVv2hQeQJCi/py4= github.com/smallstep/truststore v0.13.0/go.mod h1:3tmMp2aLKZ/OA/jnFUB0cYPcho402UG2knuJoPh4j7A= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= @@ -476,8 +482,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= -github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= +github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= @@ -489,8 +495,8 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -539,8 +545,8 @@ github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zI github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= -github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +github.com/yuin/goldmark v1.7.10 h1:S+LrtBjRmqMac2UdtB6yyCEJm+UILZ2fefI4p7o0QpI= +github.com/yuin/goldmark v1.7.10/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= @@ -554,46 +560,44 @@ go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/contrib/propagators/autoprop v0.58.0 h1:pL1MMoBcG/ol6fVsjE1bbOO9A8GMQiN+T73hnmaXDoU= -go.opentelemetry.io/contrib/propagators/autoprop v0.58.0/go.mod h1:EU5uMoCqafsagp4hzFqzu1Eyg/8L23JS5Y1hChoHf7s= -go.opentelemetry.io/contrib/propagators/aws v1.33.0 h1:MefPfPIut0IxEiQRK1qVv5AFADBOwizl189+m7QhpFg= -go.opentelemetry.io/contrib/propagators/aws v1.33.0/go.mod h1:VB6xPo12uW/PezOqtA/cY2/DiAGYshnhID606wC9NEY= -go.opentelemetry.io/contrib/propagators/b3 v1.33.0 h1:ig/IsHyyoQ1F1d6FUDIIW5oYpsuTVtN16AyGOgdjAHQ= -go.opentelemetry.io/contrib/propagators/b3 v1.33.0/go.mod h1:EsVYoNy+Eol5znb6wwN3XQTILyjl040gUpEnUSNZfsk= -go.opentelemetry.io/contrib/propagators/jaeger v1.33.0 h1:Jok/dG8kfp+yod29XKYV/blWgYPlMuRUoRHljrXMF5E= -go.opentelemetry.io/contrib/propagators/jaeger v1.33.0/go.mod h1:ku/EpGk44S5lyVMbtJRK2KFOnXEehxf6SDnhu1eZmjA= -go.opentelemetry.io/contrib/propagators/ot v1.33.0 h1:xj/pQFKo4ROsx0v129KpLgFwaYMgFTu3dAMEEih97cY= -go.opentelemetry.io/contrib/propagators/ot v1.33.0/go.mod h1:/xxHCLhTmaypEFwMViRGROj2qgrGiFrkxIlATt0rddc= -go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= -go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0 h1:5pojmb1U1AogINhN3SurB+zm/nIcusopeBNp42f45QM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.33.0/go.mod h1:57gTHJSE5S1tqg+EKsLPlTWhpHMsWlVmer+LA926XiA= -go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= -go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= -go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU= -go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ= -go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= -go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= -go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= -go.step.sm/crypto v0.57.1 h1:bt7ugfc0m2/nJ9/uhQOtXRW3xQr8zJwL087FLQk9mvc= -go.step.sm/crypto v0.57.1/go.mod h1:wL25/Mh7edmo36AA93hf9agP493Zt3y4QBzB1wzwOjc= -go.step.sm/linkedca v0.22.2 h1:zmFIyDC77gFHo6FLQJ8OIXYpLYDIsgDWaYqtYs6A9/Q= -go.step.sm/linkedca v0.22.2/go.mod h1:ESY8r5VfhJA8ZVzI6hXIQcEX9LwaY3aoPnT+Hb9jpbw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= +go.opentelemetry.io/contrib/propagators/autoprop v0.60.0 h1:sevByeAWTtfBdJQT7nkJfK5wOCjNpmDMZGPEBx3l1RA= +go.opentelemetry.io/contrib/propagators/autoprop v0.60.0/go.mod h1:uEhyRPnUTSeUwMjDdrMQnsJ0sQ2mf/fA94hfchemm4A= +go.opentelemetry.io/contrib/propagators/aws v1.35.0 h1:xoXA+5dVwsf5uE5GvSJ3lKiapyMFuIzbEmJwQ0JP+QU= +go.opentelemetry.io/contrib/propagators/aws v1.35.0/go.mod h1:s11Orts/IzEgw9Srw5iRXtk2kM2j3jt/45noUWyf60E= +go.opentelemetry.io/contrib/propagators/b3 v1.35.0 h1:DpwKW04LkdFRFCIgM3sqwTJA/QREHMeMHYPWP1WeaPQ= +go.opentelemetry.io/contrib/propagators/b3 v1.35.0/go.mod h1:9+SNxwqvCWo1qQwUpACBY5YKNVxFJn5mlbXg/4+uKBg= +go.opentelemetry.io/contrib/propagators/jaeger v1.35.0 h1:UIrZgRBHUrYRlJ4V419lVb4rs2ar0wFzKNAebaP05XU= +go.opentelemetry.io/contrib/propagators/jaeger v1.35.0/go.mod h1:0ciyFyYZxE6JqRAQvIgGRabKWDUmNdW3GAQb6y/RlFU= +go.opentelemetry.io/contrib/propagators/ot v1.35.0 h1:ZsgYijVvOpju4mq3g4QyqCwLKs2vKenlCpZHbKu50OA= +go.opentelemetry.io/contrib/propagators/ot v1.35.0/go.mod h1:t1ZwtgjEtDH9uW6OlCRVLL2wOgsTJmp0pJwNouUq+HE= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= +go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.step.sm/crypto v0.61.0 h1:rW7He7LCzhOFn9JIf/XzgTjt4Djpf1KhdXHfbXUVFpY= +go.step.sm/crypto v0.61.0/go.mod h1:rYubsWIX9j9xzi/aXXr2eFSzoTN3sklTAxJYucBqZaY= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs= +go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -610,15 +614,14 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= -golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4 h1:QDiVWrFJ2lyXzr3pJnIREQWR8S7jkjzuWJPJda8Ic8E= -golang.org/x/crypto/x509roots/fallback v0.0.0-20250214233241-911360c8a4f4/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU= +golang.org/x/crypto/x509roots/fallback v0.0.0-20250418111936-9c1aa6af88df h1:SwgTucX8ajPE0La2ELpYOIs8jVMoCMpAvYB6mDqP9vk= +golang.org/x/crypto/x509roots/fallback v0.0.0-20250418111936-9c1aa6af88df/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4= -golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -651,8 +654,8 @@ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAG golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE= -golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= +golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -664,7 +667,6 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= @@ -689,7 +691,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= @@ -701,7 +702,6 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= @@ -714,14 +714,13 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4= -golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -732,14 +731,14 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/api v0.218.0 h1:x6JCjEWeZ9PFCRe9z0FBrNwj7pB7DOAqT35N+IPnAUA= -google.golang.org/api v0.218.0/go.mod h1:5VGHBAkxrA/8EFjLVEYmMUJ8/8+gWWQ3s4cFH0FxG2M= +google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8= +google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -749,18 +748,20 @@ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk= -google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0= -google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= +google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= +google.golang.org/genproto/googleapis/api v0.0.0-20250421163800-61c742ae3ef0 h1:bphwUhSYYbcKacmc2crgiMvwARwqeNCtAI5g1PohT34= +google.golang.org/genproto/googleapis/api v0.0.0-20250421163800-61c742ae3ef0/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0 h1:l7lvb5BMqtbmd7fibSq7fi956Fv9/sqiwI9qOw8ltCo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250421163800-61c742ae3ef0/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= -google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= +google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM= +google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -768,8 +769,6 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= From 99293831489fece9c7c19bd3eb505556c1a528e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 22 Apr 2025 17:16:57 +0200 Subject: [PATCH 36/51] chore: run prettier --- .github/dependabot.yaml | 6 +- CONTRIBUTING.md | 90 ++++----- README.md | 58 +++--- docs/compile.md | 2 +- docs/config.md | 14 +- docs/docker.md | 8 +- docs/embed.md | 46 ++--- docs/fr/CONTRIBUTING.md | 92 ++++----- docs/fr/README.md | 56 +++--- docs/fr/compile.md | 2 +- docs/fr/config.md | 14 +- docs/fr/docker.md | 8 +- docs/fr/embed.md | 46 ++--- docs/fr/known-issues.md | 8 +- docs/fr/laravel.md | 130 ++++++------ docs/fr/metrics.md | 22 +-- docs/fr/performance.md | 22 +-- docs/fr/static.md | 22 +-- docs/fr/worker.md | 6 +- docs/known-issues.md | 8 +- docs/laravel.md | 138 ++++++------- docs/metrics.md | 22 +-- docs/performance.md | 8 +- docs/ru/CONTRIBUTING.md | 96 ++++----- docs/ru/README.md | 50 ++--- docs/ru/compile.md | 4 +- docs/ru/config.md | 14 +- docs/ru/docker.md | 8 +- docs/ru/embed.md | 38 ++-- docs/ru/known-issues.md | 16 +- docs/ru/laravel.md | 132 ++++++------- docs/ru/production.md | 2 +- docs/ru/static.md | 22 +-- docs/ru/worker.md | 8 +- docs/static.md | 22 +-- docs/tr/CONTRIBUTING.md | 404 +++++++++++++++++++------------------- docs/tr/README.md | 156 +++++++-------- docs/tr/compile.md | 200 +++++++++---------- docs/tr/config.md | 8 +- docs/tr/docker.md | 342 ++++++++++++++++---------------- docs/tr/early-hints.md | 42 ++-- docs/tr/embed.md | 264 ++++++++++++------------- docs/tr/github-actions.md | 62 +++--- docs/tr/known-issues.md | 214 ++++++++++---------- docs/tr/laravel.md | 52 ++--- docs/tr/mercure.md | 24 +-- docs/tr/production.md | 278 +++++++++++++------------- docs/tr/static.md | 200 +++++++++---------- docs/tr/worker.md | 245 +++++++++++------------ docs/worker.md | 6 +- 50 files changed, 1870 insertions(+), 1867 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 72584f8e03..9f07ece873 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -10,7 +10,7 @@ updates: groups: go-modules: patterns: - - '*' + - "*" - package-ecosystem: gomod directory: /caddy schedule: @@ -25,7 +25,7 @@ updates: groups: go-modules: patterns: - - '*' + - "*" - package-ecosystem: github-actions directory: / schedule: @@ -35,4 +35,4 @@ updates: groups: github-actions: patterns: - - '*' + - "*" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a720e13f0e..bf3ef696ff 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -111,22 +111,22 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Download the debug version of the FrankenPHP binary from GitHub or create your custom static build including debug symbols: - ```console - docker buildx bake \ - --load \ - --set static-builder.args.DEBUG_SYMBOLS=1 \ - --set "static-builder.platform=linux/amd64" \ - static-builder - docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp - ``` + ```console + docker buildx bake \ + --load \ + --set static-builder.args.DEBUG_SYMBOLS=1 \ + --set "static-builder.platform=linux/amd64" \ + static-builder + docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp + ``` 2. Replace your current version of `frankenphp` by the debug FrankenPHP executable 3. Start FrankenPHP as usual (alternatively, you can directly start FrankenPHP with GDB: `gdb --args frankenphp run`) 4. Attach to the process with GDB: - ```console - gdb -p `pidof frankenphp` - ``` + ```console + gdb -p `pidof frankenphp` + ``` 5. If necessary, type `continue` in the GDB shell 6. Make FrankenPHP crash @@ -138,60 +138,60 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Open `.github/workflows/tests.yml` 2. Enable PHP debug symbols - ```patch - - uses: shivammathur/setup-php@v2 - # ... - env: - phpts: ts - + debug: true - ``` + ```patch + - uses: shivammathur/setup-php@v2 + # ... + env: + phpts: ts + + debug: true + ``` 3. Enable `tmate` to connect to the container - ```patch - - name: Set CGO flags - run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" - + - run: | - + sudo apt install gdb - + mkdir -p /home/runner/.config/gdb/ - + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit - + - uses: mxschmitt/action-tmate@v3 - ``` + ```patch + - name: Set CGO flags + run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" + + - run: | + + sudo apt install gdb + + mkdir -p /home/runner/.config/gdb/ + + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit + + - uses: mxschmitt/action-tmate@v3 + ``` 4. Connect to the container 5. Open `frankenphp.go` 6. Enable `cgosymbolizer` - ```patch - - //_ "github.com/ianlancetaylor/cgosymbolizer" - + _ "github.com/ianlancetaylor/cgosymbolizer" - ``` + ```patch + - //_ "github.com/ianlancetaylor/cgosymbolizer" + + _ "github.com/ianlancetaylor/cgosymbolizer" + ``` 7. Download the module: `go get` 8. In the container, you can use GDB and the like: - ```console - go test -tags watcher -c -ldflags=-w - gdb --args frankenphp.test -test.run ^MyTest$ - ``` + ```console + go test -tags watcher -c -ldflags=-w + gdb --args frankenphp.test -test.run ^MyTest$ + ``` 9. When the bug is fixed, revert all these changes ## Misc Dev Resources -* [PHP embedding in uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) -* [PHP embedding in NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) -* [PHP embedding in Go (go-php)](https://github.com/deuill/go-php) -* [PHP embedding in Go (GoEmPHP)](https://github.com/mikespook/goemphp) -* [PHP embedding in C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) -* [Extending and Embedding PHP by Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) -* [What the heck is TSRMLS_CC, anyway?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) -* [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) +- [PHP embedding in uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) +- [PHP embedding in NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) +- [PHP embedding in Go (go-php)](https://github.com/deuill/go-php) +- [PHP embedding in Go (GoEmPHP)](https://github.com/mikespook/goemphp) +- [PHP embedding in C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) +- [Extending and Embedding PHP by Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) +- [What the heck is TSRMLS_CC, anyway?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) +- [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) ## Docker-Related Resources -* [Bake file definition](https://docs.docker.com/build/customize/bake/file-definition/) -* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) +- [Bake file definition](https://docs.docker.com/build/customize/bake/file-definition/) +- [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) ## Useful Command diff --git a/README.md b/README.md index e0b0c9d8f4..a3bc473425 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,13 @@ FrankenPHP is a modern application server for PHP built on top of the [Caddy](https://caddyserver.com/) web server. -FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: [*Early Hints*](https://frankenphp.dev/docs/early-hints/), [worker mode](https://frankenphp.dev/docs/worker/), [real-time capabilities](https://frankenphp.dev/docs/mercure/), automatic HTTPS, HTTP/2, and HTTP/3 support... +FrankenPHP gives superpowers to your PHP apps thanks to its stunning features: [_Early Hints_](https://frankenphp.dev/docs/early-hints/), [worker mode](https://frankenphp.dev/docs/worker/), [real-time capabilities](https://frankenphp.dev/docs/mercure/), automatic HTTPS, HTTP/2, and HTTP/3 support... FrankenPHP works with any PHP app and makes your Laravel and Symfony projects faster than ever thanks to their official integrations with the worker mode. FrankenPHP can also be used as a standalone Go library to embed PHP in any app using `net/http`. -[**Learn more** on *frankenphp.dev*](https://frankenphp.dev) and in this slide deck: +[**Learn more** on _frankenphp.dev_](https://frankenphp.dev) and in this slide deck: Slides @@ -84,33 +84,33 @@ frankenphp php-server ## Docs -* [Classic mode](https://frankenphp.dev/docs/classic/) -* [Worker mode](https://frankenphp.dev/docs/worker/) -* [Early Hints support (103 HTTP status code)](https://frankenphp.dev/docs/early-hints/) -* [Real-time](https://frankenphp.dev/docs/mercure/) -* [Efficiently Serving Large Static Files](https://frankenphp.dev/docs/x-sendfile/) -* [Configuration](https://frankenphp.dev/docs/config/) -* [Docker images](https://frankenphp.dev/docs/docker/) -* [Deploy in production](https://frankenphp.dev/docs/production/) -* [Performance optimization](https://frankenphp.dev/docs/performance/) -* [Create **standalone**, self-executable PHP apps](https://frankenphp.dev/docs/embed/) -* [Create static binaries](https://frankenphp.dev/docs/static/) -* [Compile from sources](https://frankenphp.dev/docs/compile/) -* [Monitoring FrankenPHP](https://frankenphp.dev/docs/metrics/) -* [Laravel integration](https://frankenphp.dev/docs/laravel/) -* [Known issues](https://frankenphp.dev/docs/known-issues/) -* [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo) -* [Go library documentation](https://pkg.go.dev/github.com/dunglas/frankenphp) -* [Contributing and debugging](https://frankenphp.dev/docs/contributing/) +- [Classic mode](https://frankenphp.dev/docs/classic/) +- [Worker mode](https://frankenphp.dev/docs/worker/) +- [Early Hints support (103 HTTP status code)](https://frankenphp.dev/docs/early-hints/) +- [Real-time](https://frankenphp.dev/docs/mercure/) +- [Efficiently Serving Large Static Files](https://frankenphp.dev/docs/x-sendfile/) +- [Configuration](https://frankenphp.dev/docs/config/) +- [Docker images](https://frankenphp.dev/docs/docker/) +- [Deploy in production](https://frankenphp.dev/docs/production/) +- [Performance optimization](https://frankenphp.dev/docs/performance/) +- [Create **standalone**, self-executable PHP apps](https://frankenphp.dev/docs/embed/) +- [Create static binaries](https://frankenphp.dev/docs/static/) +- [Compile from sources](https://frankenphp.dev/docs/compile/) +- [Monitoring FrankenPHP](https://frankenphp.dev/docs/metrics/) +- [Laravel integration](https://frankenphp.dev/docs/laravel/) +- [Known issues](https://frankenphp.dev/docs/known-issues/) +- [Demo app (Symfony) and benchmarks](https://github.com/dunglas/frankenphp-demo) +- [Go library documentation](https://pkg.go.dev/github.com/dunglas/frankenphp) +- [Contributing and debugging](https://frankenphp.dev/docs/contributing/) ## Examples and Skeletons -* [Symfony](https://github.com/dunglas/symfony-docker) -* [API Platform](https://api-platform.com/docs/symfony) -* [Laravel](https://frankenphp.dev/docs/laravel/) -* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) -* [WordPress](https://github.com/StephenMiracle/frankenwp) -* [Drupal](https://github.com/dunglas/frankenphp-drupal) -* [Joomla](https://github.com/alexandreelise/frankenphp-joomla) -* [TYPO3](https://github.com/ochorocho/franken-typo3) -* [Magento2](https://github.com/ekino/frankenphp-magento2) +- [Symfony](https://github.com/dunglas/symfony-docker) +- [API Platform](https://api-platform.com/docs/symfony) +- [Laravel](https://frankenphp.dev/docs/laravel/) +- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) +- [WordPress](https://github.com/StephenMiracle/frankenwp) +- [Drupal](https://github.com/dunglas/frankenphp-drupal) +- [Joomla](https://github.com/alexandreelise/frankenphp-joomla) +- [TYPO3](https://github.com/ochorocho/franken-typo3) +- [Magento2](https://github.com/ekino/frankenphp-magento2) diff --git a/docs/compile.md b/docs/compile.md index 84b7337f20..9e2e0bdefe 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -67,7 +67,7 @@ Some FrankenPHP features depend on optional system dependencies that must be ins Alternatively, these features can be disabled by passing build tags to the Go compiler. | Feature | Dependency | Build tag to disable it | -|--------------------------------|-----------------------------------------------------------------------|-------------------------| +| ------------------------------ | --------------------------------------------------------------------- | ----------------------- | | Brotli compression | [Brotli](https://github.com/google/brotli) | nobrotli | | Restart workers on file change | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher | diff --git a/docs/config.md b/docs/config.md index f0b46d83bf..e62528a47a 100644 --- a/docs/config.md +++ b/docs/config.md @@ -179,10 +179,10 @@ where the FrankenPHP process was started. You can instead also specify one or mo } ``` -* The `**` pattern signifies recursive watching -* Directories can also be relative (to where the FrankenPHP process is started from) -* If you have multiple workers defined, all of them will be restarted when a file changes -* Be wary about watching files that are created at runtime (like logs) since they might cause unwanted worker restarts. +- The `**` pattern signifies recursive watching +- Directories can also be relative (to where the FrankenPHP process is started from) +- If you have multiple workers defined, all of them will be restarted when a file changes +- Be wary about watching files that are created at runtime (like logs) since they might cause unwanted worker restarts. The file watcher is based on [e-dant/watcher](https://github.com/e-dant/watcher). @@ -218,9 +218,9 @@ You can find more information about this setting in the [Caddy documentation](ht The following environment variables can be used to inject Caddy directives in the `Caddyfile` without modifying it: -* `SERVER_NAME`: change [the addresses on which to listen](https://caddyserver.com/docs/caddyfile/concepts#addresses), the provided hostnames will also be used for the generated TLS certificate -* `CADDY_GLOBAL_OPTIONS`: inject [global options](https://caddyserver.com/docs/caddyfile/options) -* `FRANKENPHP_CONFIG`: inject config under the `frankenphp` directive +- `SERVER_NAME`: change [the addresses on which to listen](https://caddyserver.com/docs/caddyfile/concepts#addresses), the provided hostnames will also be used for the generated TLS certificate +- `CADDY_GLOBAL_OPTIONS`: inject [global options](https://caddyserver.com/docs/caddyfile/options) +- `FRANKENPHP_CONFIG`: inject config under the `frankenphp` directive As for FPM and CLI SAPIs, environment variables are exposed by default in the `$_SERVER` superglobal. diff --git a/docs/docker.md b/docs/docker.md index 1875a6c481..d2a6592066 100644 --- a/docs/docker.md +++ b/docs/docker.md @@ -6,8 +6,8 @@ Variants for PHP 8.2, 8.3 and 8.4 are provided. The tags follow this pattern: `dunglas/frankenphp:-php-` -* `` and `` are version numbers of FrankenPHP and PHP respectively, ranging from major (e.g. `1`), minor (e.g. `1.2`) to patch versions (e.g. `1.2.3`). -* `` is either `bookworm` (for Debian Bookworm) or `alpine` (for the latest stable version of Alpine). +- `` and `` are version numbers of FrankenPHP and PHP respectively, ranging from major (e.g. `1`), minor (e.g. `1.2`) to patch versions (e.g. `1.2.3`). +- `` is either `bookworm` (for Debian Bookworm) or `alpine` (for the latest stable version of Alpine). [Browse tags](https://hub.docker.com/r/dunglas/frankenphp/tags). @@ -193,8 +193,8 @@ Example: `:8000` The Docker images are built: -* when a new release is tagged -* daily at 4 am UTC, if new versions of the official PHP images are available +- when a new release is tagged +- daily at 4 am UTC, if new versions of the official PHP images are available ## Development Versions diff --git a/docs/embed.md b/docs/embed.md index e0efe905c6..7d18174fc3 100644 --- a/docs/embed.md +++ b/docs/embed.md @@ -14,10 +14,10 @@ Before creating the self-contained binary be sure that your app is ready for emb For instance, you likely want to: -* Install the production dependencies of the app -* Dump the autoloader -* Enable the production mode of your application (if any) -* Strip unneeded files such as `.git` or tests to reduce the size of your final binary +- Install the production dependencies of the app +- Dump the autoloader +- Enable the production mode of your application (if any) +- Strip unneeded files such as `.git` or tests to reduce the size of your final binary For instance, for a Symfony app, you can use the following commands: @@ -53,34 +53,34 @@ The easiest way to create a Linux binary is to use the Docker-based builder we p 1. Create a file named `static-build.Dockerfile` in the repository of your app: - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Copy your app - WORKDIR /go/src/app/dist/app - COPY . . + # Copy your app + WORKDIR /go/src/app/dist/app + COPY . . - # Build the static binary - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Build the static binary + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` - > [!CAUTION] - > - > Some `.dockerignore` files (e.g. default [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) - > will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build. + > [!CAUTION] + > + > Some `.dockerignore` files (e.g. default [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build. 2. Build: - ```console - docker build -t static-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-app -f static-build.Dockerfile . + ``` 3. Extract the binary: - ```console - docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp - ``` + ```console + docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp + ``` The resulting binary is the file named `my-app` in the current directory. diff --git a/docs/fr/CONTRIBUTING.md b/docs/fr/CONTRIBUTING.md index fb5ff856e6..f49a3e60f1 100644 --- a/docs/fr/CONTRIBUTING.md +++ b/docs/fr/CONTRIBUTING.md @@ -112,22 +112,22 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Téléchargez la version de débogage du binaire FrankenPHP depuis GitHub ou créez votre propre build statique incluant des symboles de débogage : - ```console - docker buildx bake \ - --load \ - --set static-builder.args.DEBUG_SYMBOLS=1 \ - --set "static-builder.platform=linux/amd64" \ - static-builder - docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp - ``` + ```console + docker buildx bake \ + --load \ + --set static-builder.args.DEBUG_SYMBOLS=1 \ + --set "static-builder.platform=linux/amd64" \ + static-builder + docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp + ``` 2. Remplacez votre version actuelle de `frankenphp` par l'exécutable de débogage de FrankenPHP. 3. Démarrez FrankenPHP comme d'habitude (alternativement, vous pouvez directement démarrer FrankenPHP avec GDB : `gdb --args frankenphp run`). 4. Attachez-vous au processus avec GDB : - ```console - gdb -p `pidof frankenphp` - ``` + ```console + gdb -p `pidof frankenphp` + ``` 5. Si nécessaire, tapez `continue` dans le shell GDB 6. Faites planter FrankenPHP. @@ -139,61 +139,61 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Ouvrir `.github/workflows/tests.yml` 2. Activer les symboles de débogage de la bibliothèque PHP - ```patch - - uses: shivammathur/setup-php@v2 - # ... - env: - phpts: ts - + debug: true - ``` + ```patch + - uses: shivammathur/setup-php@v2 + # ... + env: + phpts: ts + + debug: true + ``` 3. Activer `tmate` pour se connecter au conteneur - ```patch - - name: Set CGO flags - run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" - + - run: | - + sudo apt install gdb - + mkdir -p /home/runner/.config/gdb/ - + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit - + - uses: mxschmitt/action-tmate@v3 - ``` + ```patch + - name: Set CGO flags + run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" + + - run: | + + sudo apt install gdb + + mkdir -p /home/runner/.config/gdb/ + + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit + + - uses: mxschmitt/action-tmate@v3 + ``` 4. Se connecter au conteneur 5. Ouvrir `frankenphp.go` 6. Activer `cgosymbolizer` - ```patch - - //_ "github.com/ianlancetaylor/cgosymbolizer" - + _ "github.com/ianlancetaylor/cgosymbolizer" - ``` + ```patch + - //_ "github.com/ianlancetaylor/cgosymbolizer" + + _ "github.com/ianlancetaylor/cgosymbolizer" + ``` 7. Télécharger le module : `go get` 8. Dans le conteneur, vous pouvez utiliser GDB et similaires : - ```console - go test -tags watcher -c -ldflags=-w - gdb --args frankenphp.test -test.run ^MyTest$ - ``` + ```console + go test -tags watcher -c -ldflags=-w + gdb --args frankenphp.test -test.run ^MyTest$ + ``` 9. Quand le bug est corrigé, annulez tous les changements. ## Ressources Diverses pour le Développement -* [Intégration de PHP dans uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) -* [Intégration de PHP dans NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) -* [Intégration de PHP dans Go (go-php)](https://github.com/deuill/go-php) -* [Intégration de PHP dans Go (GoEmPHP)](https://github.com/mikespook/goemphp) -* [Intégration de PHP dans C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) -* [Extending and Embedding PHP par Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) -* [Qu'est-ce que TSRMLS_CC, au juste ?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) -* [Intégration de PHP sur Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4) -* [Bindings SDL](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) +- [Intégration de PHP dans uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) +- [Intégration de PHP dans NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) +- [Intégration de PHP dans Go (go-php)](https://github.com/deuill/go-php) +- [Intégration de PHP dans Go (GoEmPHP)](https://github.com/mikespook/goemphp) +- [Intégration de PHP dans C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) +- [Extending and Embedding PHP par Sara Golemon](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) +- [Qu'est-ce que TSRMLS_CC, au juste ?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) +- [Intégration de PHP sur Mac](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4) +- [Bindings SDL](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) ## Ressources Liées à Docker -* [Définition du fichier Bake](https://docs.docker.com/build/customize/bake/file-definition/) -* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) +- [Définition du fichier Bake](https://docs.docker.com/build/customize/bake/file-definition/) +- [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) ## Commande utile diff --git a/docs/fr/README.md b/docs/fr/README.md index 0cc3853ac3..427824f8ab 100644 --- a/docs/fr/README.md +++ b/docs/fr/README.md @@ -4,7 +4,7 @@ FrankenPHP est un serveur d'applications moderne pour PHP construit à partir du serveur web [Caddy](https://caddyserver.com/). -FrankenPHP donne des super-pouvoirs à vos applications PHP grâce à ses fonctionnalités à la pointe : [*Early Hints*](early-hints.md), [mode worker](worker.md), [fonctionnalités en temps réel](mercure.md), HTTPS automatique, prise en charge de HTTP/2 et HTTP/3... +FrankenPHP donne des super-pouvoirs à vos applications PHP grâce à ses fonctionnalités à la pointe : [_Early Hints_](early-hints.md), [mode worker](worker.md), [fonctionnalités en temps réel](mercure.md), HTTPS automatique, prise en charge de HTTP/2 et HTTP/3... FrankenPHP fonctionne avec n'importe quelle application PHP et rend vos projets Laravel et Symfony plus rapides que jamais grâce à leurs intégrations officielles avec le mode worker. @@ -83,33 +83,33 @@ frankenphp php-server ## Documentation -* [Le mode classique](classic.md) -* [Le mode worker](worker.md) -* [Le support des Early Hints (code de statut HTTP 103)](early-hints.md) -* [Temps réel](mercure.md) -* [Servir efficacement les fichiers statiques volumineux](x-sendfile.md) -* [Configuration](config.md) -* [Images Docker](docker.md) -* [Déploiement en production](production.md) -* [Optimisation des performances](performance.md) -* [Créer des applications PHP **standalone**, auto-exécutables](embed.md) -* [Créer un build statique](static.md) -* [Compiler depuis les sources](compile.md) -* [Surveillance de FrankenPHP](metrics.md) -* [Intégration Laravel](laravel.md) -* [Problèmes connus](known-issues.md) -* [Application de démo (Symfony) et benchmarks](https://github.com/dunglas/frankenphp-demo) -* [Documentation de la bibliothèque Go](https://pkg.go.dev/github.com/dunglas/frankenphp) -* [Contribuer et débugger](CONTRIBUTING.md) +- [Le mode classique](classic.md) +- [Le mode worker](worker.md) +- [Le support des Early Hints (code de statut HTTP 103)](early-hints.md) +- [Temps réel](mercure.md) +- [Servir efficacement les fichiers statiques volumineux](x-sendfile.md) +- [Configuration](config.md) +- [Images Docker](docker.md) +- [Déploiement en production](production.md) +- [Optimisation des performances](performance.md) +- [Créer des applications PHP **standalone**, auto-exécutables](embed.md) +- [Créer un build statique](static.md) +- [Compiler depuis les sources](compile.md) +- [Surveillance de FrankenPHP](metrics.md) +- [Intégration Laravel](laravel.md) +- [Problèmes connus](known-issues.md) +- [Application de démo (Symfony) et benchmarks](https://github.com/dunglas/frankenphp-demo) +- [Documentation de la bibliothèque Go](https://pkg.go.dev/github.com/dunglas/frankenphp) +- [Contribuer et débugger](CONTRIBUTING.md) ## Exemples et squelettes -* [Symfony](https://github.com/dunglas/symfony-docker) -* [API Platform](https://api-platform.com/docs/distribution/) -* [Laravel](laravel.md) -* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) -* [WordPress](https://github.com/StephenMiracle/frankenwp) -* [Drupal](https://github.com/dunglas/frankenphp-drupal) -* [Joomla](https://github.com/alexandreelise/frankenphp-joomla) -* [TYPO3](https://github.com/ochorocho/franken-typo3) -* [Magento2](https://github.com/ekino/frankenphp-magento2) +- [Symfony](https://github.com/dunglas/symfony-docker) +- [API Platform](https://api-platform.com/docs/distribution/) +- [Laravel](laravel.md) +- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) +- [WordPress](https://github.com/StephenMiracle/frankenwp) +- [Drupal](https://github.com/dunglas/frankenphp-drupal) +- [Joomla](https://github.com/alexandreelise/frankenphp-joomla) +- [TYPO3](https://github.com/ochorocho/franken-typo3) +- [Magento2](https://github.com/ekino/frankenphp-magento2) diff --git a/docs/fr/compile.md b/docs/fr/compile.md index bb913620f5..5c039abc71 100644 --- a/docs/fr/compile.md +++ b/docs/fr/compile.md @@ -67,7 +67,7 @@ Certaines fonctionnalités de FrankenPHP nécessitent des dépendances optionnel Ces fonctionnalités peuvent également être désactivées en passant des balises de compilation au compilateur Go. | Fonctionnalité | Dépendance | Balise de compilation pour la désactiver | -|---------------------------------------------------------|-----------------------------------------------------------------------|------------------------------------------| +| ------------------------------------------------------- | --------------------------------------------------------------------- | ---------------------------------------- | | Compression Brotli | [Brotli](https://github.com/google/brotli) | nobrotli | | Redémarrage des workers en cas de changement de fichier | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher | diff --git a/docs/fr/config.md b/docs/fr/config.md index 740be3a01c..787c6bfcb4 100644 --- a/docs/fr/config.md +++ b/docs/fr/config.md @@ -180,10 +180,10 @@ où le processus FrankenPHP a été lancé. Vous pouvez également spécifier un } ``` -* Le motif `**` signifie une surveillance récursive. -* Les répertoires peuvent également être relatifs (depuis l'endroit où le processus FrankenPHP est démarré). -* Si vous avez défini plusieurs workers, ils seront tous redémarrés lorsqu'un fichier est modifié. -* Méfiez-vous des fichiers créés au moment de l'exécution (comme les logs) car ils peuvent provoquer des redémarrages intempestifs du worker. +- Le motif `**` signifie une surveillance récursive. +- Les répertoires peuvent également être relatifs (depuis l'endroit où le processus FrankenPHP est démarré). +- Si vous avez défini plusieurs workers, ils seront tous redémarrés lorsqu'un fichier est modifié. +- Méfiez-vous des fichiers créés au moment de l'exécution (comme les logs) car ils peuvent provoquer des redémarrages intempestifs du worker. La surveillance des fichiers est basé sur [e-dant/watcher](https://github.com/e-dant/watcher). @@ -219,9 +219,9 @@ Vous trouverez plus d'informations sur ce paramètre dans la [documentation Cadd Les variables d'environnement suivantes peuvent être utilisées pour insérer des directives Caddy dans le `Caddyfile` sans le modifier : -* `SERVER_NAME` : change [les adresses sur lesquelles écouter](https://caddyserver.com/docs/caddyfile/concepts#addresses), les noms d'hôte fournis seront également utilisés pour le certificat TLS généré -* `CADDY_GLOBAL_OPTIONS` : injecte [des options globales](https://caddyserver.com/docs/caddyfile/options) -* `FRANKENPHP_CONFIG` : insère la configuration sous la directive `frankenphp` +- `SERVER_NAME` : change [les adresses sur lesquelles écouter](https://caddyserver.com/docs/caddyfile/concepts#addresses), les noms d'hôte fournis seront également utilisés pour le certificat TLS généré +- `CADDY_GLOBAL_OPTIONS` : injecte [des options globales](https://caddyserver.com/docs/caddyfile/options) +- `FRANKENPHP_CONFIG` : insère la configuration sous la directive `frankenphp` Comme pour les SAPI FPM et CLI, les variables d'environnement ne sont exposées par défaut dans la superglobale `$_SERVER`. diff --git a/docs/fr/docker.md b/docs/fr/docker.md index 5cc6d6fcd0..bf863a5db8 100644 --- a/docs/fr/docker.md +++ b/docs/fr/docker.md @@ -6,8 +6,8 @@ Des variantes pour PHP 8.2, 8.3 et 8.4 sont disponibles. [Parcourir les tags](ht Les tags suivent le pattern suivant: `dunglas/frankenphp:-php-` -* `` et `` sont repsectivement les numéros de version de FrankenPHP et PHP, allant de majeur (e.g. `1`), mineur (e.g. `1.2`) à des versions correctives (e.g. `1.2.3`). -* `` est soit `bookworm` (pour Debian Bookworm) ou `alpine` (pour la dernière version stable d'Alpine). +- `` et `` sont repsectivement les numéros de version de FrankenPHP et PHP, allant de majeur (e.g. `1`), mineur (e.g. `1.2`) à des versions correctives (e.g. `1.2.3`). +- `` est soit `bookworm` (pour Debian Bookworm) ou `alpine` (pour la dernière version stable d'Alpine). [Parcourir les tags](https://hub.docker.com/r/dunglas/frankenphp/tags). @@ -192,8 +192,8 @@ Exemple `:8000` Les images Docker sont construites : -* lorsqu'une nouvelle version est taguée -* tous les jours à 4h UTC, si de nouvelles versions des images officielles PHP sont disponibles +- lorsqu'une nouvelle version est taguée +- tous les jours à 4h UTC, si de nouvelles versions des images officielles PHP sont disponibles ## Versions de développement diff --git a/docs/fr/embed.md b/docs/fr/embed.md index a0d902fac6..cd51def776 100644 --- a/docs/fr/embed.md +++ b/docs/fr/embed.md @@ -14,10 +14,10 @@ Avant de créer le binaire autonome, assurez-vous que votre application est prê Vous devrez probablement : -* Installer les dépendances de production de l'application -* Dumper l'autoloader -* Activer le mode production de votre application (si disponible) -* Supprimer les fichiers inutiles tels que `.git` ou les tests pour réduire la taille de votre binaire final +- Installer les dépendances de production de l'application +- Dumper l'autoloader +- Activer le mode production de votre application (si disponible) +- Supprimer les fichiers inutiles tels que `.git` ou les tests pour réduire la taille de votre binaire final Par exemple, pour une application Symfony, lancez les commandes suivantes : @@ -55,34 +55,34 @@ La manière la plus simple de créer un binaire Linux est d'utiliser le builder 1. Créez un fichier nommé `static-build.Dockerfile` dans le répertoire de votre application préparée : - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Copy your app - WORKDIR /go/src/app/dist/app - COPY . . + # Copy your app + WORKDIR /go/src/app/dist/app + COPY . . - # Build the static binary, be sure to select only the PHP extensions you want - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Build the static binary, be sure to select only the PHP extensions you want + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` - > [!CAUTION] - > - > Certains fichiers `.dockerignore` (par exemple celui fourni par défaut par [Symfony Docker](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) - > empêchent la copie du dossier `vendor/` et des fichiers `.env`. Assurez-vous d'ajuster ou de supprimer le fichier `.dockerignore` avant le build. + > [!CAUTION] + > + > Certains fichiers `.dockerignore` (par exemple celui fourni par défaut par [Symfony Docker](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > empêchent la copie du dossier `vendor/` et des fichiers `.env`. Assurez-vous d'ajuster ou de supprimer le fichier `.dockerignore` avant le build. 2. Construisez: - ```console - docker build -t static-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-app -f static-build.Dockerfile . + ``` 3. Extrayez le binaire : - ```console - docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp - ``` + ```console + docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp + ``` Le binaire généré sera nommé `my-app` dans le répertoire courant. diff --git a/docs/fr/known-issues.md b/docs/fr/known-issues.md index 1601d6f13f..1738f61007 100644 --- a/docs/fr/known-issues.md +++ b/docs/fr/known-issues.md @@ -5,7 +5,7 @@ Les extensions suivantes sont connues pour ne pas être compatibles avec FrankenPHP : | Nom | Raison | Alternatives | -|-------------------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------| +| ----------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- | | [imap](https://www.php.net/manual/en/imap.installation.php) | Non thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) | | [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Non thread-safe | - | @@ -14,7 +14,7 @@ Les extensions suivantes sont connues pour ne pas être compatibles avec Franken Les extensions suivantes ont des bugs connus ou des comportements inattendus lorsqu'elles sont utilisées avec FrankenPHP : | Nom | Problème | -|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [ext-openssl](https://www.php.net/manual/fr/book.openssl.php) | Lors de l'utilisation d'une version statique de FrankenPHP (construite avec la libc musl), l'extension OpenSSL peut planter sous de fortes charges. Une solution consiste à utiliser une version liée dynamiquement (comme celle utilisée dans les images Docker). Ce bogue est [suivi par PHP](https://github.com/php/php-src/issues/13648). | ## get_browser @@ -80,8 +80,8 @@ docker run \ Les [scripts Composer](https://getcomposer.org/doc/articles/scripts.md) peuvent vouloir exécuter un binaire PHP pour certaines tâches, par exemple dans [un projet Laravel](laravel.md) pour exécuter `@php artisan package:discover --ansi`. Cela [echoue actuellement](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) pour deux raisons : -* Composer ne sait pas comment appeler le binaire FrankenPHP ; -* Composer peut ajouter des paramètres PHP en utilisant le paramètre `-d` dans la commande, ce que FrankenPHP ne supporte pas encore. +- Composer ne sait pas comment appeler le binaire FrankenPHP ; +- Composer peut ajouter des paramètres PHP en utilisant le paramètre `-d` dans la commande, ce que FrankenPHP ne supporte pas encore. Comme solution de contournement, nous pouvons créer un script shell dans `/usr/local/bin/php` qui supprime les paramètres non supportés et appelle ensuite FrankenPHP : diff --git a/docs/fr/laravel.md b/docs/fr/laravel.md index f96d0c8c75..a037108edb 100644 --- a/docs/fr/laravel.md +++ b/docs/fr/laravel.md @@ -19,23 +19,23 @@ Vous pouvez également exécuter vos projets Laravel avec FrankenPHP depuis votr 1. [Téléchargez le binaire correspondant à votre système](README.md#binaire-autonome) 2. Ajoutez la configuration suivante dans un fichier nommé `Caddyfile` placé dans le répertoire racine de votre projet Laravel : - ```caddyfile - { - frankenphp - } - - # Le nom de domaine de votre serveur - localhost { - # Définir le répertoire racine sur le dossier public/ - root public/ - # Autoriser la compression (optionnel) - encode zstd br gzip - # Exécuter les scripts PHP du dossier public/ et servir les assets - php_server { - try_files {path} index.php - } - } - ``` + ```caddyfile + { + frankenphp + } + + # Le nom de domaine de votre serveur + localhost { + # Définir le répertoire racine sur le dossier public/ + root public/ + # Autoriser la compression (optionnel) + encode zstd br gzip + # Exécuter les scripts PHP du dossier public/ et servir les assets + php_server { + try_files {path} index.php + } + } + ``` 3. Démarrez FrankenPHP depuis le répertoire racine de votre projet Laravel : `frankenphp run` @@ -61,17 +61,17 @@ php artisan octane:frankenphp La commande `octane:frankenphp` peut prendre les options suivantes : -* `--host` : L'adresse IP à laquelle le serveur doit se lier (par défaut : `127.0.0.1`) -* `--port` : Le port sur lequel le serveur doit être disponible (par défaut : `8000`) -* `--admin-port` : Le port sur lequel le serveur administratif doit être disponible (par défaut : `2019`) -* `--workers` : Le nombre de workers qui doivent être disponibles pour traiter les requêtes (par défaut : `auto`) -* `--max-requests` : Le nombre de requêtes à traiter avant de recharger le serveur (par défaut : `500`) -* `--caddyfile` : Le chemin vers le fichier `Caddyfile` de FrankenPHP -* `--https` : Activer HTTPS, HTTP/2, et HTTP/3, et générer automatiquement et renouveler les certificats -* `--http-redirect` : Activer la redirection HTTP vers HTTPS (uniquement activé si --https est passé) -* `--watch` : Recharger automatiquement le serveur lorsque l'application est modifiée -* `--poll` : Utiliser le sondage du système de fichiers pendant la surveillance pour surveiller les fichiers sur un réseau -* `--log-level` : Enregistrer les messages au niveau de journalisation spécifié ou au-dessus, en utilisant le logger natif de Caddy +- `--host` : L'adresse IP à laquelle le serveur doit se lier (par défaut : `127.0.0.1`) +- `--port` : Le port sur lequel le serveur doit être disponible (par défaut : `8000`) +- `--admin-port` : Le port sur lequel le serveur administratif doit être disponible (par défaut : `2019`) +- `--workers` : Le nombre de workers qui doivent être disponibles pour traiter les requêtes (par défaut : `auto`) +- `--max-requests` : Le nombre de requêtes à traiter avant de recharger le serveur (par défaut : `500`) +- `--caddyfile` : Le chemin vers le fichier `Caddyfile` de FrankenPHP +- `--https` : Activer HTTPS, HTTP/2, et HTTP/3, et générer automatiquement et renouveler les certificats +- `--http-redirect` : Activer la redirection HTTP vers HTTPS (uniquement activé si --https est passé) +- `--watch` : Recharger automatiquement le serveur lorsque l'application est modifiée +- `--poll` : Utiliser le sondage du système de fichiers pendant la surveillance pour surveiller les fichiers sur un réseau +- `--log-level` : Enregistrer les messages au niveau de journalisation spécifié ou au-dessus, en utilisant le logger natif de Caddy > [!TIP] > Pour obtenir des logs structurés en JSON logs (utile quand vous utilisez des solutions d'analyse de logs), passez explicitement l'otpion `--log-level`. @@ -87,31 +87,31 @@ Suivez ces étapes pour empaqueter votre application Laravel en tant que binaire 1. Créez un fichier nommé `static-build.Dockerfile` dans le dépôt de votre application : - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Copiez votre application - WORKDIR /go/src/app/dist/app - COPY . . + # Copiez votre application + WORKDIR /go/src/app/dist/app + COPY . . - # Supprimez les tests et autres fichiers inutiles pour gagner de la place - # Alternativement, ajoutez ces fichiers à un fichier .dockerignore - RUN rm -Rf tests/ + # Supprimez les tests et autres fichiers inutiles pour gagner de la place + # Alternativement, ajoutez ces fichiers à un fichier .dockerignore + RUN rm -Rf tests/ - # Copiez le fichier .env - RUN cp .env.example .env - # Modifier APP_ENV et APP_DEBUG pour qu'ils soient prêts pour la production - RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env + # Copiez le fichier .env + RUN cp .env.example .env + # Modifier APP_ENV et APP_DEBUG pour qu'ils soient prêts pour la production + RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env - # Apportez d'autres modifications à votre fichier .env si nécessaire + # Apportez d'autres modifications à votre fichier .env si nécessaire - # Installez les dépendances - RUN composer install --ignore-platform-reqs --no-dev -a + # Installez les dépendances + RUN composer install --ignore-platform-reqs --no-dev -a - # Construire le binaire statique - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Construire le binaire statique + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` > [!CAUTION] > @@ -120,39 +120,39 @@ Suivez ces étapes pour empaqueter votre application Laravel en tant que binaire 2. Build: - ```console - docker build -t static-laravel-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-laravel-app -f static-build.Dockerfile . + ``` 3. Extraire le binaire - ```console - docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp - ``` + ```console + docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp + ``` 4. Remplir les caches : - ```console - frankenphp php-cli artisan optimize - ``` + ```console + frankenphp php-cli artisan optimize + ``` 5. Exécutez les migrations de base de données (s'il y en a) : - ```console - frankenphp php-cli artisan migrate - ```` + ```console + frankenphp php-cli artisan migrate + ``` 6. Générer la clé secrète de l'application : - ```console - frankenphp php-cli artisan key:generate - ``` + ```console + frankenphp php-cli artisan key:generate + ``` 7. Démarrez le serveur: - ```console - frankenphp php-server - ``` + ```console + frankenphp php-server + ``` Votre application est maintenant prête ! diff --git a/docs/fr/metrics.md b/docs/fr/metrics.md index 76e9644384..697d2eebf1 100644 --- a/docs/fr/metrics.md +++ b/docs/fr/metrics.md @@ -2,16 +2,16 @@ Lorsque les [métriques Caddy](https://caddyserver.com/docs/metrics) sont activées, FrankenPHP expose les métriques suivantes : -* `frankenphp_total_threads` : Le nombre total de threads PHP. -* `frankenphp_busy_threads` : Le nombre de threads PHP en cours de traitement d'une requête (les workers en cours d'exécution consomment toujours un thread). -* `frankenphp_queue_depth` : Le nombre de requêtes régulières en file d'attente -* `frankenphp_total_workers{worker=« [nom_du_worker] »}` : Le nombre total de workers. -* `frankenphp_busy_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui traitent actuellement une requête. -* `frankenphp_worker_request_time{worker=« [nom_du_worker] »}` : Le temps passé à traiter les requêtes par tous les workers. -* `frankenphp_worker_request_count{worker=« [nom_du_worker] »}` : Le nombre de requêtes traitées par tous les workers. -* `frankenphp_ready_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui ont appelé `frankenphp_handle_request` au moins une fois. -* `frankenphp_worker_crashes{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker s'est arrêté de manière inattendue. -* `frankenphp_worker_restarts{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker a été délibérément redémarré. -* `frankenphp_worker_queue_depth{worker=« [nom_du_worker] »}` : Le nombre de requêtes en file d'attente. +- `frankenphp_total_threads` : Le nombre total de threads PHP. +- `frankenphp_busy_threads` : Le nombre de threads PHP en cours de traitement d'une requête (les workers en cours d'exécution consomment toujours un thread). +- `frankenphp_queue_depth` : Le nombre de requêtes régulières en file d'attente +- `frankenphp_total_workers{worker=« [nom_du_worker] »}` : Le nombre total de workers. +- `frankenphp_busy_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui traitent actuellement une requête. +- `frankenphp_worker_request_time{worker=« [nom_du_worker] »}` : Le temps passé à traiter les requêtes par tous les workers. +- `frankenphp_worker_request_count{worker=« [nom_du_worker] »}` : Le nombre de requêtes traitées par tous les workers. +- `frankenphp_ready_workers{worker=« [nom_du_worker] »}` : Le nombre de workers qui ont appelé `frankenphp_handle_request` au moins une fois. +- `frankenphp_worker_crashes{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker s'est arrêté de manière inattendue. +- `frankenphp_worker_restarts{worker=« [nom_du_worker] »}` : Le nombre de fois où un worker a été délibérément redémarré. +- `frankenphp_worker_queue_depth{worker=« [nom_du_worker] »}` : Le nombre de requêtes en file d'attente. Pour les métriques de worker, le placeholder `[nom_du_worker]` est remplacé par le nom du worker dans le Caddyfile, sinon le chemin absolu du fichier du worker sera utilisé. diff --git a/docs/fr/performance.md b/docs/fr/performance.md index a4c7f1da1c..e1531624a3 100644 --- a/docs/fr/performance.md +++ b/docs/fr/performance.md @@ -37,7 +37,7 @@ vous devez créer un script worker et vous assurer que l'application n'a pas de Les binaires statiques que nous fournissons, ainsi que la variante Alpine Linux des images Docker officielles, utilisent [la bibliothèque musl](https://musl.libc.org). PHP est connu pour être [significativement plus lent](https://gitlab.alpinelinux.org/alpine/aports/-/issues/14381) lorsqu'il utilise cette bibliothèque C alternative au lieu de la bibliothèque GNU traditionnelle, -surtout lorsqu'il est compilé en mode ZTS (*thread-safe*), ce qui est nécessaire pour FrankenPHP. +surtout lorsqu'il est compilé en mode ZTS (_thread-safe_), ce qui est nécessaire pour FrankenPHP. En outre, [certains bogues ne se produisent que lors de l'utilisation de musl](https://github.com/php/php-src/issues?q=sort%3Aupdated-desc+is%3Aissue+is%3Aopen+label%3ABug+musl). @@ -113,16 +113,16 @@ route { } ``` -## *Placeholders* +## _Placeholders_ -Vous pouvez utiliser des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders) dans les directives `root` et `env`. +Vous pouvez utiliser des [_placeholders_](https://caddyserver.com/docs/conventions#placeholders) dans les directives `root` et `env`. Cependant, cela empêche la mise en cache de ces valeurs et a un coût important en termes de performances. -Si possible, évitez les *placeholders* dans ces directives. +Si possible, évitez les _placeholders_ dans ces directives. ## `resolve_root_symlink` -Par défaut, si le *document root* est un lien symbolique, il est automatiquement résolu par FrankenPHP (c'est nécessaire pour le bon fonctionnement de PHP). +Par défaut, si le _document root_ est un lien symbolique, il est automatiquement résolu par FrankenPHP (c'est nécessaire pour le bon fonctionnement de PHP). Si la racine du document n'est pas un lien symbolique, vous pouvez désactiver cette fonctionnalité. ```caddyfile @@ -131,12 +131,12 @@ php_server { } ``` -Cela améliorera les performances si la directive `root` contient des [*placeholders*](https://caddyserver.com/docs/conventions#placeholders). +Cela améliorera les performances si la directive `root` contient des [_placeholders_](https://caddyserver.com/docs/conventions#placeholders). Le gain sera négligeable dans les autres cas. ## Journaux -La journalisation est évidemment très utile, mais, par définition, elle nécessite des opérations d'*I/O* et des allocations de mémoire, +La journalisation est évidemment très utile, mais, par définition, elle nécessite des opérations d'_I/O_ et des allocations de mémoire, ce qui réduit considérablement les performances. Assurez-vous de [définir le niveau de journalisation](https://caddyserver.com/docs/caddyfile/options#log) correctement, et de ne journaliser que ce qui est nécessaire. @@ -148,10 +148,10 @@ Toutes les optimisations de performances habituelles liées à PHP s'appliquent En particulier : -* vérifiez que [OPcache](https://www.php.net/manual/en/book.opcache.php) est installé, activé et correctement configuré -* activez [les optimisations de l'autoloader de Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md) -* assurez-vous que le cache `realpath` est suffisamment grand pour les besoins de votre application -* utilisez le [pré-chargement](https://www.php.net/manual/en/opcache.preloading.php) +- vérifiez que [OPcache](https://www.php.net/manual/en/book.opcache.php) est installé, activé et correctement configuré +- activez [les optimisations de l'autoloader de Composer](https://getcomposer.org/doc/articles/autoloader-optimization.md) +- assurez-vous que le cache `realpath` est suffisamment grand pour les besoins de votre application +- utilisez le [pré-chargement](https://www.php.net/manual/en/opcache.preloading.php) Pour plus de détails, lisez [l'entrée de la documentation dédiée de Symfony](https://symfony.com/doc/current/performance.html) (la plupart des conseils sont utiles même si vous n'utilisez pas Symfony). diff --git a/docs/fr/static.md b/docs/fr/static.md index a66fbfbf41..02467d3168 100644 --- a/docs/fr/static.md +++ b/docs/fr/static.md @@ -116,17 +116,17 @@ Note : ce script fonctionne également sur Linux (et probablement sur d'autres U Les variables d'environnement suivantes peuvent être transmises à `docker build` et au script `build-static.sh` pour personnaliser la construction statique : -* `FRANKENPHP_VERSION` : la version de FrankenPHP à utiliser -* `PHP_VERSION` : la version de PHP à utiliser -* `PHP_EXTENSIONS` : les extensions PHP à construire ([liste des extensions prises en charge](https://static-php.dev/en/guide/extensions.html)) -* `PHP_EXTENSION_LIBS` : bibliothèques supplémentaires à construire qui ajoutent des fonctionnalités aux extensions -* `XCADDY_ARGS` : arguments à passer à [xcaddy](https://github.com/caddyserver/xcaddy), par exemple pour ajouter des modules Caddy supplémentaires -* `EMBED` : chemin de l'application PHP à intégrer dans le binaire -* `CLEAN` : lorsque défini, `libphp` et toutes ses dépendances sont construites à partir de zéro (pas de cache) -* `DEBUG_SYMBOLS` : lorsque défini, les symboles de débogage ne seront pas supprimés et seront ajoutés dans le binaire -* `NO_COMPRESS`: ne pas compresser le binaire avec UPX -* `MIMALLOC`: (expérimental, Linux seulement) remplace l'allocateur mallocng de musl par [mimalloc](https://github.com/microsoft/mimalloc) pour des performances améliorées -* `RELEASE` : (uniquement pour les mainteneurs) lorsque défini, le binaire résultant sera uploadé sur GitHub +- `FRANKENPHP_VERSION` : la version de FrankenPHP à utiliser +- `PHP_VERSION` : la version de PHP à utiliser +- `PHP_EXTENSIONS` : les extensions PHP à construire ([liste des extensions prises en charge](https://static-php.dev/en/guide/extensions.html)) +- `PHP_EXTENSION_LIBS` : bibliothèques supplémentaires à construire qui ajoutent des fonctionnalités aux extensions +- `XCADDY_ARGS` : arguments à passer à [xcaddy](https://github.com/caddyserver/xcaddy), par exemple pour ajouter des modules Caddy supplémentaires +- `EMBED` : chemin de l'application PHP à intégrer dans le binaire +- `CLEAN` : lorsque défini, `libphp` et toutes ses dépendances sont construites à partir de zéro (pas de cache) +- `DEBUG_SYMBOLS` : lorsque défini, les symboles de débogage ne seront pas supprimés et seront ajoutés dans le binaire +- `NO_COMPRESS`: ne pas compresser le binaire avec UPX +- `MIMALLOC`: (expérimental, Linux seulement) remplace l'allocateur mallocng de musl par [mimalloc](https://github.com/microsoft/mimalloc) pour des performances améliorées +- `RELEASE` : (uniquement pour les mainteneurs) lorsque défini, le binaire résultant sera uploadé sur GitHub ## Extensions diff --git a/docs/fr/worker.md b/docs/fr/worker.md index 186e85eabd..69923e8160 100644 --- a/docs/fr/worker.md +++ b/docs/fr/worker.md @@ -146,7 +146,7 @@ curl -X POST http://localhost:2019/frankenphp/workers/restart ### Worker Failures Si un script de worker se plante avec un code de sortie non nul, FrankenPHP le redémarre avec une stratégie de backoff exponentielle. -Si le script worker reste en place plus longtemps que le dernier backoff * 2, FrankenPHP ne pénalisera pas le script et le redémarrera à nouveau. +Si le script worker reste en place plus longtemps que le dernier backoff \* 2, FrankenPHP ne pénalisera pas le script et le redémarrera à nouveau. Toutefois, si le script de worker continue d'échouer avec un code de sortie non nul dans un court laps de temps (par exemple, une faute de frappe dans un script), FrankenPHP plantera avec l'erreur : `too many consecutive failures` (trop d'échecs consécutifs). @@ -155,8 +155,8 @@ Toutefois, si le script de worker continue d'échouer avec un code de sortie non [Les superglobales PHP](https://www.php.net/manual/fr/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...) se comportent comme suit : -* avant le premier appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs liées au script worker lui-même -* pendant et après l'appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs générées à partir de la requête HTTP traitée, chaque appel à `frankenphp_handle_request()` change les valeurs des superglobales +- avant le premier appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs liées au script worker lui-même +- pendant et après l'appel à `frankenphp_handle_request()`, les superglobales contiennent des valeurs générées à partir de la requête HTTP traitée, chaque appel à `frankenphp_handle_request()` change les valeurs des superglobales Pour accéder aux superglobales du script worker à l'intérieur de la fonction de rappel, vous devez les copier et importer la copie dans le scope de la fonction : diff --git a/docs/known-issues.md b/docs/known-issues.md index ba7c9421bb..4e3d2e4f37 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -5,7 +5,7 @@ The following extensions are known not to be compatible with FrankenPHP: | Name | Reason | Alternatives | -|-------------------------------------------------------------------------------------------------------------|-----------------|----------------------------------------------------------------------------------------------------------------------| +| ----------------------------------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------- | | [imap](https://www.php.net/manual/en/imap.installation.php) | Not thread-safe | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) | | [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Not thread-safe | - | @@ -14,7 +14,7 @@ The following extensions are known not to be compatible with FrankenPHP: The following extensions have known bugs and unexpected behaviors when used with FrankenPHP: | Name | Problem | -|---------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | When using a static build of FrankenPHP (built with the musl libc), the OpenSSL extension may crash under heavy loads. A workaround is to use a dynamically linked build (like the one used in Docker images). This bug is [being tracked by PHP](https://github.com/php/php-src/issues/13648). | ## get_browser @@ -80,8 +80,8 @@ docker run \ [Composer scripts](https://getcomposer.org/doc/articles/scripts.md) may want to execute a PHP binary for some tasks, e.g. in [a Laravel project](laravel.md) to run `@php artisan package:discover --ansi`. This [currently fails](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) for two reasons: -* Composer does not know how to call the FrankenPHP binary; -* Composer may add PHP settings using the `-d` flag in the command, which FrankenPHP does not yet support. +- Composer does not know how to call the FrankenPHP binary; +- Composer may add PHP settings using the `-d` flag in the command, which FrankenPHP does not yet support. As a workaround, we can create a shell script in `/usr/local/bin/php` which strips the unsupported parameters and then calls FrankenPHP: diff --git a/docs/laravel.md b/docs/laravel.md index 1a240c9d23..54203367c5 100644 --- a/docs/laravel.md +++ b/docs/laravel.md @@ -19,23 +19,23 @@ Alternatively, you can run your Laravel projects with FrankenPHP from your local 1. [Download the binary corresponding to your system](../#standalone-binary) 2. Add the following configuration to a file named `Caddyfile` in the root directory of your Laravel project: - ```caddyfile - { - frankenphp - } - - # The domain name of your server - localhost { - # Set the webroot to the public/ directory - root public/ - # Enable compression (optional) - encode zstd br gzip - # Execute PHP files from the public/ directory and serve assets - php_server { - try_files {path} index.php - } - } - ``` + ```caddyfile + { + frankenphp + } + + # The domain name of your server + localhost { + # Set the webroot to the public/ directory + root public/ + # Enable compression (optional) + encode zstd br gzip + # Execute PHP files from the public/ directory and serve assets + php_server { + try_files {path} index.php + } + } + ``` 3. Start FrankenPHP from the root directory of your Laravel project: `frankenphp run` @@ -61,17 +61,17 @@ php artisan octane:frankenphp The `octane:frankenphp` command can take the following options: -* `--host`: The IP address the server should bind to (default: `127.0.0.1`) -* `--port`: The port the server should be available on (default: `8000`) -* `--admin-port`: The port the admin server should be available on (default: `2019`) -* `--workers`: The number of workers that should be available to handle requests (default: `auto`) -* `--max-requests`: The number of requests to process before reloading the server (default: `500`) -* `--caddyfile`: The path to the FrankenPHP `Caddyfile` file (default: [stubbed `Caddyfile` in Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile)) -* `--https`: Enable HTTPS, HTTP/2, and HTTP/3, and automatically generate and renew certificates -* `--http-redirect`: Enable HTTP to HTTPS redirection (only enabled if --https is passed) -* `--watch`: Automatically reload the server when the application is modified -* `--poll`: Use file system polling while watching in order to watch files over a network -* `--log-level`: Log messages at or above the specified log level, using the native Caddy logger +- `--host`: The IP address the server should bind to (default: `127.0.0.1`) +- `--port`: The port the server should be available on (default: `8000`) +- `--admin-port`: The port the admin server should be available on (default: `2019`) +- `--workers`: The number of workers that should be available to handle requests (default: `auto`) +- `--max-requests`: The number of requests to process before reloading the server (default: `500`) +- `--caddyfile`: The path to the FrankenPHP `Caddyfile` file (default: [stubbed `Caddyfile` in Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile)) +- `--https`: Enable HTTPS, HTTP/2, and HTTP/3, and automatically generate and renew certificates +- `--http-redirect`: Enable HTTP to HTTPS redirection (only enabled if --https is passed) +- `--watch`: Automatically reload the server when the application is modified +- `--poll`: Use file system polling while watching in order to watch files over a network +- `--log-level`: Log messages at or above the specified log level, using the native Caddy logger > [!TIP] > To get structured JSON logs (useful when using log analytics solutions), explicitly the pass `--log-level` option. @@ -87,72 +87,72 @@ Follow these steps to package your Laravel app as a standalone binary for Linux: 1. Create a file named `static-build.Dockerfile` in the repository of your app: - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Copy your app - WORKDIR /go/src/app/dist/app - COPY . . + # Copy your app + WORKDIR /go/src/app/dist/app + COPY . . - # Remove the tests and other unneeded files to save space - # Alternatively, add these files to a .dockerignore file - RUN rm -Rf tests/ + # Remove the tests and other unneeded files to save space + # Alternatively, add these files to a .dockerignore file + RUN rm -Rf tests/ - # Copy .env file - RUN cp .env.example .env - # Change APP_ENV and APP_DEBUG to be production ready - RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env + # Copy .env file + RUN cp .env.example .env + # Change APP_ENV and APP_DEBUG to be production ready + RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env - # Make other changes to your .env file if needed + # Make other changes to your .env file if needed - # Install the dependencies - RUN composer install --ignore-platform-reqs --no-dev -a + # Install the dependencies + RUN composer install --ignore-platform-reqs --no-dev -a - # Build the static binary - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Build the static binary + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` - > [!CAUTION] - > - > Some `.dockerignore` files - > will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build. + > [!CAUTION] + > + > Some `.dockerignore` files + > will ignore the `vendor/` directory and `.env` files. Be sure to adjust or remove the `.dockerignore` file before the build. 2. Build: - ```console - docker build -t static-laravel-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-laravel-app -f static-build.Dockerfile . + ``` 3. Extract the binary: - ```console - docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp - ``` + ```console + docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp + ``` 4. Populate caches: - ```console - frankenphp php-cli artisan optimize - ``` + ```console + frankenphp php-cli artisan optimize + ``` 5. Run database migrations (if any): - ```console - frankenphp php-cli artisan migrate - ```` + ```console + frankenphp php-cli artisan migrate + ``` 6. Generate app's secret key: - ```console - frankenphp php-cli artisan key:generate - ``` + ```console + frankenphp php-cli artisan key:generate + ``` 7. Start the server: - ```console - frankenphp php-server - ``` + ```console + frankenphp php-server + ``` Your app is now ready! diff --git a/docs/metrics.md b/docs/metrics.md index 2691afc15a..df02e08400 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -2,16 +2,16 @@ When [Caddy metrics](https://caddyserver.com/docs/metrics) are enabled, FrankenPHP exposes the following metrics: -* `frankenphp_total_threads`: The total number of PHP threads. -* `frankenphp_busy_threads`: The number of PHP threads currently processing a request (running workers always consume a thread). -* `frankenphp_queue_depth`: The number of regular queued requests -* `frankenphp_total_workers{worker="[worker_name]"}`: The total number of workers. -* `frankenphp_busy_workers{worker="[worker_name]"}`: The number of workers currently processing a request. -* `frankenphp_worker_request_time{worker="[worker_name]"}`: The time spent processing requests by all workers. -* `frankenphp_worker_request_count{worker="[worker_name]"}`: The number of requests processed by all workers. -* `frankenphp_ready_workers{worker="[worker_name]"}`: The number of workers that have called `frankenphp_handle_request` at least once. -* `frankenphp_worker_crashes{worker="[worker_name]"}`: The number of times a worker has unexpectedly terminated. -* `frankenphp_worker_restarts{worker="[worker_name]"}`: The number of times a worker has been deliberately restarted. -* `frankenphp_worker_queue_depth{worker="[worker_name]"}`: The number of queued requests. +- `frankenphp_total_threads`: The total number of PHP threads. +- `frankenphp_busy_threads`: The number of PHP threads currently processing a request (running workers always consume a thread). +- `frankenphp_queue_depth`: The number of regular queued requests +- `frankenphp_total_workers{worker="[worker_name]"}`: The total number of workers. +- `frankenphp_busy_workers{worker="[worker_name]"}`: The number of workers currently processing a request. +- `frankenphp_worker_request_time{worker="[worker_name]"}`: The time spent processing requests by all workers. +- `frankenphp_worker_request_count{worker="[worker_name]"}`: The number of requests processed by all workers. +- `frankenphp_ready_workers{worker="[worker_name]"}`: The number of workers that have called `frankenphp_handle_request` at least once. +- `frankenphp_worker_crashes{worker="[worker_name]"}`: The number of times a worker has unexpectedly terminated. +- `frankenphp_worker_restarts{worker="[worker_name]"}`: The number of times a worker has been deliberately restarted. +- `frankenphp_worker_queue_depth{worker="[worker_name]"}`: The number of queued requests. For worker metrics, the `[worker_name]` placeholder is replaced by the worker name in the Caddyfile, otherwise absolute path of worker file will be used. diff --git a/docs/performance.md b/docs/performance.md index 19a29a967e..ec4e6c3a5e 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -148,10 +148,10 @@ All usual PHP-related performance optimizations apply with FrankenPHP. In particular: -* check that [OPcache](https://www.php.net/manual/en/book.opcache.php) is installed, enabled and properly configured -* enable [Composer autoloader optimizations](https://getcomposer.org/doc/articles/autoloader-optimization.md) -* ensure that the `realpath` cache is big enough for the needs of your application -* use [preloading](https://www.php.net/manual/en/opcache.preloading.php) +- check that [OPcache](https://www.php.net/manual/en/book.opcache.php) is installed, enabled and properly configured +- enable [Composer autoloader optimizations](https://getcomposer.org/doc/articles/autoloader-optimization.md) +- ensure that the `realpath` cache is big enough for the needs of your application +- use [preloading](https://www.php.net/manual/en/opcache.preloading.php) For more details, read [the dedicated Symfony documentation entry](https://symfony.com/doc/current/performance.html) (most tips are useful even if you don't use Symfony). diff --git a/docs/ru/CONTRIBUTING.md b/docs/ru/CONTRIBUTING.md index 564e95d5c2..8c7c08d6dc 100644 --- a/docs/ru/CONTRIBUTING.md +++ b/docs/ru/CONTRIBUTING.md @@ -108,22 +108,22 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Скачайте отладочную версию бинарного файла FrankenPHP с GitHub или создайте собственную статическую сборку с включённым отладочным режимом: - ```console - docker buildx bake \ - --load \ - --set static-builder.args.DEBUG_SYMBOLS=1 \ - --set "static-builder.platform=linux/amd64" \ - static-builder - docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp - ``` + ```console + docker buildx bake \ + --load \ + --set static-builder.args.DEBUG_SYMBOLS=1 \ + --set "static-builder.platform=linux/amd64" \ + static-builder + docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp + ``` 2. Замените текущую версию `frankenphp` на бинарный файл с включенным отладочным режимом. 3. Запустите FrankenPHP как обычно (или сразу запустите FrankenPHP с GDB: `gdb --args frankenphp run`). 4. Подключитесь к процессу через GDB: - ```console - gdb -p `pidof frankenphp` - ``` + ```console + gdb -p `pidof frankenphp` + ``` 5. При необходимости введите `continue` в консоли GDB. 6. Вызовите сбой FrankenPHP. @@ -135,63 +135,63 @@ docker buildx bake -f docker-bake.hcl --pull --no-cache --push 1. Откройте файл `.github/workflows/tests.yml`. 2. Включите режим отладки PHP: - ```patch - - uses: shivammathur/setup-php@v2 - # ... - env: - phpts: ts - + debug: true - ``` + ```patch + - uses: shivammathur/setup-php@v2 + # ... + env: + phpts: ts + + debug: true + ``` 3. Настройте `tmate` для удалённого подключения к контейнеру: - ```patch - - - name: Set CGO flags - run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" - + - - + run: | - + sudo apt install gdb - + mkdir -p /home/runner/.config/gdb/ - + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit - + - - + uses: mxschmitt/action-tmate@v3 - ``` + ```patch + - + name: Set CGO flags + run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" + + - + + run: | + + sudo apt install gdb + + mkdir -p /home/runner/.config/gdb/ + + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit + + - + + uses: mxschmitt/action-tmate@v3 + ``` 4. Подключитесь к контейнеру. 5. Откройте файл `frankenphp.go`. 6. Включите `cgosymbolizer`: - ```patch - - //_ "github.com/ianlancetaylor/cgosymbolizer" - + _ "github.com/ianlancetaylor/cgosymbolizer" - ``` + ```patch + - //_ "github.com/ianlancetaylor/cgosymbolizer" + + _ "github.com/ianlancetaylor/cgosymbolizer" + ``` 7. Загрузите модуль: `go get`. 8. В контейнере используйте GDB и другие инструменты: - ```console - go test -tags watcher -c -ldflags=-w - gdb --args frankenphp.test -test.run ^MyTest$ - ``` + ```console + go test -tags watcher -c -ldflags=-w + gdb --args frankenphp.test -test.run ^MyTest$ + ``` 9. После исправления ошибки откатите все внесенные изменения. ## Дополнительные ресурсы для разработки -* [Встраивание PHP в uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) -* [Встраивание PHP в NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) -* [Встраивание PHP в Go (go-php)](https://github.com/deuill/go-php) -* [Встраивание PHP в Go (GoEmPHP)](https://github.com/mikespook/goemphp) -* [Встраивание PHP в C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) -* [Книга "Extending and Embedding PHP" Сары Големан](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) -* [Статья: Что такое TSRMLS_CC?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) -* [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) +- [Встраивание PHP в uWSGI](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) +- [Встраивание PHP в NGINX Unit](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) +- [Встраивание PHP в Go (go-php)](https://github.com/deuill/go-php) +- [Встраивание PHP в Go (GoEmPHP)](https://github.com/mikespook/goemphp) +- [Встраивание PHP в C++](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) +- [Книга "Extending and Embedding PHP" Сары Големан](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) +- [Статья: Что такое TSRMLS_CC?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) +- [SDL bindings](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) ## Docker-ресурсы -* [Определение файлов bake](https://docs.docker.com/build/customize/bake/file-definition/) -* [Документация по команде `docker buildx build`](https://docs.docker.com/engine/reference/commandline/buildx_build/) +- [Определение файлов bake](https://docs.docker.com/build/customize/bake/file-definition/) +- [Документация по команде `docker buildx build`](https://docs.docker.com/engine/reference/commandline/buildx_build/) ## Полезные команды diff --git a/docs/ru/README.md b/docs/ru/README.md index e5b868be84..0e2556767d 100644 --- a/docs/ru/README.md +++ b/docs/ru/README.md @@ -4,13 +4,13 @@ **FrankenPHP** — это современный сервер приложений для PHP, построенный на базе веб-сервера [Caddy](https://caddyserver.com/). -FrankenPHP добавляет новые возможности вашим PHP-приложениям благодаря следующим функциям: [*Early Hints*](https://frankenphp.dev/docs/early-hints/), [Worker режим](https://frankenphp.dev/docs/worker/), [Real-time режим](https://frankenphp.dev/docs/mercure/), автоматическая поддержка HTTPS, HTTP/2 и HTTP/3. +FrankenPHP добавляет новые возможности вашим PHP-приложениям благодаря следующим функциям: [_Early Hints_](https://frankenphp.dev/docs/early-hints/), [Worker режим](https://frankenphp.dev/docs/worker/), [Real-time режим](https://frankenphp.dev/docs/mercure/), автоматическая поддержка HTTPS, HTTP/2 и HTTP/3. FrankenPHP совместим с любыми PHP-приложениями и значительно ускоряет ваши проекты на Laravel и Symfony благодаря их официальной поддержке в worker режиме. FrankenPHP также может использоваться как автономная Go-библиотека для встраивания PHP в любое приложение с использованием `net/http`. -[**Узнайте больше** на сайте *frankenphp.dev*](https://frankenphp.dev) или из этой презентации: +[**Узнайте больше** на сайте _frankenphp.dev_](https://frankenphp.dev) или из этой презентации: Slides @@ -58,29 +58,29 @@ frankenphp php-cli /path/to/your/script.php ## Документация -* [Worker режим](https://frankenphp.dev/docs/worker/) -* [Поддержка Early Hints (103 HTTP статус код)](https://frankenphp.dev/docs/early-hints/) -* [Real-time режим](https://frankenphp.dev/docs/mercure/) -* [Конфигурация](https://frankenphp.dev/docs/config/) -* [Docker-образы](https://frankenphp.dev/docs/docker/) -* [Деплой в продакшен](https://frankenphp.dev/docs/production/) -* [Оптимизация производительности](https://frankenphp.dev/docs/performance/) -* [Создание автономного PHP-приложений](https://frankenphp.dev/docs/embed/) -* [Создание статических бинарных файлов](https://frankenphp.dev/docs/static/) -* [Компиляция из исходников](https://frankenphp.dev/docs/compile/) -* [Интеграция с Laravel](https://frankenphp.dev/docs/laravel/) -* [Известные проблемы](https://frankenphp.dev/docs/known-issues/) -* [Демо-приложение (Symfony) и бенчмарки](https://github.com/dunglas/frankenphp-demo) -* [Документация Go-библиотеки](https://pkg.go.dev/github.com/dunglas/frankenphp) -* [Участие в проекте и отладка](https://frankenphp.dev/docs/contributing/) +- [Worker режим](https://frankenphp.dev/docs/worker/) +- [Поддержка Early Hints (103 HTTP статус код)](https://frankenphp.dev/docs/early-hints/) +- [Real-time режим](https://frankenphp.dev/docs/mercure/) +- [Конфигурация](https://frankenphp.dev/docs/config/) +- [Docker-образы](https://frankenphp.dev/docs/docker/) +- [Деплой в продакшен](https://frankenphp.dev/docs/production/) +- [Оптимизация производительности](https://frankenphp.dev/docs/performance/) +- [Создание автономного PHP-приложений](https://frankenphp.dev/docs/embed/) +- [Создание статических бинарных файлов](https://frankenphp.dev/docs/static/) +- [Компиляция из исходников](https://frankenphp.dev/docs/compile/) +- [Интеграция с Laravel](https://frankenphp.dev/docs/laravel/) +- [Известные проблемы](https://frankenphp.dev/docs/known-issues/) +- [Демо-приложение (Symfony) и бенчмарки](https://github.com/dunglas/frankenphp-demo) +- [Документация Go-библиотеки](https://pkg.go.dev/github.com/dunglas/frankenphp) +- [Участие в проекте и отладка](https://frankenphp.dev/docs/contributing/) ## Примеры и шаблоны -* [Symfony](https://github.com/dunglas/symfony-docker) -* [API Platform](https://api-platform.com/docs/symfony) -* [Laravel](https://frankenphp.dev/docs/laravel/) -* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) -* [WordPress](https://github.com/StephenMiracle/frankenwp) -* [Drupal](https://github.com/dunglas/frankenphp-drupal) -* [Joomla](https://github.com/alexandreelise/frankenphp-joomla) -* [TYPO3](https://github.com/ochorocho/franken-typo3) +- [Symfony](https://github.com/dunglas/symfony-docker) +- [API Platform](https://api-platform.com/docs/symfony) +- [Laravel](https://frankenphp.dev/docs/laravel/) +- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) +- [WordPress](https://github.com/StephenMiracle/frankenwp) +- [Drupal](https://github.com/dunglas/frankenphp-drupal) +- [Joomla](https://github.com/alexandreelise/frankenphp-joomla) +- [TYPO3](https://github.com/ochorocho/franken-typo3) diff --git a/docs/ru/compile.md b/docs/ru/compile.md index 7c19751628..e547be21ab 100644 --- a/docs/ru/compile.md +++ b/docs/ru/compile.md @@ -1,7 +1,7 @@ # Компиляция из исходников Этот документ объясняет, как создать бинарный файл FrankenPHP, который будет загружать PHP как динамическую библиотеку. -Это рекомендуемый способ. +Это рекомендуемый способ. Альтернативно можно создать [статическую сборку](static.md). @@ -67,7 +67,7 @@ sudo make install Альтернативно, эти функции можно отключить, передав соответствующие теги сборки компилятору Go. | Функция | Зависимость | Тег сборки для отключения | -|-------------------------------------------------|-----------------------------------------------------------------------|---------------------------| +| ----------------------------------------------- | --------------------------------------------------------------------- | ------------------------- | | Сжатие Brotli | [Brotli](https://github.com/google/brotli) | nobrotli | | Перезапуск worker-скриптов при изменении файлов | [Watcher C](https://github.com/e-dant/watcher/tree/release/watcher-c) | nowatcher | diff --git a/docs/ru/config.md b/docs/ru/config.md index 941406501f..ebc62a5bee 100644 --- a/docs/ru/config.md +++ b/docs/ru/config.md @@ -169,10 +169,10 @@ php_server [] { } ``` -* Шаблон `**` указывает на рекурсивное отслеживание. -* Директории могут быть указаны относительно директории запуска FrankenPHP. -* Если у вас определено несколько workers, все они будут перезапущены при изменении файлов. -* Избегайте отслеживания файлов, создаваемых во время выполнения (например, логов), так как это может вызвать нежелательные перезапуски. +- Шаблон `**` указывает на рекурсивное отслеживание. +- Директории могут быть указаны относительно директории запуска FrankenPHP. +- Если у вас определено несколько workers, все они будут перезапущены при изменении файлов. +- Избегайте отслеживания файлов, создаваемых во время выполнения (например, логов), так как это может вызвать нежелательные перезапуски. Механизм отслеживания файлов основан на [e-dant/watcher](https://github.com/e-dant/watcher). @@ -207,9 +207,9 @@ CADDY_GLOBAL_OPTIONS="servers { Следующие переменные окружения могут быть использованы для добавления директив в `Caddyfile` без его изменения: -* `SERVER_NAME`: изменение [адресов для прослушивания](https://caddyserver.com/docs/caddyfile/concepts#addresses); предоставленные хостнеймы также будут использованы для генерации TLS-сертификата. -* `CADDY_GLOBAL_OPTIONS`: добавление [глобальных опций](https://caddyserver.com/docs/caddyfile/options). -* `FRANKENPHP_CONFIG`: добавление конфигурации в директиву `frankenphp`. +- `SERVER_NAME`: изменение [адресов для прослушивания](https://caddyserver.com/docs/caddyfile/concepts#addresses); предоставленные хостнеймы также будут использованы для генерации TLS-сертификата. +- `CADDY_GLOBAL_OPTIONS`: добавление [глобальных опций](https://caddyserver.com/docs/caddyfile/options). +- `FRANKENPHP_CONFIG`: добавление конфигурации в директиву `frankenphp`. Как и для FPM и CLI SAPIs, переменные окружения по умолчанию доступны в суперглобальной переменной `$_SERVER`. diff --git a/docs/ru/docker.md b/docs/ru/docker.md index dcf0fa46e9..f1a0a00e4a 100644 --- a/docs/ru/docker.md +++ b/docs/ru/docker.md @@ -6,8 +6,8 @@ Теги следуют следующему шаблону: `dunglas/frankenphp:-php-`. -* `` и `` — версии FrankenPHP и PHP соответственно: от основных (например, `1`) до минорных (например, `1.2`) и патч-версий (например, `1.2.3`). -* `` может быть `bookworm` (для Debian Bookworm) или `alpine` (для последней стабильной версии Alpine). +- `` и `` — версии FrankenPHP и PHP соответственно: от основных (например, `1`) до минорных (например, `1.2`) и патч-версий (например, `1.2.3`). +- `` может быть `bookworm` (для Debian Bookworm) или `alpine` (для последней стабильной версии Alpine). [Просмотреть доступные теги](https://hub.docker.com/r/dunglas/frankenphp/tags). @@ -189,8 +189,8 @@ USER ${USER} Docker-образы обновляются: -* при выпуске новой версии; -* ежедневно в 4 утра UTC, если доступны новые версии официальных PHP-образов. +- при выпуске новой версии; +- ежедневно в 4 утра UTC, если доступны новые версии официальных PHP-образов. ## Версии для разработки diff --git a/docs/ru/embed.md b/docs/ru/embed.md index e24a7db783..2c60921835 100644 --- a/docs/ru/embed.md +++ b/docs/ru/embed.md @@ -51,34 +51,34 @@ composer dump-env prod 1. Создайте файл `static-build.Dockerfile` в репозитории вашего приложения: - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Скопировать приложение - WORKDIR /go/src/app/dist/app - COPY . . + # Скопировать приложение + WORKDIR /go/src/app/dist/app + COPY . . - # Сборка статического бинарного файла - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Сборка статического бинарного файла + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` - > [!CAUTION] - > - > Некоторые `.dockerignore` файлы (например, [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) - > игнорируют директорию `vendor/` и файлы `.env`. Перед сборкой убедитесь, что `.dockerignore` файл настроен корректно или удалён. + > [!CAUTION] + > + > Некоторые `.dockerignore` файлы (например, [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > игнорируют директорию `vendor/` и файлы `.env`. Перед сборкой убедитесь, что `.dockerignore` файл настроен корректно или удалён. 2. Соберите образ: - ```console - docker build -t static-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-app -f static-build.Dockerfile . + ``` 3. Извлеките бинарный файл: - ```console - docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp - ``` + ```console + docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp + ``` Созданный бинарный файл сохранится в текущей директории под именем `my-app`. diff --git a/docs/ru/known-issues.md b/docs/ru/known-issues.md index af92ba4b7c..eb9f62d33c 100644 --- a/docs/ru/known-issues.md +++ b/docs/ru/known-issues.md @@ -4,18 +4,18 @@ Следующие расширения не совместимы с FrankenPHP: -| Название | Причина | Альтернативы | -|-------------------------------------------------------------------------------------------------------------|-------------------|-----------------------------------------------------------------------------------------------------------------------| +| Название | Причина | Альтернативы | +| ----------------------------------------------------------------------------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | [imap](https://www.php.net/manual/en/imap.installation.php) | Не поддерживает потокобезопасность | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) | -| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Не поддерживает потокобезопасность | - | +| [newrelic](https://docs.newrelic.com/docs/apm/agents/php-agent/getting-started/introduction-new-relic-php/) | Не поддерживает потокобезопасность | - | ## Проблемные расширения PHP Следующие расширения имеют известные ошибки или могут вести себя непредсказуемо при использовании с FrankenPHP: -| Название | Проблема | -|-------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | При использовании статической сборки FrankenPHP (на базе musl libc) расширение OpenSSL может аварийно завершаться при высокой нагрузке. Решение — использовать динамически связанную сборку (например, ту, что используется в Docker-образах). Ошибка [отслеживается сообществом PHP](https://github.com/php/php-src/issues/13648). | +| Название | Проблема | +| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [ext-openssl](https://www.php.net/manual/en/book.openssl.php) | При использовании статической сборки FrankenPHP (на базе musl libc) расширение OpenSSL может аварийно завершаться при высокой нагрузке. Решение — использовать динамически связанную сборку (например, ту, что используется в Docker-образах). Ошибка [отслеживается сообществом PHP](https://github.com/php/php-src/issues/13648). | ## `get_browser` @@ -79,8 +79,8 @@ docker run \ [Скрипты Composer](https://getcomposer.org/doc/articles/scripts.md) могут вызывать PHP для выполнения задач, например, в [проекте Laravel](laravel.md) для команды `@php artisan package:discover --ansi`. Это [на данный момент не поддерживается](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) по двум причинам: -* Composer не знает, как вызывать бинарный файл FrankenPHP; -* Composer может добавлять настройки PHP через флаг `-d`, который FrankenPHP пока не поддерживает. +- Composer не знает, как вызывать бинарный файл FrankenPHP; +- Composer может добавлять настройки PHP через флаг `-d`, который FrankenPHP пока не поддерживает. Решение — создать shell-скрипт в `/usr/local/bin/php`, который удаляет неподдерживаемые параметры и вызывает FrankenPHP: diff --git a/docs/ru/laravel.md b/docs/ru/laravel.md index 4dda990fa8..bb8411c9be 100644 --- a/docs/ru/laravel.md +++ b/docs/ru/laravel.md @@ -19,21 +19,21 @@ docker run -p 80:80 -p 443:443 -p 443:443/udp -v $PWD:/app dunglas/frankenphp 1. [Скачайте бинарный файл для вашей системы](README.md#автономный-бинарный-файл) 2. Добавьте следующую конфигурацию в файл с именем `Caddyfile` в корневой директории вашего Laravel-проекта: - ```caddyfile - { - frankenphp - } - - # Доменное имя вашего сервера - localhost { - # Укажите веб-корень как директорию public/ - root public/ - # Включите сжатие (опционально) - encode zstd br gzip - # Выполняйте PHP-файлы из директории public/ и обслуживайте статические файлы - php_server - } - ``` + ```caddyfile + { + frankenphp + } + + # Доменное имя вашего сервера + localhost { + # Укажите веб-корень как директорию public/ + root public/ + # Включите сжатие (опционально) + encode zstd br gzip + # Выполняйте PHP-файлы из директории public/ и обслуживайте статические файлы + php_server + } + ``` 3. Запустите FrankenPHP из корневой директории вашего Laravel-проекта: `frankenphp run` @@ -59,17 +59,17 @@ php artisan octane:frankenphp Команда `octane:frankenphp` поддерживает следующие опции: -* `--host`: IP-адрес, к которому должен привязаться сервер (по умолчанию: `127.0.0.1`) -* `--port`: Порт, на котором сервер будет доступен (по умолчанию: `8000`) -* `--admin-port`: Порт, на котором будет доступен административный сервер (по умолчанию: `2019`) -* `--workers`: Количество worker-скриптов для обработки запросов (по умолчанию: `auto`) -* `--max-requests`: Количество запросов, обрабатываемых перед перезагрузкой сервера (по умолчанию: `500`) -* `--caddyfile`: Путь к файлу `Caddyfile` FrankenPHP (по умолчанию: [stubbed `Caddyfile` в Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile)) -* `--https`: Включить HTTPS, HTTP/2 и HTTP/3, а также автоматически генерировать и обновлять сертификаты -* `--http-redirect`: Включить редирект с HTTP на HTTPS (включается только при передаче --https) -* `--watch`: Автоматически перезагружать сервер при изменении приложения -* `--poll`: Использовать опрос файловой системы для отслеживания изменений в файлах через сеть -* `--log-level`: Установить уровень логирования, используя встроенный логгер Caddy +- `--host`: IP-адрес, к которому должен привязаться сервер (по умолчанию: `127.0.0.1`) +- `--port`: Порт, на котором сервер будет доступен (по умолчанию: `8000`) +- `--admin-port`: Порт, на котором будет доступен административный сервер (по умолчанию: `2019`) +- `--workers`: Количество worker-скриптов для обработки запросов (по умолчанию: `auto`) +- `--max-requests`: Количество запросов, обрабатываемых перед перезагрузкой сервера (по умолчанию: `500`) +- `--caddyfile`: Путь к файлу `Caddyfile` FrankenPHP (по умолчанию: [stubbed `Caddyfile` в Laravel Octane](https://github.com/laravel/octane/blob/2.x/src/Commands/stubs/Caddyfile)) +- `--https`: Включить HTTPS, HTTP/2 и HTTP/3, а также автоматически генерировать и обновлять сертификаты +- `--http-redirect`: Включить редирект с HTTP на HTTPS (включается только при передаче --https) +- `--watch`: Автоматически перезагружать сервер при изменении приложения +- `--poll`: Использовать опрос файловой системы для отслеживания изменений в файлах через сеть +- `--log-level`: Установить уровень логирования, используя встроенный логгер Caddy > [!TIP] > Чтобы получить структурированные JSON-логи (полезно при использовании решений для анализа логов), явно укажите опцию `--log-level`. @@ -84,71 +84,71 @@ php artisan octane:frankenphp 1. Создайте файл с именем `static-build.Dockerfile` в репозитории вашего приложения: - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - # Скопируйте ваше приложение - WORKDIR /go/src/app/dist/app - COPY . . + # Скопируйте ваше приложение + WORKDIR /go/src/app/dist/app + COPY . . - # Удалите тесты и другие ненужные файлы, чтобы сэкономить место - # В качестве альтернативы добавьте эти файлы в .dockerignore - RUN rm -Rf tests/ + # Удалите тесты и другие ненужные файлы, чтобы сэкономить место + # В качестве альтернативы добавьте эти файлы в .dockerignore + RUN rm -Rf tests/ - # Скопируйте файл .env - RUN cp .env.example .env - # Измените APP_ENV и APP_DEBUG для продакшна - RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env + # Скопируйте файл .env + RUN cp .env.example .env + # Измените APP_ENV и APP_DEBUG для продакшна + RUN sed -i'' -e 's/^APP_ENV=.*/APP_ENV=production/' -e 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env - # Внесите другие изменения в файл .env, если необходимо + # Внесите другие изменения в файл .env, если необходимо - # Установите зависимости - RUN composer install --ignore-platform-reqs --no-dev -a + # Установите зависимости + RUN composer install --ignore-platform-reqs --no-dev -a - # Соберите статический бинарный файл - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ ./build-static.sh - ``` + # Соберите статический бинарный файл + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ ./build-static.sh + ``` - > [!CAUTION] - > - > Некоторые `.dockerignore` файлы могут игнорировать директорию `vendor/` и файлы `.env`. Убедитесь, что вы скорректировали или удалили `.dockerignore` перед сборкой. + > [!CAUTION] + > + > Некоторые `.dockerignore` файлы могут игнорировать директорию `vendor/` и файлы `.env`. Убедитесь, что вы скорректировали или удалили `.dockerignore` перед сборкой. 2. Соберите: - ```console - docker build -t static-laravel-app -f static-build.Dockerfile . - ``` + ```console + docker build -t static-laravel-app -f static-build.Dockerfile . + ``` 3. Извлеките бинарный файл: - ```console - docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp - ``` + ```console + docker cp $(docker create --name static-laravel-app-tmp static-laravel-app):/go/src/app/dist/frankenphp-linux-x86_64 frankenphp ; docker rm static-laravel-app-tmp + ``` 4. Заполните кеши: - ```console - frankenphp php-cli artisan optimize - ``` + ```console + frankenphp php-cli artisan optimize + ``` 5. Запустите миграции базы данных (если есть): - ```console - frankenphp php-cli artisan migrate - ``` + ```console + frankenphp php-cli artisan migrate + ``` 6. Сгенерируйте секретный ключ приложения: - ```console - frankenphp php-cli artisan key:generate - ``` + ```console + frankenphp php-cli artisan key:generate + ``` 7. Запустите сервер: - ```console - frankenphp php-server - ``` + ```console + frankenphp php-server + ``` Ваше приложение готово! diff --git a/docs/ru/production.md b/docs/ru/production.md index 529b4a142a..e438b56410 100644 --- a/docs/ru/production.md +++ b/docs/ru/production.md @@ -55,7 +55,7 @@ volumes: > [!NOTE] > > Примеры выше предназначены для использования в продакшне. -> В процессе разработки вы можете использовать том для монтирования, другую конфигурацию PHP и другое значение для переменной окружения `SERVER_NAME`. +> В процессе разработки вы можете использовать том для монтирования, другую конфигурацию PHP и другое значение для переменной окружения `SERVER_NAME`. > > Посмотрите проект [Symfony Docker](https://github.com/dunglas/symfony-docker) (который использует FrankenPHP) для более сложного примера с использованием мультистейдж-образов, Composer, дополнительных PHP-расширений и т.д. diff --git a/docs/ru/static.md b/docs/ru/static.md index a898c40d68..53169c4fb6 100644 --- a/docs/ru/static.md +++ b/docs/ru/static.md @@ -87,14 +87,14 @@ cd frankenphp Следующие переменные окружения можно передать в `docker build` и скрипт `build-static.sh`, чтобы настроить статическую сборку: -* `FRANKENPHP_VERSION`: версия FrankenPHP -* `PHP_VERSION`: версия PHP -* `PHP_EXTENSIONS`: PHP-расширения для сборки ([список поддерживаемых расширений](https://static-php.dev/en/guide/extensions.html)) -* `PHP_EXTENSION_LIBS`: дополнительные библиотеки, добавляющие функциональность расширениям -* `XCADDY_ARGS`: аргументы для [xcaddy](https://github.com/caddyserver/xcaddy), например, для добавления модулей Caddy -* `EMBED`: путь к PHP-приложению для встраивания в бинарник -* `CLEAN`: если задано, libphp и все его зависимости будут пересобраны с нуля (без кэша) -* `NO_COMPRESS`: отключает сжатие результирующего бинарника с помощью UPX -* `DEBUG_SYMBOLS`: если задано, отладочные символы не будут удалены и будут добавлены в бинарник -* `MIMALLOC`: (экспериментально, только для Linux) заменяет musl's mallocng на [mimalloc](https://github.com/microsoft/mimalloc) для повышения производительности -* `RELEASE`: (только для мейнтейнеров) если задано, бинарник будет загружен на GitHub +- `FRANKENPHP_VERSION`: версия FrankenPHP +- `PHP_VERSION`: версия PHP +- `PHP_EXTENSIONS`: PHP-расширения для сборки ([список поддерживаемых расширений](https://static-php.dev/en/guide/extensions.html)) +- `PHP_EXTENSION_LIBS`: дополнительные библиотеки, добавляющие функциональность расширениям +- `XCADDY_ARGS`: аргументы для [xcaddy](https://github.com/caddyserver/xcaddy), например, для добавления модулей Caddy +- `EMBED`: путь к PHP-приложению для встраивания в бинарник +- `CLEAN`: если задано, libphp и все его зависимости будут пересобраны с нуля (без кэша) +- `NO_COMPRESS`: отключает сжатие результирующего бинарника с помощью UPX +- `DEBUG_SYMBOLS`: если задано, отладочные символы не будут удалены и будут добавлены в бинарник +- `MIMALLOC`: (экспериментально, только для Linux) заменяет musl's mallocng на [mimalloc](https://github.com/microsoft/mimalloc) для повышения производительности +- `RELEASE`: (только для мейнтейнеров) если задано, бинарник будет загружен на GitHub diff --git a/docs/ru/worker.md b/docs/ru/worker.md index e94a540ca9..e0a727c821 100644 --- a/docs/ru/worker.md +++ b/docs/ru/worker.md @@ -126,22 +126,22 @@ docker run \ ### Перезапуск worker-скрипта после определённого количества запросов PHP изначально не предназначался для долгоживущих процессов, поэтому некоторые библиотеки и устаревший код могут приводить к утечкам памяти. -Для этого можно настроить автоматический перезапуск worker-скрипта после обработки определённого количества запросов. +Для этого можно настроить автоматический перезапуск worker-скрипта после обработки определённого количества запросов. В предыдущем примере максимальное количество запросов задаётся с помощью переменной окружения `MAX_REQUESTS`. ### Сбои worker-скрипта Если worker-скрипт завершится с ненулевым кодом выхода, FrankenPHP перезапустит его с использованием экспоненциальной задержки. -Если worker-скрипт проработает дольше, чем время последней задержки * 2, он будет считаться стабильным, и задержка сбросится. +Если worker-скрипт проработает дольше, чем время последней задержки \* 2, он будет считаться стабильным, и задержка сбросится. Однако, если worker-скрипт продолжает завершаться с ненулевым кодом выхода в течение короткого промежутка времени (например, из-за опечатки в коде), FrankenPHP завершит работу с ошибкой: `too many consecutive failures`. ## Поведение суперглобальных переменных [PHP суперглобальные переменные](https://www.php.net/manual/en/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET` и т.д.) ведут себя следующим образом: -* до первого вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, связанные с самим worker-скриптом -* во время и после вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, сгенерированные на основе обработанного HTTP-запроса, каждый вызов изменяет значения суперглобальных переменных +- до первого вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, связанные с самим worker-скриптом +- во время и после вызова `frankenphp_handle_request()` суперглобальные переменные содержат значения, сгенерированные на основе обработанного HTTP-запроса, каждый вызов изменяет значения суперглобальных переменных Чтобы получить доступ к суперглобальным переменным worker-скрипта внутри колбэка, необходимо скопировать их и импортировать копию в область видимости колбэка: diff --git a/docs/static.md b/docs/static.md index 781edaecb7..dd11f36cb0 100644 --- a/docs/static.md +++ b/docs/static.md @@ -117,17 +117,17 @@ Note: this script also works on Linux (and probably on other Unixes), and is use The following environment variables can be passed to `docker build` and to the `build-static.sh` script to customize the static build: -* `FRANKENPHP_VERSION`: the version of FrankenPHP to use -* `PHP_VERSION`: the version of PHP to use -* `PHP_EXTENSIONS`: the PHP extensions to build ([list of supported extensions](https://static-php.dev/en/guide/extensions.html)) -* `PHP_EXTENSION_LIBS`: extra libraries to build that add features to the extensions -* `XCADDY_ARGS`: arguments to pass to [xcaddy](https://github.com/caddyserver/xcaddy), for instance to add extra Caddy modules -* `EMBED`: path of the PHP application to embed in the binary -* `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache) -* `NO_COMPRESS`: don't compress the resulting binary using UPX -* `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added to the binary -* `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance. We only recommend using this for musl targeting builds, for glibc prefer disabling this option and using [`LD_PRELOAD`](https://microsoft.github.io/mimalloc/overrides.html) when you run your binary instead. -* `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub +- `FRANKENPHP_VERSION`: the version of FrankenPHP to use +- `PHP_VERSION`: the version of PHP to use +- `PHP_EXTENSIONS`: the PHP extensions to build ([list of supported extensions](https://static-php.dev/en/guide/extensions.html)) +- `PHP_EXTENSION_LIBS`: extra libraries to build that add features to the extensions +- `XCADDY_ARGS`: arguments to pass to [xcaddy](https://github.com/caddyserver/xcaddy), for instance to add extra Caddy modules +- `EMBED`: path of the PHP application to embed in the binary +- `CLEAN`: when set, libphp and all its dependencies are built from scratch (no cache) +- `NO_COMPRESS`: don't compress the resulting binary using UPX +- `DEBUG_SYMBOLS`: when set, debug-symbols will not be stripped and will be added to the binary +- `MIMALLOC`: (experimental, Linux-only) replace musl's mallocng by [mimalloc](https://github.com/microsoft/mimalloc) for improved performance. We only recommend using this for musl targeting builds, for glibc prefer disabling this option and using [`LD_PRELOAD`](https://microsoft.github.io/mimalloc/overrides.html) when you run your binary instead. +- `RELEASE`: (maintainers only) when set, the resulting binary will be uploaded on GitHub ## Extensions diff --git a/docs/tr/CONTRIBUTING.md b/docs/tr/CONTRIBUTING.md index 8962548d11..fa4b76f93a 100644 --- a/docs/tr/CONTRIBUTING.md +++ b/docs/tr/CONTRIBUTING.md @@ -1,202 +1,202 @@ -# Katkıda Bulunmak - -## PHP Derleme - -### Docker ile (Linux) - -Geliştirme Ortamı için Docker İmajını Oluşturun: - -```console -docker build -t frankenphp-dev -f dev.Dockerfile . -docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev -``` - -İmaj genel geliştirme araçlarını (Go, GDB, Valgrind, Neovim...) içerir. - -Docker sürümü 23.0'dan düşükse, derleme dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) tarafından başarısız olur. Dizinleri `.dockerignore` dosyasına ekleyin. - -```patch - !testdata/*.php - !testdata/*.txt -+!caddy -+!internal -``` - -### Docker olmadan (Linux ve macOS) - -[Kaynaklardan derlemek için talimatları izleyin](https://frankenphp.dev/docs/compile/) ve `--debug` yapılandırma seçeneğini geçirin. - -## Test senaryolarını çalıştırma - -```console -go test -tags watcher -race -v ./... -``` - -## Caddy modülü - -FrankenPHP Caddy modülü ile Caddy'yi oluşturun: - -```console -cd caddy/frankenphp/ -go build -cd ../../ -``` - -Caddy'yi FrankenPHP Caddy modülü ile çalıştırın: - -```console -cd testdata/ -../caddy/frankenphp/frankenphp run -``` - -Sunucu `127.0.0.1:8080` adresini dinliyor: - -```console -curl -vk https://localhost/phpinfo.php -``` - -## Minimal test sunucusu - -Minimal test sunucusunu oluşturun: - -```console -cd internal/testserver/ -go build -cd ../../ -``` - -Test sunucusunu çalıştırın: - -```console -cd testdata/ -../internal/testserver/testserver -``` - -Sunucu `127.0.0.1:8080` adresini dinliyor: - -```console -curl -v http://127.0.0.1:8080/phpinfo.php -``` - -## Docker İmajlarını Yerel Olarak Oluşturma - -Bake (pişirme) planını yazdırın: - -```console -docker buildx bake -f docker-bake.hcl --print -``` - -Yerel olarak amd64 için FrankenPHP görüntüleri oluşturun: - -```console -docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64" -``` - -Yerel olarak arm64 için FrankenPHP görüntüleri oluşturun: - -```console -docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64" -``` - -FrankenPHP imajlarını arm64 ve amd64 için sıfırdan oluşturun ve Docker Hub'a gönderin: - -```console -docker buildx bake -f docker-bake.hcl --pull --no-cache --push -``` - -## Statik Derlemelerle Segmentasyon Hatalarında Hata Ayıklama - -1. FrankenPHP binary dosyasının hata ayıklama sürümünü GitHub'dan indirin veya hata ayıklama seçeneklerini kullanarak özel statik derlemenizi oluşturun: - - ```console - docker buildx bake \ - --load \ - --set static-builder.args.DEBUG_SYMBOLS=1 \ - --set "static-builder.platform=linux/amd64" \ - static-builder - docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp - ``` - -2. Mevcut `frankenphp` sürümünüzü hata ayıklama FrankenPHP çalıştırılabilir dosyasıyla değiştirin -3. FrankenPHP'yi her zamanki gibi başlatın (alternatif olarak FrankenPHP'yi doğrudan GDB ile başlatabilirsiniz: `gdb --args frankenphp run`) -4. GDB ile sürece bağlanın: - - ```console - gdb -p `pidof frankenphp` - ``` - -5. Gerekirse, GDB kabuğuna `continue` yazın -6. FrankenPHP'nin çökmesini sağlayın -7. GDB kabuğuna `bt` yazın -8. Çıktıyı kopyalayın - -## GitHub Eylemlerinde Segmentasyon Hatalarında Hata Ayıklama - -1. `.github/workflows/tests.yml` dosyasını açın -2. PHP hata ayıklama seçeneklerini etkinleştirin - - ```patch - - uses: shivammathur/setup-php@v2 - # ... - env: - phpts: ts - + debug: true - ``` - -3. Konteynere bağlanmak için `tmate`i etkinleştirin - - ```patch - - - name: Set CGO flags - run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" - + - - + run: | - + sudo apt install gdb - + mkdir -p /home/runner/.config/gdb/ - + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit - + - - + uses: mxschmitt/action-tmate@v3 - ``` - -4. Konteynere bağlanın -5. `frankenphp.go` dosyasını açın -6. `cgosymbolizer`'ı etkinleştirin - - ```patch - - //_ "github.com/ianlancetaylor/cgosymbolizer" - + _ "github.com/ianlancetaylor/cgosymbolizer" - ``` - -7. Modülü indirin: `go get` -8. Konteynerde GDB ve benzerlerini kullanabilirsiniz: - - ```console - go test -tags watcher -c -ldflags=-w - gdb --args frankenphp.test -test.run ^MyTest$ - ``` - -9. Hata düzeltildiğinde, tüm bu değişiklikleri geri alın - -## Misc Dev Resources - -* [uWSGI içine PHP gömme](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) -* [NGINX Unit'te PHP gömme](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) -* [Go (go-php) içinde PHP gömme](https://github.com/deuill/go-php) -* [Go'da PHP gömme (GoEmPHP)](https://github.com/mikespook/goemphp) -* [C++'da PHP gömme](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) -* [Sara Golemon tarafından PHP'yi Genişletme ve Yerleştirme](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) -* [TSRMLS_CC de neyin nesi?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) -* [Mac'te PHP gömme](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4) -* [SDL bağları](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) - -## Docker ile İlgili Kaynaklar - -* [Pişirme (bake) dosya tanımı](https://docs.docker.com/build/customize/bake/file-definition/) -* [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) - -## Faydalı Komut - -```console -apk add strace util-linux gdb -strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1 -``` +# Katkıda Bulunmak + +## PHP Derleme + +### Docker ile (Linux) + +Geliştirme Ortamı için Docker İmajını Oluşturun: + +```console +docker build -t frankenphp-dev -f dev.Dockerfile . +docker run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -p 8080:8080 -p 443:443 -p 443:443/udp -v $PWD:/go/src/app -it frankenphp-dev +``` + +İmaj genel geliştirme araçlarını (Go, GDB, Valgrind, Neovim...) içerir. + +Docker sürümü 23.0'dan düşükse, derleme dockerignore [pattern issue](https://github.com/moby/moby/pull/42676) tarafından başarısız olur. Dizinleri `.dockerignore` dosyasına ekleyin. + +```patch + !testdata/*.php + !testdata/*.txt ++!caddy ++!internal +``` + +### Docker olmadan (Linux ve macOS) + +[Kaynaklardan derlemek için talimatları izleyin](https://frankenphp.dev/docs/compile/) ve `--debug` yapılandırma seçeneğini geçirin. + +## Test senaryolarını çalıştırma + +```console +go test -tags watcher -race -v ./... +``` + +## Caddy modülü + +FrankenPHP Caddy modülü ile Caddy'yi oluşturun: + +```console +cd caddy/frankenphp/ +go build +cd ../../ +``` + +Caddy'yi FrankenPHP Caddy modülü ile çalıştırın: + +```console +cd testdata/ +../caddy/frankenphp/frankenphp run +``` + +Sunucu `127.0.0.1:8080` adresini dinliyor: + +```console +curl -vk https://localhost/phpinfo.php +``` + +## Minimal test sunucusu + +Minimal test sunucusunu oluşturun: + +```console +cd internal/testserver/ +go build +cd ../../ +``` + +Test sunucusunu çalıştırın: + +```console +cd testdata/ +../internal/testserver/testserver +``` + +Sunucu `127.0.0.1:8080` adresini dinliyor: + +```console +curl -v http://127.0.0.1:8080/phpinfo.php +``` + +## Docker İmajlarını Yerel Olarak Oluşturma + +Bake (pişirme) planını yazdırın: + +```console +docker buildx bake -f docker-bake.hcl --print +``` + +Yerel olarak amd64 için FrankenPHP görüntüleri oluşturun: + +```console +docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/amd64" +``` + +Yerel olarak arm64 için FrankenPHP görüntüleri oluşturun: + +```console +docker buildx bake -f docker-bake.hcl --pull --load --set "*.platform=linux/arm64" +``` + +FrankenPHP imajlarını arm64 ve amd64 için sıfırdan oluşturun ve Docker Hub'a gönderin: + +```console +docker buildx bake -f docker-bake.hcl --pull --no-cache --push +``` + +## Statik Derlemelerle Segmentasyon Hatalarında Hata Ayıklama + +1. FrankenPHP binary dosyasının hata ayıklama sürümünü GitHub'dan indirin veya hata ayıklama seçeneklerini kullanarak özel statik derlemenizi oluşturun: + + ```console + docker buildx bake \ + --load \ + --set static-builder.args.DEBUG_SYMBOLS=1 \ + --set "static-builder.platform=linux/amd64" \ + static-builder + docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp + ``` + +2. Mevcut `frankenphp` sürümünüzü hata ayıklama FrankenPHP çalıştırılabilir dosyasıyla değiştirin +3. FrankenPHP'yi her zamanki gibi başlatın (alternatif olarak FrankenPHP'yi doğrudan GDB ile başlatabilirsiniz: `gdb --args frankenphp run`) +4. GDB ile sürece bağlanın: + + ```console + gdb -p `pidof frankenphp` + ``` + +5. Gerekirse, GDB kabuğuna `continue` yazın +6. FrankenPHP'nin çökmesini sağlayın +7. GDB kabuğuna `bt` yazın +8. Çıktıyı kopyalayın + +## GitHub Eylemlerinde Segmentasyon Hatalarında Hata Ayıklama + +1. `.github/workflows/tests.yml` dosyasını açın +2. PHP hata ayıklama seçeneklerini etkinleştirin + + ```patch + - uses: shivammathur/setup-php@v2 + # ... + env: + phpts: ts + + debug: true + ``` + +3. Konteynere bağlanmak için `tmate`i etkinleştirin + + ```patch + - + name: Set CGO flags + run: echo "CGO_CFLAGS=$(php-config --includes)" >> "$GITHUB_ENV" + + - + + run: | + + sudo apt install gdb + + mkdir -p /home/runner/.config/gdb/ + + printf "set auto-load safe-path /\nhandle SIG34 nostop noprint pass" > /home/runner/.config/gdb/gdbinit + + - + + uses: mxschmitt/action-tmate@v3 + ``` + +4. Konteynere bağlanın +5. `frankenphp.go` dosyasını açın +6. `cgosymbolizer`'ı etkinleştirin + + ```patch + - //_ "github.com/ianlancetaylor/cgosymbolizer" + + _ "github.com/ianlancetaylor/cgosymbolizer" + ``` + +7. Modülü indirin: `go get` +8. Konteynerde GDB ve benzerlerini kullanabilirsiniz: + + ```console + go test -tags watcher -c -ldflags=-w + gdb --args frankenphp.test -test.run ^MyTest$ + ``` + +9. Hata düzeltildiğinde, tüm bu değişiklikleri geri alın + +## Misc Dev Resources + +- [uWSGI içine PHP gömme](https://github.com/unbit/uwsgi/blob/master/plugins/php/php_plugin.c) +- [NGINX Unit'te PHP gömme](https://github.com/nginx/unit/blob/master/src/nxt_php_sapi.c) +- [Go (go-php) içinde PHP gömme](https://github.com/deuill/go-php) +- [Go'da PHP gömme (GoEmPHP)](https://github.com/mikespook/goemphp) +- [C++'da PHP gömme](https://gist.github.com/paresy/3cbd4c6a469511ac7479aa0e7c42fea7) +- [Sara Golemon tarafından PHP'yi Genişletme ve Yerleştirme](https://books.google.fr/books?id=zMbGvK17_tYC&pg=PA254&lpg=PA254#v=onepage&q&f=false) +- [TSRMLS_CC de neyin nesi?](http://blog.golemon.com/2006/06/what-heck-is-tsrmlscc-anyway.html) +- [Mac'te PHP gömme](https://gist.github.com/jonnywang/61427ffc0e8dde74fff40f479d147db4) +- [SDL bağları](https://pkg.go.dev/github.com/veandco/go-sdl2@v0.4.21/sdl#Main) + +## Docker ile İlgili Kaynaklar + +- [Pişirme (bake) dosya tanımı](https://docs.docker.com/build/customize/bake/file-definition/) +- [docker buildx build](https://docs.docker.com/engine/reference/commandline/buildx_build/) + +## Faydalı Komut + +```console +apk add strace util-linux gdb +strace -e 'trace=!futex,epoll_ctl,epoll_pwait,tgkill,rt_sigreturn' -p 1 +``` diff --git a/docs/tr/README.md b/docs/tr/README.md index 27f2bc575a..324c00a0c0 100644 --- a/docs/tr/README.md +++ b/docs/tr/README.md @@ -1,78 +1,78 @@ -# FrankenPHP: PHP için Modern Uygulama Sunucusu - -

FrankenPHP

- -FrankenPHP, [Caddy](https://caddyserver.com/) web sunucusunun üzerine inşa edilmiş PHP için modern bir uygulama sunucusudur. - -FrankenPHP, çarpıcı özellikleri sayesinde PHP uygulamalarınıza süper güçler kazandırır: [Early Hints*](https://frankenphp.dev/docs/early-hints/), [worker modu](https://frankenphp.dev/docs/worker/), [real-time yetenekleri](https://frankenphp.dev/docs/mercure/), otomatik HTTPS, HTTP/2 ve HTTP/3 desteği... - -FrankenPHP herhangi bir PHP uygulaması ile çalışır ve worker modu ile resmi entegrasyonları sayesinde Laravel ve Symfony projelerinizi her zamankinden daha performanslı hale getirir. - -FrankenPHP, PHP'yi `net/http` kullanarak herhangi bir uygulamaya yerleştirmek için bağımsız bir Go kütüphanesi olarak da kullanılabilir. - -[*Frankenphp.dev*](https://frankenphp.dev) adresinden ve bu slayt üzerinden daha fazlasını öğrenin: - -Slides - -## Başlarken - -### Docker - -```console -docker run -v $PWD:/app/public \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -`https://localhost` adresine gidin ve keyfini çıkarın! - -> [!TIP] -> -> `https://127.0.0.1` kullanmaya çalışmayın. `https://localhost` kullanın ve kendinden imzalı sertifikayı kabul edin. -> Kullanılacak alan adını değiştirmek için [`SERVER_NAME` ortam değişkenini](https://frankenphp.dev/tr/docs/config#ortam-değişkenleri) kullanın. - -### Binary Çıktısı - -Docker kullanmayı tercih etmiyorsanız, Linux ve macOS için bağımsız FrankenPHP binary dosyası sağlıyoruz -[PHP 8.4](https://www.php.net/releases/8.4/en.php) ve en popüler PHP eklentilerini de içermekte: [FrankenPHP](https://github.com/dunglas/frankenphp/releases) indirin - -Geçerli dizinin içeriğini başlatmak için çalıştırın: - -```console -./frankenphp php-server -``` - -Ayrıca aşağıdaki tek komut satırı ile de çalıştırabilirsiniz: - -```console -./frankenphp php-cli /path/to/your/script.php -``` - -## Docs - -* [Worker modu](worker.md) -* [Early Hints desteği (103 HTTP durum kodu)](early-hints.md) -* [Real-time](mercure.md) -* [Konfigürasyon](config.md) -* [Docker imajları](docker.md) -* [Production'a dağıtım](production.md) -* [**Bağımsız** kendiliğinden çalıştırılabilir PHP uygulamaları oluşturma](embed.md) -* [Statik binary'leri oluşturma](static.md) -* [Kaynak dosyalarından derleme](config.md) -* [Laravel entegrasyonu](laravel.md) -* [Bilinen sorunlar](known-issues.md) -* [Demo uygulama (Symfony) ve kıyaslamalar](https://github.com/dunglas/frankenphp-demo) -* [Go kütüphane dokümantasonu](https://pkg.go.dev/github.com/dunglas/frankenphp) -* [Katkıda bulunma ve hata ayıklama](CONTRIBUTING.md) - -## Örnekler ve İskeletler - -* [Symfony](https://github.com/dunglas/symfony-docker) -* [API Platform](https://api-platform.com/docs/distribution/) -* [Laravel](https://frankenphp.dev/docs/laravel/) -* [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) -* [WordPress](https://github.com/StephenMiracle/frankenwp) -* [Drupal](https://github.com/dunglas/frankenphp-drupal) -* [Joomla](https://github.com/alexandreelise/frankenphp-joomla) -* [TYPO3](https://github.com/ochorocho/franken-typo3) -* [Magento2](https://github.com/ekino/frankenphp-magento2) +# FrankenPHP: PHP için Modern Uygulama Sunucusu + +

FrankenPHP

+ +FrankenPHP, [Caddy](https://caddyserver.com/) web sunucusunun üzerine inşa edilmiş PHP için modern bir uygulama sunucusudur. + +FrankenPHP, çarpıcı özellikleri sayesinde PHP uygulamalarınıza süper güçler kazandırır: [Early Hints\*](https://frankenphp.dev/docs/early-hints/), [worker modu](https://frankenphp.dev/docs/worker/), [real-time yetenekleri](https://frankenphp.dev/docs/mercure/), otomatik HTTPS, HTTP/2 ve HTTP/3 desteği... + +FrankenPHP herhangi bir PHP uygulaması ile çalışır ve worker modu ile resmi entegrasyonları sayesinde Laravel ve Symfony projelerinizi her zamankinden daha performanslı hale getirir. + +FrankenPHP, PHP'yi `net/http` kullanarak herhangi bir uygulamaya yerleştirmek için bağımsız bir Go kütüphanesi olarak da kullanılabilir. + +[_Frankenphp.dev_](https://frankenphp.dev) adresinden ve bu slayt üzerinden daha fazlasını öğrenin: + +Slides + +## Başlarken + +### Docker + +```console +docker run -v $PWD:/app/public \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +`https://localhost` adresine gidin ve keyfini çıkarın! + +> [!TIP] +> +> `https://127.0.0.1` kullanmaya çalışmayın. `https://localhost` kullanın ve kendinden imzalı sertifikayı kabul edin. +> Kullanılacak alan adını değiştirmek için [`SERVER_NAME` ortam değişkenini](https://frankenphp.dev/tr/docs/config#ortam-değişkenleri) kullanın. + +### Binary Çıktısı + +Docker kullanmayı tercih etmiyorsanız, Linux ve macOS için bağımsız FrankenPHP binary dosyası sağlıyoruz +[PHP 8.4](https://www.php.net/releases/8.4/en.php) ve en popüler PHP eklentilerini de içermekte: [FrankenPHP](https://github.com/dunglas/frankenphp/releases) indirin + +Geçerli dizinin içeriğini başlatmak için çalıştırın: + +```console +./frankenphp php-server +``` + +Ayrıca aşağıdaki tek komut satırı ile de çalıştırabilirsiniz: + +```console +./frankenphp php-cli /path/to/your/script.php +``` + +## Docs + +- [Worker modu](worker.md) +- [Early Hints desteği (103 HTTP durum kodu)](early-hints.md) +- [Real-time](mercure.md) +- [Konfigürasyon](config.md) +- [Docker imajları](docker.md) +- [Production'a dağıtım](production.md) +- [**Bağımsız** kendiliğinden çalıştırılabilir PHP uygulamaları oluşturma](embed.md) +- [Statik binary'leri oluşturma](static.md) +- [Kaynak dosyalarından derleme](config.md) +- [Laravel entegrasyonu](laravel.md) +- [Bilinen sorunlar](known-issues.md) +- [Demo uygulama (Symfony) ve kıyaslamalar](https://github.com/dunglas/frankenphp-demo) +- [Go kütüphane dokümantasonu](https://pkg.go.dev/github.com/dunglas/frankenphp) +- [Katkıda bulunma ve hata ayıklama](CONTRIBUTING.md) + +## Örnekler ve İskeletler + +- [Symfony](https://github.com/dunglas/symfony-docker) +- [API Platform](https://api-platform.com/docs/distribution/) +- [Laravel](https://frankenphp.dev/docs/laravel/) +- [Sulu](https://sulu.io/blog/running-sulu-with-frankenphp) +- [WordPress](https://github.com/StephenMiracle/frankenwp) +- [Drupal](https://github.com/dunglas/frankenphp-drupal) +- [Joomla](https://github.com/alexandreelise/frankenphp-joomla) +- [TYPO3](https://github.com/ochorocho/franken-typo3) +- [Magento2](https://github.com/ekino/frankenphp-magento2) diff --git a/docs/tr/compile.md b/docs/tr/compile.md index bb75d2a28f..ceae3ef068 100644 --- a/docs/tr/compile.md +++ b/docs/tr/compile.md @@ -1,100 +1,100 @@ -# Kaynak Kodlardan Derleme - -Bu doküman, PHP'yi dinamik bir kütüphane olarak yükleyecek bir FrankenPHP yapısının nasıl oluşturulacağını açıklamaktadır. -Önerilen yöntem bu şekildedir. - -Alternatif olarak, [statik yapılar oluşturma](static.md) da mümkündür. - -## PHP'yi yükleyin - -FrankenPHP, PHP 8.2 ve üstü ile uyumludur. - -İlk olarak, [PHP'nin kaynaklarını edinin](https://www.php.net/downloads.php) ve bunları çıkarın: - -```console -tar xf php-* -cd php-*/ -``` - -Ardından, PHP'yi platformunuz için yapılandırın. - -Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar) -İhtiyaç halinde. - -### Linux - -```console -./configure \ - --enable-embed \ - --enable-zts \ - --disable-zend-signals \ - --enable-zend-max-execution-timers -``` - -### Mac - -Yüklemek için [Homebrew](https://brew.sh/) paket yöneticisini kullanın -`libiconv`, `bison`, `re2c` ve `pkg-config`: - -```console -brew install libiconv bison re2c pkg-config -echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc -``` - -Ardından yapılandırma betiğini çalıştırın: - -```console -./configure \ - --enable-embed=static \ - --enable-zts \ - --disable-zend-signals \ - --disable-opcache-jit \ - --enable-static \ - --enable-shared=no \ - --with-iconv=/opt/homebrew/opt/libiconv/ -``` - -## PHP Derleyin - -Son olarak, PHP'yi derleyin ve kurun: - -```console -make -j"$(getconf _NPROCESSORS_ONLN)" -sudo make install -``` - -## Go Uygulamasını Derleyin - -Artık Go kütüphanesini kullanabilir ve Caddy yapımızı derleyebilirsiniz: - -```console -curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz -cd frankenphp-main/caddy/frankenphp -CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build -``` - -### Xcaddy kullanımı - -Alternatif olarak, FrankenPHP'yi [özel Caddy modülleri](https://caddyserver.com/docs/modules/) ile derlemek için [xcaddy](https://github.com/caddyserver/xcaddy) kullanın: - -```console -CGO_ENABLED=1 \ -XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \ -xcaddy build \ - --output frankenphp \ - --with github.com/dunglas/frankenphp/caddy \ - --with github.com/dunglas/caddy-cbrotli \ - --with github.com/dunglas/mercure/caddy \ - --with github.com/dunglas/vulcain/caddy - # Add extra Caddy modules here -``` - -> [!TIP] -> -> Eğer musl libc (Alpine Linux'ta varsayılan) ve Symfony kullanıyorsanız, -> varsayılan yığın boyutunu artırmanız gerekebilir. -> Aksi takdirde, şu tarz hatalar alabilirsiniz `PHP Fatal error: Maximum call stack size of 83360 bytes reached during compilation. Try splitting expression` -> -> Bunu yapmak için, `XCADDY_GO_BUILD_FLAGS` ortam değişkenini bu şekilde değiştirin -> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'` -> (yığın boyutunun değerini uygulamanızın ihtiyaçlarına göre değiştirin). +# Kaynak Kodlardan Derleme + +Bu doküman, PHP'yi dinamik bir kütüphane olarak yükleyecek bir FrankenPHP yapısının nasıl oluşturulacağını açıklamaktadır. +Önerilen yöntem bu şekildedir. + +Alternatif olarak, [statik yapılar oluşturma](static.md) da mümkündür. + +## PHP'yi yükleyin + +FrankenPHP, PHP 8.2 ve üstü ile uyumludur. + +İlk olarak, [PHP'nin kaynaklarını edinin](https://www.php.net/downloads.php) ve bunları çıkarın: + +```console +tar xf php-* +cd php-*/ +``` + +Ardından, PHP'yi platformunuz için yapılandırın. + +Bu şekilde yapılandırma gereklidir, ancak başka opsiyonlar da ekleyebilirsiniz (örn. ekstra uzantılar) +İhtiyaç halinde. + +### Linux + +```console +./configure \ + --enable-embed \ + --enable-zts \ + --disable-zend-signals \ + --enable-zend-max-execution-timers +``` + +### Mac + +Yüklemek için [Homebrew](https://brew.sh/) paket yöneticisini kullanın +`libiconv`, `bison`, `re2c` ve `pkg-config`: + +```console +brew install libiconv bison re2c pkg-config +echo 'export PATH="/opt/homebrew/opt/bison/bin:$PATH"' >> ~/.zshrc +``` + +Ardından yapılandırma betiğini çalıştırın: + +```console +./configure \ + --enable-embed=static \ + --enable-zts \ + --disable-zend-signals \ + --disable-opcache-jit \ + --enable-static \ + --enable-shared=no \ + --with-iconv=/opt/homebrew/opt/libiconv/ +``` + +## PHP Derleyin + +Son olarak, PHP'yi derleyin ve kurun: + +```console +make -j"$(getconf _NPROCESSORS_ONLN)" +sudo make install +``` + +## Go Uygulamasını Derleyin + +Artık Go kütüphanesini kullanabilir ve Caddy yapımızı derleyebilirsiniz: + +```console +curl -L https://github.com/dunglas/frankenphp/archive/refs/heads/main.tar.gz | tar xz +cd frankenphp-main/caddy/frankenphp +CGO_CFLAGS=$(php-config --includes) CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build +``` + +### Xcaddy kullanımı + +Alternatif olarak, FrankenPHP'yi [özel Caddy modülleri](https://caddyserver.com/docs/modules/) ile derlemek için [xcaddy](https://github.com/caddyserver/xcaddy) kullanın: + +```console +CGO_ENABLED=1 \ +XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'" \ +xcaddy build \ + --output frankenphp \ + --with github.com/dunglas/frankenphp/caddy \ + --with github.com/dunglas/caddy-cbrotli \ + --with github.com/dunglas/mercure/caddy \ + --with github.com/dunglas/vulcain/caddy + # Add extra Caddy modules here +``` + +> [!TIP] +> +> Eğer musl libc (Alpine Linux'ta varsayılan) ve Symfony kullanıyorsanız, +> varsayılan yığın boyutunu artırmanız gerekebilir. +> Aksi takdirde, şu tarz hatalar alabilirsiniz `PHP Fatal error: Maximum call stack size of 83360 bytes reached during compilation. Try splitting expression` +> +> Bunu yapmak için, `XCADDY_GO_BUILD_FLAGS` ortam değişkenini bu şekilde değiştirin +> `XCADDY_GO_BUILD_FLAGS=$'-ldflags "-w -s -extldflags \'-Wl,-z,stack-size=0x80000\'"'` +> (yığın boyutunun değerini uygulamanızın ihtiyaçlarına göre değiştirin). diff --git a/docs/tr/config.md b/docs/tr/config.md index 605cd6be0e..0ea66b45b9 100644 --- a/docs/tr/config.md +++ b/docs/tr/config.md @@ -122,7 +122,7 @@ route { } ``` -php_server` ve `php` yönergeleri aşağıdaki seçeneklere sahiptir: +php_server`ve`php` yönergeleri aşağıdaki seçeneklere sahiptir: ```caddyfile php_server [] { @@ -137,9 +137,9 @@ php_server [] { Aşağıdaki ortam değişkenleri `Caddyfile` içinde değişiklik yapmadan Caddy yönergelerini entegre etmek için kullanılabilir: -* `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır -* `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options) -* `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin +- `SERVER_NAME`: değiştirin [dinlenecek adresleri](https://caddyserver.com/docs/caddyfile/concepts#addresses), sağlanan ana bilgisayar adları oluşturulan TLS sertifikası için de kullanılacaktır +- `CADDY_GLOBAL_OPTIONS`: entegre edin [global seçenekler](https://caddyserver.com/docs/caddyfile/options) +- `FRANKENPHP_CONFIG`: `frankenphp` yönergesi altına yapılandırma entegre edin FPM ve CLI SAPI'lerinde olduğu gibi, ortam değişkenleri varsayılan olarak `$_SERVER` süper globalinde gösterilir. diff --git a/docs/tr/docker.md b/docs/tr/docker.md index 28710d2845..a55c14b664 100644 --- a/docs/tr/docker.md +++ b/docs/tr/docker.md @@ -1,171 +1,171 @@ -# Özel Docker İmajı Oluşturma - -[Resmi PHP imajları](https://hub.docker.com/_/php/) temel alınarak [FrankenPHP Docker imajları](https://hub.docker.com/r/dunglas/frankenphp) hazırlanmıştır. Popüler mimariler için Debian ve Alpine Linux varyantları sağlanmıştır. Debian dağıtımı tavsiye edilir. - -PHP 8.2, 8.3 ve 8.4 için varyantlar sağlanmıştır. [Etiketlere göz atın](https://hub.docker.com/r/dunglas/frankenphp/tags). - -## İmajlar Nasıl Kullanılır - -Projenizde bir `Dockerfile` oluşturun: - -```dockerfile -FROM dunglas/frankenphp - -COPY . /app/public -``` - -Ardından, Docker imajını oluşturmak ve çalıştırmak için bu komutları çalıştırın: - -```console -docker build -t my-php-app . -docker run -it --rm --name my-running-app my-php-app -``` - -## Daha Fazla PHP Eklentisi Nasıl Kurulur - -[Docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer) betiği temel imajda sağlanmıştır. -Ek PHP eklentileri eklemek ise gerçekten kolaydır: - -```dockerfile -FROM dunglas/frankenphp - -# buraya istenilen eklentileri ekleyin: -RUN install-php-extensions \ - pdo_mysql \ - gd \ - intl \ - zip \ - opcache -``` - -## Daha Fazla Caddy Modülü Nasıl Kurulur - -FrankenPHP, Caddy'nin üzerine inşa edilmiştir ve tüm [Caddy modülleri](https://caddyserver.com/docs/modules/) FrankenPHP ile kullanılabilir. - -Özel Caddy modüllerini kurmanın en kolay yolu [xcaddy](https://github.com/caddyserver/xcaddy) kullanmaktır: - -```dockerfile -FROM dunglas/frankenphp:builder AS builder - -# xcaddy'yi derleyen imaja kopyalayın -COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy - -# FrankenPHP oluşturmak için CGO etkinleştirilmelidir -RUN CGO_ENABLED=1 \ - XCADDY_SETCAP=1 \ - XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \ - CGO_CFLAGS=$(php-config --includes) \ - CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \ - xcaddy build \ - --output /usr/local/bin/frankenphp \ - --with github.com/dunglas/frankenphp=./ \ - --with github.com/dunglas/frankenphp/caddy=./caddy/ \ - --with github.com/dunglas/caddy-cbrotli \ - # Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin - --with github.com/dunglas/mercure/caddy \ - --with github.com/dunglas/vulcain/caddy - # Buraya ekstra Caddy modülleri ekleyin - -FROM dunglas/frankenphp AS runner - -# Resmi binary dosyayı özel modüllerinizi içeren binary dosyayla değiştirin -COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp -``` - -FrankenPHP tarafından sağlanan `builder` imajı `libphp`'nin derlenmiş bir sürümünü içerir. -[Derleyici imajları](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) hem Debian hem de Alpine için FrankenPHP ve PHP'nin tüm sürümleri için sağlanmıştır. - -> [!TIP] -> -> Eğer Alpine Linux ve Symfony kullanıyorsanız, -> [varsayılan yığın boyutunu artırmanız](compile.md#xcaddy-kullanımı) gerekebilir. - -## Varsayılan Olarak Worker Modunun Etkinleştirilmesi - -FrankenPHP'yi bir worker betiği ile başlatmak için `FRANKENPHP_CONFIG` ortam değişkenini ayarlayın: - -```dockerfile -FROM dunglas/frankenphp - -# ... - -ENV FRANKENPHP_CONFIG="worker ./public/index.php" -``` - -## Geliştirme Sürecinde Yığın (Volume) Kullanma - -FrankenPHP ile kolayca geliştirme yapmak için, uygulamanın kaynak kodunu içeren dizini ana bilgisayarınızdan Docker konteynerine bir yığın (volume) olarak bağlayın: - -```console -docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp --tty my-php-app -``` - -> [!TIP] -> -> `--tty` seçeneği JSON günlükleri yerine insan tarafından okunabilir güzel günlüklere sahip olmayı sağlar. - -Docker Compose ile: - -```yaml -# compose.yaml - -services: - php: - image: dunglas/frankenphp - # özel bir Dockerfile kullanmak istiyorsanız aşağıdaki yorum satırını kaldırın - #build: . - # bunu bir production ortamında çalıştırmak istiyorsanız aşağıdaki yorum satırını kaldırın - # restart: always - ports: - - "80:80" # HTTP - - "443:443" # HTTPS - - "443:443/udp" # HTTP/3 - volumes: - - ./:/app/public - - caddy_data:/data - - caddy_config:/config - # production ortamda aşağıdaki satırı yorum satırı yapın, geliştirme ortamında insan tarafından okunabilir güzel günlüklere sahip olmanızı sağlar - tty: true - -# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes) -volumes: - caddy_data: - caddy_config: -``` - -## Root Olmayan Kullanıcı Olarak Çalıştırma - -FrankenPHP, Docker'da root olmayan kullanıcı olarak çalışabilir. - -İşte bunu yapan örnek bir `Dockerfile`: - -```dockerfile -FROM dunglas/frankenphp - -ARG USER=appuser - -RUN \ - # Alpine tabanlı dağıtımlar için "adduser -D ${USER}" kullanın - useradd ${USER}; \ - # 80 ve 443 numaralı bağlantı noktalarına bağlanmak için ek özellik ekleyin - setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \ - # /data/caddy ve /config/caddy dosyalarına yazma erişimi verin - chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy; - -USER ${USER} -``` - -## Güncellemeler - -Docker imajları oluşturulur: - -* Yeni bir sürüm etiketlendiğinde -* Her gün UTC ile saat 4'te Resmi PHP imajlarının yeni sürümleri mevcutsa - -## Geliştirme Sürümleri - -Geliştirme sürümleri [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev) Docker deposunda mevcuttur. -GitHub deposunun ana dalına her commit yapıldığında yeni bir derleme tetiklenir. - -`latest*` etiketleri `main` dalının başına işaret eder. -`sha-` biçimindeki etiketler de kullanılabilir. +# Özel Docker İmajı Oluşturma + +[Resmi PHP imajları](https://hub.docker.com/_/php/) temel alınarak [FrankenPHP Docker imajları](https://hub.docker.com/r/dunglas/frankenphp) hazırlanmıştır. Popüler mimariler için Debian ve Alpine Linux varyantları sağlanmıştır. Debian dağıtımı tavsiye edilir. + +PHP 8.2, 8.3 ve 8.4 için varyantlar sağlanmıştır. [Etiketlere göz atın](https://hub.docker.com/r/dunglas/frankenphp/tags). + +## İmajlar Nasıl Kullanılır + +Projenizde bir `Dockerfile` oluşturun: + +```dockerfile +FROM dunglas/frankenphp + +COPY . /app/public +``` + +Ardından, Docker imajını oluşturmak ve çalıştırmak için bu komutları çalıştırın: + +```console +docker build -t my-php-app . +docker run -it --rm --name my-running-app my-php-app +``` + +## Daha Fazla PHP Eklentisi Nasıl Kurulur + +[Docker-php-extension-installer`](https://github.com/mlocati/docker-php-extension-installer) betiği temel imajda sağlanmıştır. +Ek PHP eklentileri eklemek ise gerçekten kolaydır: + +```dockerfile +FROM dunglas/frankenphp + +# buraya istenilen eklentileri ekleyin: +RUN install-php-extensions \ + pdo_mysql \ + gd \ + intl \ + zip \ + opcache +``` + +## Daha Fazla Caddy Modülü Nasıl Kurulur + +FrankenPHP, Caddy'nin üzerine inşa edilmiştir ve tüm [Caddy modülleri](https://caddyserver.com/docs/modules/) FrankenPHP ile kullanılabilir. + +Özel Caddy modüllerini kurmanın en kolay yolu [xcaddy](https://github.com/caddyserver/xcaddy) kullanmaktır: + +```dockerfile +FROM dunglas/frankenphp:builder AS builder + +# xcaddy'yi derleyen imaja kopyalayın +COPY --from=caddy:builder /usr/bin/xcaddy /usr/bin/xcaddy + +# FrankenPHP oluşturmak için CGO etkinleştirilmelidir +RUN CGO_ENABLED=1 \ + XCADDY_SETCAP=1 \ + XCADDY_GO_BUILD_FLAGS="-ldflags='-w -s' -tags=nobadger,nomysql,nopgx" \ + CGO_CFLAGS=$(php-config --includes) \ + CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" \ + xcaddy build \ + --output /usr/local/bin/frankenphp \ + --with github.com/dunglas/frankenphp=./ \ + --with github.com/dunglas/frankenphp/caddy=./caddy/ \ + --with github.com/dunglas/caddy-cbrotli \ + # Mercure ve Vulcain resmi yapıya dahil edilmiştir, ancak bunları kaldırmaktan çekinmeyin + --with github.com/dunglas/mercure/caddy \ + --with github.com/dunglas/vulcain/caddy + # Buraya ekstra Caddy modülleri ekleyin + +FROM dunglas/frankenphp AS runner + +# Resmi binary dosyayı özel modüllerinizi içeren binary dosyayla değiştirin +COPY --from=builder /usr/local/bin/frankenphp /usr/local/bin/frankenphp +``` + +FrankenPHP tarafından sağlanan `builder` imajı `libphp`'nin derlenmiş bir sürümünü içerir. +[Derleyici imajları](https://hub.docker.com/r/dunglas/frankenphp/tags?name=builder) hem Debian hem de Alpine için FrankenPHP ve PHP'nin tüm sürümleri için sağlanmıştır. + +> [!TIP] +> +> Eğer Alpine Linux ve Symfony kullanıyorsanız, +> [varsayılan yığın boyutunu artırmanız](compile.md#xcaddy-kullanımı) gerekebilir. + +## Varsayılan Olarak Worker Modunun Etkinleştirilmesi + +FrankenPHP'yi bir worker betiği ile başlatmak için `FRANKENPHP_CONFIG` ortam değişkenini ayarlayın: + +```dockerfile +FROM dunglas/frankenphp + +# ... + +ENV FRANKENPHP_CONFIG="worker ./public/index.php" +``` + +## Geliştirme Sürecinde Yığın (Volume) Kullanma + +FrankenPHP ile kolayca geliştirme yapmak için, uygulamanın kaynak kodunu içeren dizini ana bilgisayarınızdan Docker konteynerine bir yığın (volume) olarak bağlayın: + +```console +docker run -v $PWD:/app/public -p 80:80 -p 443:443 -p 443:443/udp --tty my-php-app +``` + +> [!TIP] +> +> `--tty` seçeneği JSON günlükleri yerine insan tarafından okunabilir güzel günlüklere sahip olmayı sağlar. + +Docker Compose ile: + +```yaml +# compose.yaml + +services: + php: + image: dunglas/frankenphp + # özel bir Dockerfile kullanmak istiyorsanız aşağıdaki yorum satırını kaldırın + #build: . + # bunu bir production ortamında çalıştırmak istiyorsanız aşağıdaki yorum satırını kaldırın + # restart: always + ports: + - "80:80" # HTTP + - "443:443" # HTTPS + - "443:443/udp" # HTTP/3 + volumes: + - ./:/app/public + - caddy_data:/data + - caddy_config:/config + # production ortamda aşağıdaki satırı yorum satırı yapın, geliştirme ortamında insan tarafından okunabilir güzel günlüklere sahip olmanızı sağlar + tty: true + +# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes) +volumes: + caddy_data: + caddy_config: +``` + +## Root Olmayan Kullanıcı Olarak Çalıştırma + +FrankenPHP, Docker'da root olmayan kullanıcı olarak çalışabilir. + +İşte bunu yapan örnek bir `Dockerfile`: + +```dockerfile +FROM dunglas/frankenphp + +ARG USER=appuser + +RUN \ + # Alpine tabanlı dağıtımlar için "adduser -D ${USER}" kullanın + useradd ${USER}; \ + # 80 ve 443 numaralı bağlantı noktalarına bağlanmak için ek özellik ekleyin + setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/frankenphp; \ + # /data/caddy ve /config/caddy dosyalarına yazma erişimi verin + chown -R ${USER}:${USER} /data/caddy && chown -R ${USER}:${USER} /config/caddy; + +USER ${USER} +``` + +## Güncellemeler + +Docker imajları oluşturulur: + +- Yeni bir sürüm etiketlendiğinde +- Her gün UTC ile saat 4'te Resmi PHP imajlarının yeni sürümleri mevcutsa + +## Geliştirme Sürümleri + +Geliştirme sürümleri [`dunglas/frankenphp-dev`](https://hub.docker.com/repository/docker/dunglas/frankenphp-dev) Docker deposunda mevcuttur. +GitHub deposunun ana dalına her commit yapıldığında yeni bir derleme tetiklenir. + +`latest*` etiketleri `main` dalının başına işaret eder. +`sha-` biçimindeki etiketler de kullanılabilir. diff --git a/docs/tr/early-hints.md b/docs/tr/early-hints.md index 1dad43212d..c425df4fe5 100644 --- a/docs/tr/early-hints.md +++ b/docs/tr/early-hints.md @@ -1,21 +1,21 @@ -# Early Hints - -FrankenPHP [103 Early Hints durum kodunu](https://developer.chrome.com/blog/early-hints/) yerel olarak destekler. -Early Hints kullanmak web sayfalarınızın yüklenme süresini %30 oranında artırabilir. - -```php -; rel=preload; as=style'); -headers_send(103); - -// yavaş algoritmalarınız ve SQL sorgularınız 🤪 - -echo <<<'HTML' - -Hello FrankenPHP - -HTML; -``` - -Early Hints hem normal hem de [worker](worker.md) modları tarafından desteklenir. +# Early Hints + +FrankenPHP [103 Early Hints durum kodunu](https://developer.chrome.com/blog/early-hints/) yerel olarak destekler. +Early Hints kullanmak web sayfalarınızın yüklenme süresini %30 oranında artırabilir. + +```php +; rel=preload; as=style'); +headers_send(103); + +// yavaş algoritmalarınız ve SQL sorgularınız 🤪 + +echo <<<'HTML' + +Hello FrankenPHP + +HTML; +``` + +Early Hints hem normal hem de [worker](worker.md) modları tarafından desteklenir. diff --git a/docs/tr/embed.md b/docs/tr/embed.md index df265c2688..c76b545f7d 100644 --- a/docs/tr/embed.md +++ b/docs/tr/embed.md @@ -1,132 +1,132 @@ -# Binary Dosyası Olarak PHP Uygulamaları - -FrankenPHP, PHP uygulamalarının kaynak kodunu ve varlıklarını statik, kendi kendine yeten bir binary dosyaya yerleştirme yeteneğine sahiptir. - -Bu özellik sayesinde PHP uygulamaları, uygulamanın kendisini, PHP yorumlayıcısını ve üretim düzeyinde bir web sunucusu olan Caddy'yi içeren bağımsız bir binary dosyalar olarak çıktısı alınabilir ve dağıtılabilir. - -Bu özellik hakkında daha fazla bilgi almak için [Kévin tarafından SymfonyCon 2023'te yapılan sunuma](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/) göz atabilirsiniz. - -## Preparing Your App - -Bağımsız binary dosyayı oluşturmadan önce uygulamanızın gömülmeye hazır olduğundan emin olun. - -Örneğin muhtemelen şunları yapmak istersiniz: - -* Uygulamanın üretim bağımlılıklarını yükleyin -* Otomatik yükleyiciyi boşaltın -* Uygulamanızın üretim modunu etkinleştirin (varsa) -* Nihai binary dosyanızın boyutunu küçültmek için `.git` veya testler gibi gerekli olmayan dosyaları çıkarın - -Örneğin, bir Symfony uygulaması için aşağıdaki komutları kullanabilirsiniz: - -```console -# .git/, vb. dosyalarından kurtulmak için projeyi dışa aktarın -mkdir $TMPDIR/my-prepared-app -git archive HEAD | tar -x -C $TMPDIR/my-prepared-app -cd $TMPDIR/my-prepared-app - -# Uygun ortam değişkenlerini ayarlayın -echo APP_ENV=prod > .env.local -echo APP_DEBUG=0 >> .env.local - -# Testleri kaldırın -rm -Rf tests/ - -# Bağımlılıkları yükleyin -composer install --ignore-platform-reqs --no-dev -a - -# .env'yi optimize edin -composer dump-env prod -``` - -## Linux Binary'si Oluşturma - -Bir Linux binary çıktısı almanın en kolay yolu, sağladığımız Docker tabanlı derleyiciyi kullanmaktır. - -1. Hazırladığınız uygulamanın deposunda `static-build.Dockerfile` adlı bir dosya oluşturun: - - ```dockerfile - FROM --platform=linux/amd64 dunglas/frankenphp:static-builder - - # Uygulamanızı kopyalayın - WORKDIR /go/src/app/dist/app - COPY . . - - # Statik binary dosyasını oluşturun, yalnızca istediğiniz PHP eklentilerini seçtiğinizden emin olun - WORKDIR /go/src/app/ - RUN EMBED=dist/app/ \ - PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \ - ./build-static.sh - ``` - - > [!CAUTION] - > - > Bazı `.dockerignore` dosyaları (örneğin varsayılan [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) - > `vendor/` dizinini ve `.env` dosyalarını yok sayacaktır. Derlemeden önce `.dockerignore` dosyasını ayarladığınızdan veya kaldırdığınızdan emin olun. - -2. Derleyin: - - ```console - docker build -t static-app -f static-build.Dockerfile . - ``` - -3. Binary dosyasını çıkarın: - - ```console - docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp - ``` - -Elde edilen binary dosyası, geçerli dizindeki `my-app` adlı dosyadır. - -## Diğer İşletim Sistemleri için Binary Çıktısı Alma - -Docker kullanmak istemiyorsanız veya bir macOS binary dosyası oluşturmak istiyorsanız, sağladığımız kabuk betiğini kullanın: - -```console -git clone https://github.com/dunglas/frankenphp -cd frankenphp -EMBED=/path/to/your/app \ - PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \ - ./build-static.sh -``` - -Elde edilen binary dosyası `dist/` dizinindeki `frankenphp--` adlı dosyadır. - -## Binary Dosyasını Kullanma - -İşte bu kadar! `my-app` dosyası (veya diğer işletim sistemlerinde `dist/frankenphp--`) bağımsız uygulamanızı içerir! - -Web uygulamasını başlatmak için çalıştırın: - -```console -./my-app php-server -``` - -Uygulamanız bir [worker betiği](worker.md) içeriyorsa, worker'ı aşağıdaki gibi bir şeyle başlatın: - -```console -./my-app php-server --worker public/index.php -``` - -HTTPS (Let's Encrypt sertifikası otomatik olarak oluşturulur), HTTP/2 ve HTTP/3'ü etkinleştirmek için kullanılacak alan adını belirtin: - -```console -./my-app php-server --domain localhost -``` - -Ayrıca binary dosyanıza gömülü PHP CLI betiklerini de çalıştırabilirsiniz: - -```console -./my-app php-cli bin/console -``` - -## Yapıyı Özelleştirme - -Binary dosyasının nasıl özelleştirileceğini (uzantılar, PHP sürümü...) görmek için [Statik derleme dokümanını okuyun](static.md). - -## Binary Dosyasının Dağıtılması - -Linux'ta, oluşturulan ikili dosya [UPX](https://upx.github.io) kullanılarak sıkıştırılır. - -Mac'te, göndermeden önce dosyanın boyutunu küçültmek için sıkıştırabilirsiniz. -Biz `xz` öneririz. +# Binary Dosyası Olarak PHP Uygulamaları + +FrankenPHP, PHP uygulamalarının kaynak kodunu ve varlıklarını statik, kendi kendine yeten bir binary dosyaya yerleştirme yeteneğine sahiptir. + +Bu özellik sayesinde PHP uygulamaları, uygulamanın kendisini, PHP yorumlayıcısını ve üretim düzeyinde bir web sunucusu olan Caddy'yi içeren bağımsız bir binary dosyalar olarak çıktısı alınabilir ve dağıtılabilir. + +Bu özellik hakkında daha fazla bilgi almak için [Kévin tarafından SymfonyCon 2023'te yapılan sunuma](https://dunglas.dev/2023/12/php-and-symfony-apps-as-standalone-binaries/) göz atabilirsiniz. + +## Preparing Your App + +Bağımsız binary dosyayı oluşturmadan önce uygulamanızın gömülmeye hazır olduğundan emin olun. + +Örneğin muhtemelen şunları yapmak istersiniz: + +- Uygulamanın üretim bağımlılıklarını yükleyin +- Otomatik yükleyiciyi boşaltın +- Uygulamanızın üretim modunu etkinleştirin (varsa) +- Nihai binary dosyanızın boyutunu küçültmek için `.git` veya testler gibi gerekli olmayan dosyaları çıkarın + +Örneğin, bir Symfony uygulaması için aşağıdaki komutları kullanabilirsiniz: + +```console +# .git/, vb. dosyalarından kurtulmak için projeyi dışa aktarın +mkdir $TMPDIR/my-prepared-app +git archive HEAD | tar -x -C $TMPDIR/my-prepared-app +cd $TMPDIR/my-prepared-app + +# Uygun ortam değişkenlerini ayarlayın +echo APP_ENV=prod > .env.local +echo APP_DEBUG=0 >> .env.local + +# Testleri kaldırın +rm -Rf tests/ + +# Bağımlılıkları yükleyin +composer install --ignore-platform-reqs --no-dev -a + +# .env'yi optimize edin +composer dump-env prod +``` + +## Linux Binary'si Oluşturma + +Bir Linux binary çıktısı almanın en kolay yolu, sağladığımız Docker tabanlı derleyiciyi kullanmaktır. + +1. Hazırladığınız uygulamanın deposunda `static-build.Dockerfile` adlı bir dosya oluşturun: + + ```dockerfile + FROM --platform=linux/amd64 dunglas/frankenphp:static-builder + + # Uygulamanızı kopyalayın + WORKDIR /go/src/app/dist/app + COPY . . + + # Statik binary dosyasını oluşturun, yalnızca istediğiniz PHP eklentilerini seçtiğinizden emin olun + WORKDIR /go/src/app/ + RUN EMBED=dist/app/ \ + PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \ + ./build-static.sh + ``` + + > [!CAUTION] + > + > Bazı `.dockerignore` dosyaları (örneğin varsayılan [Symfony Docker `.dockerignore`](https://github.com/dunglas/symfony-docker/blob/main/.dockerignore)) + > `vendor/` dizinini ve `.env` dosyalarını yok sayacaktır. Derlemeden önce `.dockerignore` dosyasını ayarladığınızdan veya kaldırdığınızdan emin olun. + +2. Derleyin: + + ```console + docker build -t static-app -f static-build.Dockerfile . + ``` + +3. Binary dosyasını çıkarın: + + ```console + docker cp $(docker create --name static-app-tmp static-app):/go/src/app/dist/frankenphp-linux-x86_64 my-app ; docker rm static-app-tmp + ``` + +Elde edilen binary dosyası, geçerli dizindeki `my-app` adlı dosyadır. + +## Diğer İşletim Sistemleri için Binary Çıktısı Alma + +Docker kullanmak istemiyorsanız veya bir macOS binary dosyası oluşturmak istiyorsanız, sağladığımız kabuk betiğini kullanın: + +```console +git clone https://github.com/dunglas/frankenphp +cd frankenphp +EMBED=/path/to/your/app \ + PHP_EXTENSIONS=ctype,iconv,pdo_sqlite \ + ./build-static.sh +``` + +Elde edilen binary dosyası `dist/` dizinindeki `frankenphp--` adlı dosyadır. + +## Binary Dosyasını Kullanma + +İşte bu kadar! `my-app` dosyası (veya diğer işletim sistemlerinde `dist/frankenphp--`) bağımsız uygulamanızı içerir! + +Web uygulamasını başlatmak için çalıştırın: + +```console +./my-app php-server +``` + +Uygulamanız bir [worker betiği](worker.md) içeriyorsa, worker'ı aşağıdaki gibi bir şeyle başlatın: + +```console +./my-app php-server --worker public/index.php +``` + +HTTPS (Let's Encrypt sertifikası otomatik olarak oluşturulur), HTTP/2 ve HTTP/3'ü etkinleştirmek için kullanılacak alan adını belirtin: + +```console +./my-app php-server --domain localhost +``` + +Ayrıca binary dosyanıza gömülü PHP CLI betiklerini de çalıştırabilirsiniz: + +```console +./my-app php-cli bin/console +``` + +## Yapıyı Özelleştirme + +Binary dosyasının nasıl özelleştirileceğini (uzantılar, PHP sürümü...) görmek için [Statik derleme dokümanını okuyun](static.md). + +## Binary Dosyasının Dağıtılması + +Linux'ta, oluşturulan ikili dosya [UPX](https://upx.github.io) kullanılarak sıkıştırılır. + +Mac'te, göndermeden önce dosyanın boyutunu küçültmek için sıkıştırabilirsiniz. +Biz `xz` öneririz. diff --git a/docs/tr/github-actions.md b/docs/tr/github-actions.md index 8b25ca7999..6adeaa558b 100644 --- a/docs/tr/github-actions.md +++ b/docs/tr/github-actions.md @@ -1,31 +1,31 @@ -# GitHub Actions Kullanma - -Bu depo Docker imajını [Docker Hub](https://hub.docker.com/r/dunglas/frankenphp) üzerinde derler ve dağıtır. -Bu durum onaylanan her çekme (pull) isteğinde veya çatallandıktan (fork) sonra gerçekleşir. - -## GitHub Eylemlerini Ayarlama - -Depo ayarlarında, gizli değerler altında aşağıdaki gizli değerleri ekleyin: - -- `REGISTRY_LOGIN_SERVER`: Kullanılacak Docker Registry bilgisi (örneğin `docker.io`). -- `REGISTRY_USERNAME`: Giriş yapmak için kullanılacak kullanıcı adı (örn. `dunglas`). -- `REGISTRY_PASSWORD`: Oturum açmak için kullanılacak parola (örn. bir erişim anahtarı). -- `IMAGE_NAME`: İmajın adı (örn. `dunglas/frankenphp`). - -## İmajı Oluşturma ve Dağıtma - -1. Bir Çekme (pull) İsteği oluşturun veya çatala (forka) dağıtın. -2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır. -3. Derleme başarılı olursa, görüntü `pr-x` (burada `x` PR numarasıdır) etiketi kullanılarak ilgili saklanan yere (registry'e) gönderilir. - -## İmajı Dağıtma - -1. Çekme (pull) isteği birleştirildikten sonra, GitHub Actions testleri tekrar çalıştıracak ve yeni bir imaj oluşturacaktır. -2. Derleme başarılı olursa, `main` etiketi Docker Registry'de güncellenecektir. - -## Bültenler - -1. Depoda yeni bir etiket oluşturun. -2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır. -3. Derleme başarılı olursa, etiket adı etiket olarak kullanılarak imaj saklanan yere (registry'e) gönderilir (örneğin `v1.2.3` ve `v1.2` oluşturulur). -4. `latest` etiketi de güncellenecektir. +# GitHub Actions Kullanma + +Bu depo Docker imajını [Docker Hub](https://hub.docker.com/r/dunglas/frankenphp) üzerinde derler ve dağıtır. +Bu durum onaylanan her çekme (pull) isteğinde veya çatallandıktan (fork) sonra gerçekleşir. + +## GitHub Eylemlerini Ayarlama + +Depo ayarlarında, gizli değerler altında aşağıdaki gizli değerleri ekleyin: + +- `REGISTRY_LOGIN_SERVER`: Kullanılacak Docker Registry bilgisi (örneğin `docker.io`). +- `REGISTRY_USERNAME`: Giriş yapmak için kullanılacak kullanıcı adı (örn. `dunglas`). +- `REGISTRY_PASSWORD`: Oturum açmak için kullanılacak parola (örn. bir erişim anahtarı). +- `IMAGE_NAME`: İmajın adı (örn. `dunglas/frankenphp`). + +## İmajı Oluşturma ve Dağıtma + +1. Bir Çekme (pull) İsteği oluşturun veya çatala (forka) dağıtın. +2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır. +3. Derleme başarılı olursa, görüntü `pr-x` (burada `x` PR numarasıdır) etiketi kullanılarak ilgili saklanan yere (registry'e) gönderilir. + +## İmajı Dağıtma + +1. Çekme (pull) isteği birleştirildikten sonra, GitHub Actions testleri tekrar çalıştıracak ve yeni bir imaj oluşturacaktır. +2. Derleme başarılı olursa, `main` etiketi Docker Registry'de güncellenecektir. + +## Bültenler + +1. Depoda yeni bir etiket oluşturun. +2. GitHub Actions imajı oluşturacak ve tüm testleri çalıştıracaktır. +3. Derleme başarılı olursa, etiket adı etiket olarak kullanılarak imaj saklanan yere (registry'e) gönderilir (örneğin `v1.2.3` ve `v1.2` oluşturulur). +4. `latest` etiketi de güncellenecektir. diff --git a/docs/tr/known-issues.md b/docs/tr/known-issues.md index 662c91d19f..8c3eb0c34b 100644 --- a/docs/tr/known-issues.md +++ b/docs/tr/known-issues.md @@ -1,107 +1,107 @@ -# Bilinen Sorunlar - -## Desteklenmeyen PHP Eklentileri - -Aşağıdaki eklentilerin FrankenPHP ile uyumlu olmadığı bilinmektedir: - -| Adı | Nedeni | Alternatifleri | -|-------------------------------------------------------------|----------------------------|----------------------------------------------------------------------------------------------------------------------| -| [imap](https://www.php.net/manual/en/imap.installation.php) | İş parçacığı güvenli değil | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) | - -## Sorunlu PHP Eklentileri - -Aşağıdaki eklentiler FrankenPHP ile kullanıldığında bilinen hatalara ve beklenmeyen davranışlara sahiptir: - -| Adı | Problem | -|-----------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| - -## get_browser - -[get_browser()](https://www.php.net/manual/en/function.get-browser.php) fonksiyonu bir süre sonra kötü performans gösteriyor gibi görünüyor. Geçici bir çözüm, statik oldukları için User-Agent başına sonuçları önbelleğe almaktır (örneğin [APCu](https://www.php.net/manual/en/book.apcu.php) ile). - -## Binary Çıktısı ve Alpine Tabanlı Docker İmajları - -Binary çıktısı ve Alpine tabanlı Docker imajları (dunglas/frankenphp:*-alpine), daha küçük bir binary boyutu korumak için glibc ve arkadaşları yerine musl libc kullanır. Bu durum bazı uyumluluk sorunlarına yol açabilir. Özellikle, glob seçeneği GLOB_BRACE mevcut değildir. - -## Docker ile `https://127.0.0.1` Kullanımı - -FrankenPHP varsayılan olarak `localhost` için bir TLS sertifikası oluşturur. -Bu, yerel geliştirme için en kolay ve önerilen seçenektir. - -Bunun yerine ana bilgisayar olarak `127.0.0.1` kullanmak istiyorsanız, sunucu adını `127.0.0.1` şeklinde ayarlayarak bunun için bir sertifika oluşturacak yapılandırma yapmak mümkündür. - -Ne yazık ki, [ağ sistemi](https://docs.docker.com/network/) nedeniyle Docker kullanırken bu yeterli değildir. -`Curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`'a benzer bir TLS hatası alırsınız. - -Linux kullanıyorsanız, [ana bilgisayar ağ sürücüsünü](https://docs.docker.com/network/network-tutorial-host/) kullanmak bir çözümdür: - -```console -docker run \ - -e SERVER_NAME="127.0.0.1" \ - -v $PWD:/app/public \ - --network host \ - dunglas/frankenphp -``` - -Ana bilgisayar ağ sürücüsü Mac ve Windows'ta desteklenmez. Bu platformlarda, konteynerin IP adresini tahmin etmeniz ve bunu sunucu adlarına dahil etmeniz gerekecektir. - -`docker network inspect bridge`'i çalıştırın ve `IPv4Address` anahtarının altındaki son atanmış IP adresini belirlemek için `Containers` anahtarına bakın ve bir artırın. Eğer hiçbir konteyner çalışmıyorsa, ilk atanan IP adresi genellikle `172.17.0.2`dir. - -Ardından, bunu `SERVER_NAME` ortam değişkenine ekleyin: - -```console -docker run \ - -e SERVER_NAME="127.0.0.1, 172.17.0.3" \ - -v $PWD:/app/public \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -> [!CAUTION] -> -> 172.17.0.3`ü konteynerinize atanacak IP ile değiştirdiğinizden emin olun. - -Artık ana makineden `https://127.0.0.1` adresine erişebilmeniz gerekir. - -Eğer durum böyle değilse, sorunu anlamaya çalışmak için FrankenPHP'yi hata ayıklama modunda başlatın: - -```console -docker run \ - -e CADDY_GLOBAL_OPTIONS="debug" \ - -e SERVER_NAME="127.0.0.1" \ - -v $PWD:/app/public \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -## `@php` Referanslı Composer Betikler - -[Composer betikleri](https://getcomposer.org/doc/articles/scripts.md) bazı görevler için bir PHP binary çalıştırmak isteyebilir, örneğin [bir Laravel projesinde](laravel.md) `@php artisan package:discover --ansi` çalıştırmak. Bu [şu anda mümkün değil](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) ve 2 nedeni var: - -* Composer FrankenPHP binary dosyasını nasıl çağıracağını bilmiyor; -* Composer, FrankenPHP'nin henüz desteklemediği `-d` bayrağını kullanarak PHP ayarlarını komuta ekleyebilir. - -Geçici bir çözüm olarak, `/usr/local/bin/php` içinde desteklenmeyen parametreleri silen ve ardından FrankenPHP'yi çağıran bir kabuk betiği oluşturabiliriz: - -```bash -#!/bin/bash -args=("$@") -index=0 -for i in "$@" -do - if [ "$i" == "-d" ]; then - unset 'args[$index]' - unset 'args[$index+1]' - fi - index=$((index+1)) -done - -/usr/local/bin/frankenphp php-cli ${args[@]} -``` - -Ardından `PHP_BINARY` ortam değişkenini PHP betiğimizin yoluna ayarlayın ve Composer bu yolla çalışacaktır: - -```bash -export PHP_BINARY=/usr/local/bin/php -composer install -``` +# Bilinen Sorunlar + +## Desteklenmeyen PHP Eklentileri + +Aşağıdaki eklentilerin FrankenPHP ile uyumlu olmadığı bilinmektedir: + +| Adı | Nedeni | Alternatifleri | +| ----------------------------------------------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| [imap](https://www.php.net/manual/en/imap.installation.php) | İş parçacığı güvenli değil | [javanile/php-imap2](https://github.com/javanile/php-imap2), [webklex/php-imap](https://github.com/Webklex/php-imap) | + +## Sorunlu PHP Eklentileri + +Aşağıdaki eklentiler FrankenPHP ile kullanıldığında bilinen hatalara ve beklenmeyen davranışlara sahiptir: + +| Adı | Problem | +| --- | ------- | + +## get_browser + +[get_browser()](https://www.php.net/manual/en/function.get-browser.php) fonksiyonu bir süre sonra kötü performans gösteriyor gibi görünüyor. Geçici bir çözüm, statik oldukları için User-Agent başına sonuçları önbelleğe almaktır (örneğin [APCu](https://www.php.net/manual/en/book.apcu.php) ile). + +## Binary Çıktısı ve Alpine Tabanlı Docker İmajları + +Binary çıktısı ve Alpine tabanlı Docker imajları (dunglas/frankenphp:\*-alpine), daha küçük bir binary boyutu korumak için glibc ve arkadaşları yerine musl libc kullanır. Bu durum bazı uyumluluk sorunlarına yol açabilir. Özellikle, glob seçeneği GLOB_BRACE mevcut değildir. + +## Docker ile `https://127.0.0.1` Kullanımı + +FrankenPHP varsayılan olarak `localhost` için bir TLS sertifikası oluşturur. +Bu, yerel geliştirme için en kolay ve önerilen seçenektir. + +Bunun yerine ana bilgisayar olarak `127.0.0.1` kullanmak istiyorsanız, sunucu adını `127.0.0.1` şeklinde ayarlayarak bunun için bir sertifika oluşturacak yapılandırma yapmak mümkündür. + +Ne yazık ki, [ağ sistemi](https://docs.docker.com/network/) nedeniyle Docker kullanırken bu yeterli değildir. +`Curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error`'a benzer bir TLS hatası alırsınız. + +Linux kullanıyorsanız, [ana bilgisayar ağ sürücüsünü](https://docs.docker.com/network/network-tutorial-host/) kullanmak bir çözümdür: + +```console +docker run \ + -e SERVER_NAME="127.0.0.1" \ + -v $PWD:/app/public \ + --network host \ + dunglas/frankenphp +``` + +Ana bilgisayar ağ sürücüsü Mac ve Windows'ta desteklenmez. Bu platformlarda, konteynerin IP adresini tahmin etmeniz ve bunu sunucu adlarına dahil etmeniz gerekecektir. + +`docker network inspect bridge`'i çalıştırın ve `IPv4Address` anahtarının altındaki son atanmış IP adresini belirlemek için `Containers` anahtarına bakın ve bir artırın. Eğer hiçbir konteyner çalışmıyorsa, ilk atanan IP adresi genellikle `172.17.0.2`dir. + +Ardından, bunu `SERVER_NAME` ortam değişkenine ekleyin: + +```console +docker run \ + -e SERVER_NAME="127.0.0.1, 172.17.0.3" \ + -v $PWD:/app/public \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +> [!CAUTION] +> +> 172.17.0.3`ü konteynerinize atanacak IP ile değiştirdiğinizden emin olun. + +Artık ana makineden `https://127.0.0.1` adresine erişebilmeniz gerekir. + +Eğer durum böyle değilse, sorunu anlamaya çalışmak için FrankenPHP'yi hata ayıklama modunda başlatın: + +```console +docker run \ + -e CADDY_GLOBAL_OPTIONS="debug" \ + -e SERVER_NAME="127.0.0.1" \ + -v $PWD:/app/public \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +## `@php` Referanslı Composer Betikler + +[Composer betikleri](https://getcomposer.org/doc/articles/scripts.md) bazı görevler için bir PHP binary çalıştırmak isteyebilir, örneğin [bir Laravel projesinde](laravel.md) `@php artisan package:discover --ansi` çalıştırmak. Bu [şu anda mümkün değil](https://github.com/dunglas/frankenphp/issues/483#issuecomment-1899890915) ve 2 nedeni var: + +- Composer FrankenPHP binary dosyasını nasıl çağıracağını bilmiyor; +- Composer, FrankenPHP'nin henüz desteklemediği `-d` bayrağını kullanarak PHP ayarlarını komuta ekleyebilir. + +Geçici bir çözüm olarak, `/usr/local/bin/php` içinde desteklenmeyen parametreleri silen ve ardından FrankenPHP'yi çağıran bir kabuk betiği oluşturabiliriz: + +```bash +#!/bin/bash +args=("$@") +index=0 +for i in "$@" +do + if [ "$i" == "-d" ]; then + unset 'args[$index]' + unset 'args[$index+1]' + fi + index=$((index+1)) +done + +/usr/local/bin/frankenphp php-cli ${args[@]} +``` + +Ardından `PHP_BINARY` ortam değişkenini PHP betiğimizin yoluna ayarlayın ve Composer bu yolla çalışacaktır: + +```bash +export PHP_BINARY=/usr/local/bin/php +composer install +``` diff --git a/docs/tr/laravel.md b/docs/tr/laravel.md index d1b7eee604..11db9e5882 100644 --- a/docs/tr/laravel.md +++ b/docs/tr/laravel.md @@ -19,21 +19,21 @@ Alternatif olarak, Laravel projelerinizi FrankenPHP ile yerel makinenizden çal 1. [Sisteminize karşılık gelen binary dosyayı indirin](https://github.com/dunglas/frankenphp/releases) 2. Aşağıdaki yapılandırmayı Laravel projenizin kök dizinindeki `Caddyfile` adlı bir dosyaya ekleyin: - ```caddyfile - { - frankenphp - } - - # Sunucunuzun alan adı - localhost { - # Webroot'u public/ dizinine ayarlayın - root public/ - # Sıkıştırmayı etkinleştir (isteğe bağlı) - encode zstd br gzip - # PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun - php_server - } - ``` + ```caddyfile + { + frankenphp + } + + # Sunucunuzun alan adı + localhost { + # Webroot'u public/ dizinine ayarlayın + root public/ + # Sıkıştırmayı etkinleştir (isteğe bağlı) + encode zstd br gzip + # PHP dosyalarını public/ dizininden çalıştırın ve varlıkları sunun + php_server + } + ``` 3. FrankenPHP'yi Laravel projenizin kök dizininden başlatın: `frankenphp run` @@ -59,16 +59,16 @@ php artisan octane:frankenphp `octane:frankenphp` komutu aşağıdaki seçenekleri alabilir: -* `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`) -* `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`) -* `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`) -* `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`) -* `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`) -* `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu -* `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin -* `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir) -* `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle -* `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın -* `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları +- `--host`: Sunucunun bağlanması gereken IP adresi (varsayılan: `127.0.0.1`) +- `--port`: Sunucunun erişilebilir olması gereken port (varsayılan: `8000`) +- `--admin-port`: Yönetici sunucusunun erişilebilir olması gereken port (varsayılan: `2019`) +- `--workers`: İstekleri işlemek için hazır olması gereken worker sayısı (varsayılan: `auto`) +- `--max-requests`: Sunucu yeniden yüklenmeden önce işlenecek istek sayısı (varsayılan: `500`) +- `--caddyfile`: FrankenPHP `Caddyfile` dosyasının yolu +- `--https`: HTTPS, HTTP/2 ve HTTP/3'ü etkinleştirin ve sertifikaları otomatik olarak oluşturup yenileyin +- `--http-redirect`: HTTP'den HTTPS'ye yeniden yönlendirmeyi etkinleştir (yalnızca --https geçilirse etkinleştirilir) +- `--watch`: Uygulamada kod değişikliği olduğunda sunucuyu otomatik olarak yeniden yükle +- `--poll`: Dosyaları bir ağ üzerinden izlemek için izleme sırasında dosya sistemi yoklamasını kullanın +- `--log-level`: Belirtilen günlük seviyesinde veya üzerinde günlük mesajları Laravel Octane hakkında daha fazla bilgi edinmek için [Laravel Octane resmi belgelerine](https://laravel.com/docs/octane) göz atın. diff --git a/docs/tr/mercure.md b/docs/tr/mercure.md index 43d789acde..581d486ba5 100644 --- a/docs/tr/mercure.md +++ b/docs/tr/mercure.md @@ -1,12 +1,12 @@ -# Gerçek Zamanlı - -FrankenPHP yerleşik bir [Mercure](https://mercure.rocks) hub ile birlikte gelir! -Mercure, olayları tüm bağlı cihazlara gerçek zamanlı olarak göndermeye olanak tanır: anında bir JavaScript olayı alırlar. - -JS kütüphanesi veya SDK gerekmez! - -![Mercure](../mercure-hub.png) - -Mercure hub'ını etkinleştirmek için [Mercure'ün sitesinde](https://mercure.rocks/docs/hub/config) açıklandığı gibi `Caddyfile`'ı güncelleyin. - -Mercure güncellemelerini kodunuzdan göndermek için [Symfony Mercure Bileşenini](https://symfony.com/components/Mercure) öneririz (kullanmak için Symfony tam yığın çerçevesine ihtiyacınız yoktur). +# Gerçek Zamanlı + +FrankenPHP yerleşik bir [Mercure](https://mercure.rocks) hub ile birlikte gelir! +Mercure, olayları tüm bağlı cihazlara gerçek zamanlı olarak göndermeye olanak tanır: anında bir JavaScript olayı alırlar. + +JS kütüphanesi veya SDK gerekmez! + +![Mercure](../mercure-hub.png) + +Mercure hub'ını etkinleştirmek için [Mercure'ün sitesinde](https://mercure.rocks/docs/hub/config) açıklandığı gibi `Caddyfile`'ı güncelleyin. + +Mercure güncellemelerini kodunuzdan göndermek için [Symfony Mercure Bileşenini](https://symfony.com/components/Mercure) öneririz (kullanmak için Symfony tam yığın çerçevesine ihtiyacınız yoktur). diff --git a/docs/tr/production.md b/docs/tr/production.md index 14733d7901..92f1d0096c 100644 --- a/docs/tr/production.md +++ b/docs/tr/production.md @@ -1,139 +1,139 @@ -# Production Ortamına Dağıtım - -Bu dokümanda, Docker Compose kullanarak bir PHP uygulamasını tek bir sunucuya nasıl dağıtacağımızı öğreneceğiz. - -Symfony kullanıyorsanız, Symfony Docker projesinin (FrankenPHP kullanan) "[Production ortamına dağıtım](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" dokümanını okumayı tercih edebilirsiniz. - -API Platform (FrankenPHP de kullanır) tercih ediyorsanız, [çerçevenin dağıtım dokümanına](https://api-platform.com/docs/deployment/) bakabilirsiniz. - -## Uygulamanızı Hazırlama - -İlk olarak, PHP projenizin kök dizininde bir `Dockerfile` oluşturun: - -```dockerfile -FROM dunglas/frankenphp - -# "your-domain-name.example.com" yerine kendi alan adınızı yazdığınızdan emin olun -ENV SERVER_NAME=your-domain-name.example.com -# HTTPS'yi devre dışı bırakmak istiyorsanız, bunun yerine bu değeri kullanın: -#ENV SERVER_NAME=:80 - -# PHP production ayarlarını etkinleştirin -RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" - -# Projenizin PHP dosyalarını genel dizine kopyalayın -COPY . /app/public -# Symfony veya Laravel kullanıyorsanız, bunun yerine tüm projeyi kopyalamanız gerekir: -#COPY . /app -``` - -Daha fazla ayrıntı ve seçenek için "[Özel Docker İmajı Oluşturma](docker.md)" bölümüne bakın, -ve yapılandırmayı nasıl özelleştireceğinizi öğrenmek için PHP eklentilerini ve Caddy modüllerini yükleyin. - -Projeniz Composer kullanıyorsa, -Docker imajına dahil ettiğinizden ve bağımlılıklarınızı yüklediğinizden emin olun. - -Ardından, bir `compose.yaml` dosyası ekleyin: - -```yaml -services: - php: - image: dunglas/frankenphp - restart: always - ports: - - "80:80" # HTTP - - "443:443" # HTTPS - - "443:443/udp" # HTTP/3 - volumes: - - caddy_data:/data - - caddy_config:/config - -# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes) -volumes: - caddy_data: - caddy_config: -``` - -> [!NOTE] -> -> Önceki örnekler production kullanımı için tasarlanmıştır. -> Geliştirme aşamasında, bir yığın (volume), farklı bir PHP yapılandırması ve `SERVER_NAME` ortam değişkeni için farklı bir değer kullanmak isteyebilirsiniz. -> -> (FrankenPHP kullanan) çok aşamalı Composer, ekstra PHP eklentileri vb. içeren imajlara başvuran daha gelişmiş bir örnek için [Symfony Docker](https://github.com/dunglas/symfony-docker) projesine bir göz atın. - -Son olarak, eğer Git kullanıyorsanız, bu dosyaları commit edin ve push edin. - -## Sunucu Hazırlama - -Uygulamanızı production ortamına dağıtmak için bir sunucuya ihtiyacınız vardır. -Bu dokümanda, DigitalOcean tarafından sağlanan bir sanal makine kullanacağız, ancak herhangi bir Linux sunucusu çalışabilir. -Docker yüklü bir Linux sunucunuz varsa, doğrudan [bir sonraki bölüme](#alan-adı-yapılandırma) geçebilirsiniz. - -Aksi takdirde, 200 $ ücretsiz kredi almak için [bu ortaklık bağlantısını](https://m.do.co/c/5d8aabe3ab80) kullanın, bir hesap oluşturun ve ardından "Create a Droplet" seçeneğine tıklayın. -Ardından, "Bir imaj seçin" bölümünün altındaki "Marketplace" sekmesine tıklayın ve "Docker" adlı uygulamayı bulun. -Bu, Docker ve Docker Compose'un en son sürümlerinin zaten yüklü olduğu bir Ubuntu sunucusu sağlayacaktır! - -Test amaçlı kullanım için en ucuz planlar yeterli olacaktır. -Gerçek production kullanımı için, muhtemelen ihtiyaçlarınıza uyacak şekilde "genel amaçlı" bölümünden bir plan seçmek isteyeceksiniz. - -![Docker ile DigitalOcean FrankenPHP](../digitalocean-droplet.png) - -Diğer ayarlar için varsayılanları koruyabilir veya ihtiyaçlarınıza göre değiştirebilirsiniz. -SSH anahtarınızı eklemeyi veya bir parola oluşturmayı unutmayın, ardından "Sonlandır ve oluştur" düğmesine basın. - -Ardından, Droplet'iniz hazırlanırken birkaç saniye bekleyin. -Droplet'iniz hazır olduğunda, bağlanmak için SSH kullanın: - -```console -ssh root@ -``` - -## Alan Adı Yapılandırma - -Çoğu durumda sitenizle bir alan adını ilişkilendirmek isteyeceksiniz. -Henüz bir alan adınız yoksa, bir kayıt şirketi aracılığıyla bir alan adı satın almanız gerekir. - -Daha sonra alan adınız için sunucunuzun IP adresini işaret eden `A` türünde bir DNS kaydı oluşturun: - -```dns -your-domain-name.example.com. IN A 207.154.233.113 -``` - -DigitalOcean Alan Adları hizmetiyle ilgili örnek ("Networking" > "Domains"): - -![DigitalOcean'da DNS Yapılandırma](../digitalocean-dns.png) - -> [!NOTE] -> -> FrankenPHP tarafından varsayılan olarak otomatik olarak TLS sertifikası oluşturmak için kullanılan hizmet olan Let's Encrypt, direkt IP adreslerinin kullanılmasını desteklemez. Let's Encrypt'i kullanmak için alan adı kullanmak zorunludur. - -## Dağıtım - -Projenizi `git clone`, `scp` veya ihtiyacınıza uygun başka bir araç kullanarak sunucuya kopyalayın. -GitHub kullanıyorsanız [bir dağıtım anahtarı](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys) kullanmak isteyebilirsiniz. -Dağıtım anahtarları ayrıca [GitLab tarafından desteklenir](https://docs.gitlab.com/ee/user/project/deploy_keys/). - -Git ile örnek: - -```console -git clone git@github.com:/.git -``` - -Projenizi içeren dizine gidin (``) ve uygulamayı production modunda başlatın: - -```console -docker compose up -d --wait -``` - -Sunucunuz hazır ve çalışıyor. Sizin için otomatik olarak bir HTTPS sertifikası oluşturuldu. -`https://your-domain-name.example.com` adresine gidin ve keyfini çıkarın! - -> [!CAUTION] -> -> Docker bir önbellek katmanına sahip olabilir, her dağıtım için doğru derlemeye sahip olduğunuzdan emin olun veya önbellek sorununu önlemek için projenizi `--no-cache` seçeneği ile yeniden oluşturun. - -## Birden Fazla Düğümde Dağıtım - -Uygulamanızı bir makine kümesine dağıtmak istiyorsanız, [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/) kullanabilirsiniz, -sağlanan Compose dosyaları ile uyumludur. -Kubernetes üzerinde dağıtım yapmak için FrankenPHP kullanan [API Platformu ile sağlanan Helm grafiğine](https://api-platform.com/docs/deployment/kubernetes/) göz atın. +# Production Ortamına Dağıtım + +Bu dokümanda, Docker Compose kullanarak bir PHP uygulamasını tek bir sunucuya nasıl dağıtacağımızı öğreneceğiz. + +Symfony kullanıyorsanız, Symfony Docker projesinin (FrankenPHP kullanan) "[Production ortamına dağıtım](https://github.com/dunglas/symfony-docker/blob/main/docs/production.md)" dokümanını okumayı tercih edebilirsiniz. + +API Platform (FrankenPHP de kullanır) tercih ediyorsanız, [çerçevenin dağıtım dokümanına](https://api-platform.com/docs/deployment/) bakabilirsiniz. + +## Uygulamanızı Hazırlama + +İlk olarak, PHP projenizin kök dizininde bir `Dockerfile` oluşturun: + +```dockerfile +FROM dunglas/frankenphp + +# "your-domain-name.example.com" yerine kendi alan adınızı yazdığınızdan emin olun +ENV SERVER_NAME=your-domain-name.example.com +# HTTPS'yi devre dışı bırakmak istiyorsanız, bunun yerine bu değeri kullanın: +#ENV SERVER_NAME=:80 + +# PHP production ayarlarını etkinleştirin +RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" + +# Projenizin PHP dosyalarını genel dizine kopyalayın +COPY . /app/public +# Symfony veya Laravel kullanıyorsanız, bunun yerine tüm projeyi kopyalamanız gerekir: +#COPY . /app +``` + +Daha fazla ayrıntı ve seçenek için "[Özel Docker İmajı Oluşturma](docker.md)" bölümüne bakın, +ve yapılandırmayı nasıl özelleştireceğinizi öğrenmek için PHP eklentilerini ve Caddy modüllerini yükleyin. + +Projeniz Composer kullanıyorsa, +Docker imajına dahil ettiğinizden ve bağımlılıklarınızı yüklediğinizden emin olun. + +Ardından, bir `compose.yaml` dosyası ekleyin: + +```yaml +services: + php: + image: dunglas/frankenphp + restart: always + ports: + - "80:80" # HTTP + - "443:443" # HTTPS + - "443:443/udp" # HTTP/3 + volumes: + - caddy_data:/data + - caddy_config:/config + +# Caddy sertifikaları ve yapılandırması için gereken yığınlar (volumes) +volumes: + caddy_data: + caddy_config: +``` + +> [!NOTE] +> +> Önceki örnekler production kullanımı için tasarlanmıştır. +> Geliştirme aşamasında, bir yığın (volume), farklı bir PHP yapılandırması ve `SERVER_NAME` ortam değişkeni için farklı bir değer kullanmak isteyebilirsiniz. +> +> (FrankenPHP kullanan) çok aşamalı Composer, ekstra PHP eklentileri vb. içeren imajlara başvuran daha gelişmiş bir örnek için [Symfony Docker](https://github.com/dunglas/symfony-docker) projesine bir göz atın. + +Son olarak, eğer Git kullanıyorsanız, bu dosyaları commit edin ve push edin. + +## Sunucu Hazırlama + +Uygulamanızı production ortamına dağıtmak için bir sunucuya ihtiyacınız vardır. +Bu dokümanda, DigitalOcean tarafından sağlanan bir sanal makine kullanacağız, ancak herhangi bir Linux sunucusu çalışabilir. +Docker yüklü bir Linux sunucunuz varsa, doğrudan [bir sonraki bölüme](#alan-adı-yapılandırma) geçebilirsiniz. + +Aksi takdirde, 200 $ ücretsiz kredi almak için [bu ortaklık bağlantısını](https://m.do.co/c/5d8aabe3ab80) kullanın, bir hesap oluşturun ve ardından "Create a Droplet" seçeneğine tıklayın. +Ardından, "Bir imaj seçin" bölümünün altındaki "Marketplace" sekmesine tıklayın ve "Docker" adlı uygulamayı bulun. +Bu, Docker ve Docker Compose'un en son sürümlerinin zaten yüklü olduğu bir Ubuntu sunucusu sağlayacaktır! + +Test amaçlı kullanım için en ucuz planlar yeterli olacaktır. +Gerçek production kullanımı için, muhtemelen ihtiyaçlarınıza uyacak şekilde "genel amaçlı" bölümünden bir plan seçmek isteyeceksiniz. + +![Docker ile DigitalOcean FrankenPHP](../digitalocean-droplet.png) + +Diğer ayarlar için varsayılanları koruyabilir veya ihtiyaçlarınıza göre değiştirebilirsiniz. +SSH anahtarınızı eklemeyi veya bir parola oluşturmayı unutmayın, ardından "Sonlandır ve oluştur" düğmesine basın. + +Ardından, Droplet'iniz hazırlanırken birkaç saniye bekleyin. +Droplet'iniz hazır olduğunda, bağlanmak için SSH kullanın: + +```console +ssh root@ +``` + +## Alan Adı Yapılandırma + +Çoğu durumda sitenizle bir alan adını ilişkilendirmek isteyeceksiniz. +Henüz bir alan adınız yoksa, bir kayıt şirketi aracılığıyla bir alan adı satın almanız gerekir. + +Daha sonra alan adınız için sunucunuzun IP adresini işaret eden `A` türünde bir DNS kaydı oluşturun: + +```dns +your-domain-name.example.com. IN A 207.154.233.113 +``` + +DigitalOcean Alan Adları hizmetiyle ilgili örnek ("Networking" > "Domains"): + +![DigitalOcean'da DNS Yapılandırma](../digitalocean-dns.png) + +> [!NOTE] +> +> FrankenPHP tarafından varsayılan olarak otomatik olarak TLS sertifikası oluşturmak için kullanılan hizmet olan Let's Encrypt, direkt IP adreslerinin kullanılmasını desteklemez. Let's Encrypt'i kullanmak için alan adı kullanmak zorunludur. + +## Dağıtım + +Projenizi `git clone`, `scp` veya ihtiyacınıza uygun başka bir araç kullanarak sunucuya kopyalayın. +GitHub kullanıyorsanız [bir dağıtım anahtarı](https://docs.github.com/en/free-pro-team@latest/developers/overview/managing-deploy-keys#deploy-keys) kullanmak isteyebilirsiniz. +Dağıtım anahtarları ayrıca [GitLab tarafından desteklenir](https://docs.gitlab.com/ee/user/project/deploy_keys/). + +Git ile örnek: + +```console +git clone git@github.com:/.git +``` + +Projenizi içeren dizine gidin (``) ve uygulamayı production modunda başlatın: + +```console +docker compose up -d --wait +``` + +Sunucunuz hazır ve çalışıyor. Sizin için otomatik olarak bir HTTPS sertifikası oluşturuldu. +`https://your-domain-name.example.com` adresine gidin ve keyfini çıkarın! + +> [!CAUTION] +> +> Docker bir önbellek katmanına sahip olabilir, her dağıtım için doğru derlemeye sahip olduğunuzdan emin olun veya önbellek sorununu önlemek için projenizi `--no-cache` seçeneği ile yeniden oluşturun. + +## Birden Fazla Düğümde Dağıtım + +Uygulamanızı bir makine kümesine dağıtmak istiyorsanız, [Docker Swarm](https://docs.docker.com/engine/swarm/stack-deploy/) kullanabilirsiniz, +sağlanan Compose dosyaları ile uyumludur. +Kubernetes üzerinde dağıtım yapmak için FrankenPHP kullanan [API Platformu ile sağlanan Helm grafiğine](https://api-platform.com/docs/deployment/kubernetes/) göz atın. diff --git a/docs/tr/static.md b/docs/tr/static.md index 89095b3ca9..395fedb380 100644 --- a/docs/tr/static.md +++ b/docs/tr/static.md @@ -1,100 +1,100 @@ -# Statik Yapı Oluşturun - -PHP kütüphanesinin yerel kurulumunu kullanmak yerine, -harika [static-php-cli projesi](https://github.com/crazywhalecc/static-php-cli) sayesinde FrankenPHP'nin statik bir yapısını oluşturmak mümkündür (adına rağmen, bu proje sadece CLI'yi değil, tüm SAPI'leri destekler). - -Bu yöntemle, tek, taşınabilir bir ikili PHP yorumlayıcısını, Caddy web sunucusunu ve FrankenPHP'yi içerecektir! - -FrankenPHP ayrıca [PHP uygulamasının statik binary gömülmesini](embed.md) destekler. - -## Linux - -Linux statik binary dosyası oluşturmak için bir Docker imajı sağlıyoruz: - -```console -docker buildx bake --load static-builder -docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder -``` - -Elde edilen statik binary `frankenphp` olarak adlandırılır ve geçerli dizinde kullanılabilir. - -Statik binary dosyasını Docker olmadan oluşturmak istiyorsanız, Linux için de çalışan macOS talimatlarına bir göz atın. - -### Özel Eklentiler - -Varsayılan olarak, en popüler PHP eklentileri zaten derlenir. - -Binary dosyanın boyutunu küçültmek ve saldırı yüzeyini azaltmak için `PHP_EXTENSIONS` Docker ARG'sini kullanarak derlenecek eklentilerin listesini seçebilirsiniz. - -Örneğin, yalnızca `opcache` eklentisini derlemek için aşağıdaki komutu çalıştırın: - -```console -docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder -# ... -``` - -Etkinleştirdiğiniz eklentilere ek işlevler sağlayan kütüphaneler eklemek için `PHP_EXTENSION_LIBS` Docker ARG'sini kullanabilirsiniz: - -```console -docker buildx bake \ - --load \ - --set static-builder.args.PHP_EXTENSIONS=gd \ - --set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \ - static-builder -``` - -### Ekstra Caddy Modülleri - -Ekstra Caddy modülleri eklemek veya [xcaddy](https://github.com/caddyserver/xcaddy) adresine başka argümanlar iletmek için `XCADDY_ARGS` Docker ARG'sini kullanın: - -```console -docker buildx bake \ - --load \ - --set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \ - static-builder -``` - -Bu örnekte, Caddy için [Souin](https://souin.io) HTTP önbellek modülünün yanı sıra [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) ve [Vulcain](https://vulcain.rocks) modüllerini ekliyoruz. - -> [!TIP] -> -> cbrotli, Mercure ve Vulcain modülleri, `XCADDY_ARGS` boşsa veya ayarlanmamışsa varsayılan olarak dahil edilir. -> Eğer `XCADDY_ARGS` değerini özelleştirirseniz, dahil edilmelerini istiyorsanız bunları açıkça dahil etmelisiniz. - -Derlemeyi nasıl [özelleştireceğinize](#yapıyı-özelleştirme) de bakın. - -### GitHub Token - -GitHub API kullanım limitine ulaşırsanız, `GITHUB_TOKEN` adlı bir ortam değişkeninde bir GitHub Personal Access Token ayarlayın: - -```console -GITHUB_TOKEN="xxx" docker --load buildx bake static-builder -# ... -``` - -## macOS - -macOS için statik bir binary oluşturmak için aşağıdaki betiği çalıştırın ([Homebrew](https://brew.sh/) yüklü olmalıdır): - -```console -git clone https://github.com/dunglas/frankenphp -cd frankenphp -./build-static.sh -``` - -Not: Bu betik Linux'ta (ve muhtemelen diğer Unix'lerde) da çalışır ve sağladığımız Docker tabanlı statik derleyici tarafından dahili olarak kullanılır. - -## Yapıyı Özelleştirme - -Aşağıdaki ortam değişkenleri `docker build` ve `build-static.sh` dosyalarına aktarılabilir -statik derlemeyi özelleştirmek için betik: - -* `FRANKENPHP_VERSION`: kullanılacak FrankenPHP sürümü -* `PHP_VERSION`: kullanılacak PHP sürümü -* `PHP_EXTENSIONS`: oluşturulacak PHP eklentileri ([desteklenen eklentiler listesi](https://static-php.dev/en/guide/extensions.html)) -* `PHP_EXTENSION_LIBS`: eklentilere özellikler ekleyen oluşturulacak ekstra kütüphaneler -* `XCADDY_ARGS`: [xcaddy](https://github.com/caddyserver/xcaddy) adresine iletilecek argümanlar, örneğin ekstra Caddy modülleri eklemek için -* `EMBED`: binary dosyaya gömülecek PHP uygulamasının yolu -* `CLEAN`: ayarlandığında, libphp ve tüm bağımlılıkları sıfırdan oluşturulur (önbellek yok) -* `DEBUG_SYMBOLS`: ayarlandığında, hata ayıklama sembolleri ayıklanmayacak ve binary dosyaya eklenecektir -* `RELEASE`: (yalnızca bakımcılar) ayarlandığında, ortaya çıkan binary dosya GitHub'a yüklenecektir +# Statik Yapı Oluşturun + +PHP kütüphanesinin yerel kurulumunu kullanmak yerine, +harika [static-php-cli projesi](https://github.com/crazywhalecc/static-php-cli) sayesinde FrankenPHP'nin statik bir yapısını oluşturmak mümkündür (adına rağmen, bu proje sadece CLI'yi değil, tüm SAPI'leri destekler). + +Bu yöntemle, tek, taşınabilir bir ikili PHP yorumlayıcısını, Caddy web sunucusunu ve FrankenPHP'yi içerecektir! + +FrankenPHP ayrıca [PHP uygulamasının statik binary gömülmesini](embed.md) destekler. + +## Linux + +Linux statik binary dosyası oluşturmak için bir Docker imajı sağlıyoruz: + +```console +docker buildx bake --load static-builder +docker cp $(docker create --name static-builder-musl dunglas/frankenphp:static-builder-musl):/go/src/app/dist/frankenphp-linux-$(uname -m) frankenphp ; docker rm static-builder +``` + +Elde edilen statik binary `frankenphp` olarak adlandırılır ve geçerli dizinde kullanılabilir. + +Statik binary dosyasını Docker olmadan oluşturmak istiyorsanız, Linux için de çalışan macOS talimatlarına bir göz atın. + +### Özel Eklentiler + +Varsayılan olarak, en popüler PHP eklentileri zaten derlenir. + +Binary dosyanın boyutunu küçültmek ve saldırı yüzeyini azaltmak için `PHP_EXTENSIONS` Docker ARG'sini kullanarak derlenecek eklentilerin listesini seçebilirsiniz. + +Örneğin, yalnızca `opcache` eklentisini derlemek için aşağıdaki komutu çalıştırın: + +```console +docker buildx bake --load --set static-builder.args.PHP_EXTENSIONS=opcache,pdo_sqlite static-builder +# ... +``` + +Etkinleştirdiğiniz eklentilere ek işlevler sağlayan kütüphaneler eklemek için `PHP_EXTENSION_LIBS` Docker ARG'sini kullanabilirsiniz: + +```console +docker buildx bake \ + --load \ + --set static-builder.args.PHP_EXTENSIONS=gd \ + --set static-builder.args.PHP_EXTENSION_LIBS=libjpeg,libwebp \ + static-builder +``` + +### Ekstra Caddy Modülleri + +Ekstra Caddy modülleri eklemek veya [xcaddy](https://github.com/caddyserver/xcaddy) adresine başka argümanlar iletmek için `XCADDY_ARGS` Docker ARG'sini kullanın: + +```console +docker buildx bake \ + --load \ + --set static-builder.args.XCADDY_ARGS="--with github.com/darkweak/souin/plugins/caddy --with github.com/dunglas/caddy-cbrotli --with github.com/dunglas/mercure/caddy --with github.com/dunglas/vulcain/caddy" \ + static-builder +``` + +Bu örnekte, Caddy için [Souin](https://souin.io) HTTP önbellek modülünün yanı sıra [cbrotli](https://github.com/dunglas/caddy-cbrotli), [Mercure](https://mercure.rocks) ve [Vulcain](https://vulcain.rocks) modüllerini ekliyoruz. + +> [!TIP] +> +> cbrotli, Mercure ve Vulcain modülleri, `XCADDY_ARGS` boşsa veya ayarlanmamışsa varsayılan olarak dahil edilir. +> Eğer `XCADDY_ARGS` değerini özelleştirirseniz, dahil edilmelerini istiyorsanız bunları açıkça dahil etmelisiniz. + +Derlemeyi nasıl [özelleştireceğinize](#yapıyı-özelleştirme) de bakın. + +### GitHub Token + +GitHub API kullanım limitine ulaşırsanız, `GITHUB_TOKEN` adlı bir ortam değişkeninde bir GitHub Personal Access Token ayarlayın: + +```console +GITHUB_TOKEN="xxx" docker --load buildx bake static-builder +# ... +``` + +## macOS + +macOS için statik bir binary oluşturmak için aşağıdaki betiği çalıştırın ([Homebrew](https://brew.sh/) yüklü olmalıdır): + +```console +git clone https://github.com/dunglas/frankenphp +cd frankenphp +./build-static.sh +``` + +Not: Bu betik Linux'ta (ve muhtemelen diğer Unix'lerde) da çalışır ve sağladığımız Docker tabanlı statik derleyici tarafından dahili olarak kullanılır. + +## Yapıyı Özelleştirme + +Aşağıdaki ortam değişkenleri `docker build` ve `build-static.sh` dosyalarına aktarılabilir +statik derlemeyi özelleştirmek için betik: + +- `FRANKENPHP_VERSION`: kullanılacak FrankenPHP sürümü +- `PHP_VERSION`: kullanılacak PHP sürümü +- `PHP_EXTENSIONS`: oluşturulacak PHP eklentileri ([desteklenen eklentiler listesi](https://static-php.dev/en/guide/extensions.html)) +- `PHP_EXTENSION_LIBS`: eklentilere özellikler ekleyen oluşturulacak ekstra kütüphaneler +- `XCADDY_ARGS`: [xcaddy](https://github.com/caddyserver/xcaddy) adresine iletilecek argümanlar, örneğin ekstra Caddy modülleri eklemek için +- `EMBED`: binary dosyaya gömülecek PHP uygulamasının yolu +- `CLEAN`: ayarlandığında, libphp ve tüm bağımlılıkları sıfırdan oluşturulur (önbellek yok) +- `DEBUG_SYMBOLS`: ayarlandığında, hata ayıklama sembolleri ayıklanmayacak ve binary dosyaya eklenecektir +- `RELEASE`: (yalnızca bakımcılar) ayarlandığında, ortaya çıkan binary dosya GitHub'a yüklenecektir diff --git a/docs/tr/worker.md b/docs/tr/worker.md index 24b75b55b9..b016b62b81 100644 --- a/docs/tr/worker.md +++ b/docs/tr/worker.md @@ -1,121 +1,124 @@ -# FrankenPHP Worker'ları Kullanma - -Uygulamanızı bir kez önyükleyin ve bellekte tutun. -FrankenPHP gelen istekleri birkaç milisaniye içinde halledecektir. - -## Çalışan Komut Dosyalarının Başlatılması - -### Docker - -`FRANKENPHP_CONFIG` ortam değişkeninin değerini `worker /path/to/your/worker/script.php` olarak ayarlayın: - -```console -docker run \ - -e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \ - -v $PWD:/app \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -### Binary Çıktısı - -Geçerli dizinin içeriğini bir worker kullanarak sunmak için `php-server` komutunun `--worker` seçeneğini kullanın: - -```console -frankenphp php-server --worker /path/to/your/worker/script.php -``` - -PHP uygulamanız [binary dosyaya gömülü](embed.md) ise, uygulamanın kök dizinine özel bir `Caddyfile` ekleyebilirsiniz. -Otomatik olarak kullanılacaktır. - -## Symfony Çalışma Zamanı - -FrankenPHP'nin worker modu [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html) tarafından desteklenmektedir. -Herhangi bir Symfony uygulamasını bir worker'da başlatmak için [PHP Runtime](https://github.com/php-runtime/runtime)'ın FrankenPHP paketini yükleyin: - -```console -composer require runtime/frankenphp-symfony -``` - -FrankenPHP Symfony Runtime'ı kullanmak için `APP_RUNTIME` ortam değişkenini tanımlayarak uygulama sunucunuzu başlatın: - -```console -docker run \ - -e FRANKENPHP_CONFIG="worker ./public/index.php" \ - -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \ - -v $PWD:/app \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -## Laravel Octane - -Bkz. [ilgili doküman](laravel.md#laravel-octane). - -## Özel Uygulamalar - -Aşağıdaki örnek, üçüncü taraf bir kütüphaneye güvenmeden kendi çalışan kodunuzu nasıl oluşturacağınızı göstermektedir: - -```php -boot(); - -// Daha iyi performans için döngü dışında işleyici (daha az iş yapıyor) -$handler = static function () use ($myApp) { - // Bir istek alındığında çağrılır, - // superglobals, php://input ve benzerleri sıfırlanır - echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER); -}; - -for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) { - $running = \frankenphp_handle_request($handler); - - // HTTP yanıtını gönderdikten sonra bir şey yapın - $myApp->terminate(); - - // Bir sayfa oluşturmanın ortasında tetiklenme olasılığını azaltmak için çöp toplayıcıyı çağırın - gc_collect_cycles(); -} - -// Temizleme -$myApp->shutdown(); -``` - -Ardından, uygulamanızı başlatın ve çalışanınızı yapılandırmak için `FRANKENPHP_CONFIG` ortam değişkenini kullanın: - -```console -docker run \ - -e FRANKENPHP_CONFIG="worker ./public/index.php" \ - -v $PWD:/app \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -Varsayılan olarak, CPU başına 2 worker başlatılır. -Başlatılacak worker sayısını da yapılandırabilirsiniz: - -```console -docker run \ - -e FRANKENPHP_CONFIG="worker ./public/index.php 42" \ - -v $PWD:/app \ - -p 80:80 -p 443:443 -p 443:443/udp \ - dunglas/frankenphp -``` - -### Belirli Sayıda İstekten Sonra Worker'ı Yeniden Başlatın - - -PHP başlangıçta uzun süreli işlemler için tasarlanmadığından, hala bellek sızdıran birçok kütüphane ve eski kod vardır. - -Bu tür kodları worker modunda kullanmak için geçici bir çözüm, belirli sayıda isteği işledikten sonra worker betiğini yeniden başlatmaktır: - -Önceki worker kod parçacığı, `MAX_REQUESTS` adlı bir ortam değişkeni ayarlayarak işlenecek maksimum istek sayısını yapılandırmaya izin verir. +# FrankenPHP Worker'ları Kullanma + +Uygulamanızı bir kez önyükleyin ve bellekte tutun. +FrankenPHP gelen istekleri birkaç milisaniye içinde halledecektir. + +## Çalışan Komut Dosyalarının Başlatılması + +### Docker + +`FRANKENPHP_CONFIG` ortam değişkeninin değerini `worker /path/to/your/worker/script.php` olarak ayarlayın: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +### Binary Çıktısı + +Geçerli dizinin içeriğini bir worker kullanarak sunmak için `php-server` komutunun `--worker` seçeneğini kullanın: + +```console +frankenphp php-server --worker /path/to/your/worker/script.php +``` + +PHP uygulamanız [binary dosyaya gömülü](embed.md) ise, uygulamanın kök dizinine özel bir `Caddyfile` ekleyebilirsiniz. +Otomatik olarak kullanılacaktır. + +## Symfony Çalışma Zamanı + +FrankenPHP'nin worker modu [Symfony Runtime Component](https://symfony.com/doc/current/components/runtime.html) tarafından desteklenmektedir. +Herhangi bir Symfony uygulamasını bir worker'da başlatmak için [PHP Runtime](https://github.com/php-runtime/runtime)'ın FrankenPHP paketini yükleyin: + +```console +composer require runtime/frankenphp-symfony +``` + +FrankenPHP Symfony Runtime'ı kullanmak için `APP_RUNTIME` ortam değişkenini tanımlayarak uygulama sunucunuzu başlatın: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker ./public/index.php" \ + -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +## Laravel Octane + +Bkz. [ilgili doküman](laravel.md#laravel-octane). + +## Özel Uygulamalar + +Aşağıdaki örnek, üçüncü taraf bir kütüphaneye güvenmeden kendi çalışan kodunuzu nasıl oluşturacağınızı göstermektedir: + +```php +boot(); + +// Daha iyi performans için döngü dışında işleyici (daha az iş yapıyor) +$handler = static function () use ($myApp) { + // Bir istek alındığında çağrılır, + // superglobals, php://input ve benzerleri sıfırlanır + echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER); +}; + +for ($nbRequests = 0, $running = true; isset($_SERVER['MAX_REQUESTS']) && ($nbRequests < ((int)$_SERVER['MAX_REQUESTS'])) && $running; ++$nbRequests) { + $running = \frankenphp_handle_request($handler); + + // HTTP yanıtını gönderdikten sonra bir şey yapın + $myApp->terminate(); + + // Bir sayfa oluşturmanın ortasında tetiklenme olasılığını azaltmak için çöp toplayıcıyı çağırın + gc_collect_cycles(); +} + +// Temizleme +$myApp->shutdown(); +``` + +Ardından, uygulamanızı başlatın ve çalışanınızı yapılandırmak için `FRANKENPHP_CONFIG` ortam değişkenini kullanın: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker ./public/index.php" \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +Varsayılan olarak, CPU başına 2 worker başlatılır. +Başlatılacak worker sayısını da yapılandırabilirsiniz: + +```console +docker run \ + -e FRANKENPHP_CONFIG="worker ./public/index.php 42" \ + -v $PWD:/app \ + -p 80:80 -p 443:443 -p 443:443/udp \ + dunglas/frankenphp +``` + +### Belirli Sayıda İstekten Sonra Worker'ı Yeniden Başlatın + + + +PHP başlangıçta uzun süreli işlemler için tasarlanmadığından, hala bellek sızdıran birçok kütüphane ve eski kod vardır. + + + +Bu tür kodları worker modunda kullanmak için geçici bir çözüm, belirli sayıda isteği işledikten sonra worker betiğini yeniden başlatmaktır: + +Önceki worker kod parçacığı, `MAX_REQUESTS` adlı bir ortam değişkeni ayarlayarak işlenecek maksimum istek sayısını yapılandırmaya izin verir. diff --git a/docs/worker.md b/docs/worker.md index 5935bfac07..3188196efa 100644 --- a/docs/worker.md +++ b/docs/worker.md @@ -141,7 +141,7 @@ curl -X POST http://localhost:2019/frankenphp/workers/restart ### Worker Failures If a worker script crashes with a non-zero exit code, FrankenPHP will restart it with an exponential backoff strategy. -If the worker script stays up longer than the last backoff * 2, +If the worker script stays up longer than the last backoff \* 2, it will not penalize the worker script and restart it again. However, if the worker script continues to fail with a non-zero exit code in a short period of time (for example, having a typo in a script), FrankenPHP will crash with the error: `too many consecutive failures`. @@ -151,8 +151,8 @@ However, if the worker script continues to fail with a non-zero exit code in a s [PHP superglobals](https://www.php.net/manual/en/language.variables.superglobals.php) (`$_SERVER`, `$_ENV`, `$_GET`...) behave as follows: -* before the first call to `frankenphp_handle_request()`, superglobals contain values bound to the worker script itself -* during and after the call to `frankenphp_handle_request()`, superglobals contain values generated from the processed HTTP request, each call to `frankenphp_handle_request()` changes the superglobals values +- before the first call to `frankenphp_handle_request()`, superglobals contain values bound to the worker script itself +- during and after the call to `frankenphp_handle_request()`, superglobals contain values generated from the processed HTTP request, each call to `frankenphp_handle_request()` changes the superglobals values To access the superglobals of the worker script inside the callback, you must copy them and import the copy in the scope of the callback: From 0bbd4c660904149820e45c4e8880cd0a9f020591 Mon Sep 17 00:00:00 2001 From: Marc Date: Wed, 23 Apr 2025 14:44:02 +0700 Subject: [PATCH 37/51] fix: build-static.sh consecutive builds (#1496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix consecutive builds * use minor version in PHP_VERSION * install jq in centos container * fix "arm64" download arch for spc binary * jq is not available as a rpm download * linter * specify php 8.4 default specify 8.4 so we manually switch to 8.5 when we make sure it works allows to run without jq installed * Apply suggestions from code review Co-authored-by: Kévin Dunglas --------- Co-authored-by: Kévin Dunglas --- build-static.sh | 151 +++++++++++++++++++--------------- static-builder-gnu.Dockerfile | 3 + 2 files changed, 86 insertions(+), 68 deletions(-) diff --git a/build-static.sh b/build-static.sh index 58b4b6dd0e..f5c62474d3 100755 --- a/build-static.sh +++ b/build-static.sh @@ -57,7 +57,20 @@ if [ -n "${DEBUG_SYMBOLS}" ]; then fi # php version to build if [ -z "${PHP_VERSION}" ]; then - export PHP_VERSION="8.4" + get_latest_php_version() { + input="$1" + json=$(curl -s "https://www.php.net/releases/index.php?json&version=$input") + latest=$(echo "$json" | jq -r '.version') + + if [[ "$latest" == "$input"* ]]; then + echo "$latest" + else + echo "$input" + fi + } + + PHP_VERSION="$(get_latest_php_version "8.4")" + export PHP_VERSION fi # default extension set defaultExtensions="apcu,bcmath,bz2,calendar,ctype,curl,dba,dom,exif,fileinfo,filter,ftp,gd,gmp,gettext,iconv,igbinary,imagick,intl,ldap,mbregex,mbstring,mysqli,mysqlnd,opcache,openssl,parallel,pcntl,pdo,pdo_mysql,pdo_pgsql,pdo_sqlite,pgsql,phar,posix,protobuf,readline,redis,session,shmop,simplexml,soap,sockets,sodium,sqlite3,ssh2,sysvmsg,sysvsem,sysvshm,tidy,tokenizer,xlswriter,xml,xmlreader,xmlwriter,zip,zlib,yaml,zstd" @@ -116,88 +129,90 @@ if [ -n "${CLEAN}" ]; then go clean -cache fi -cache_key="${PHP_VERSION}-${PHP_EXTENSIONS}-${PHP_EXTENSION_LIBS}" +mkdir -p dist/ +cd dist/ -# Build libphp if necessary -if [ -f dist/cache_key ] && [ "$(cat dist/cache_key)" = "${cache_key}" ] && [ -f "dist/static-php-cli/buildroot/lib/libphp.a" ]; then - cd dist/static-php-cli - - if [ -f "./spc" ]; then - spcCommand="./spc" - elif [ -f "bin/spc" ]; then - spcCommand="./bin/spc" +if type "brew" >/dev/null 2>&1; then + if ! type "composer" >/dev/null; then + packages="composer" fi -else - mkdir -p dist/ - cd dist/ - echo -n "${cache_key}" >cache_key - - if type "brew" >/dev/null 2>&1; then - if ! type "composer" >/dev/null; then - packages="composer" - fi - if ! type "go" >/dev/null 2>&1; then - packages="${packages} go" - fi - if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then - packages="${packages} gh" - fi - - if [ -n "${packages}" ]; then - # shellcheck disable=SC2086 - brew install --formula --quiet ${packages} - fi + if ! type "go" >/dev/null 2>&1; then + packages="${packages} go" fi - - if [ "${SPC_REL_TYPE}" = "binary" ] && [[ ! "${arch}" =~ arm ]]; then - mkdir -p static-php-cli/ - cd static-php-cli/ - curl -o spc -fsSL "https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-${arch}" - chmod +x spc - spcCommand="./spc" - elif [ -d "static-php-cli/src" ]; then - cd static-php-cli/ - git pull - composer install --no-dev -a - spcCommand="./bin/spc" - else - git clone --depth 1 https://github.com/crazywhalecc/static-php-cli --branch main - cd static-php-cli/ - composer install --no-dev -a - spcCommand="./bin/spc" + if [ -n "${RELEASE}" ] && ! type "gh" >/dev/null 2>&1; then + packages="${packages} gh" fi - # extensions to build - if [ -z "${PHP_EXTENSIONS}" ]; then - # enable EMBED mode, first check if project has dumped extensions - if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ] && [ -f "${EMBED}/composer.lock" ] && [ -f "${EMBED}/vendor/installed.json" ]; then - cd "${EMBED}" - # read the extensions using spc dump-extensions - PHP_EXTENSIONS=$(${spcCommand} dump-extensions "${EMBED}" --format=text --no-dev --no-ext-output="${defaultExtensions}") - else - PHP_EXTENSIONS="${defaultExtensions}" - fi + if [ -n "${packages}" ]; then + # shellcheck disable=SC2086 + brew install --formula --quiet ${packages} fi - # additional libs to build - if [ -z "${PHP_EXTENSION_LIBS}" ]; then - PHP_EXTENSION_LIBS="${defaultExtensionLibs}" +fi + +if [ "${SPC_REL_TYPE}" = "binary" ]; then + mkdir -p static-php-cli/ + cd static-php-cli/ + if [[ "${arch}" =~ "arm" ]]; then + dl_arch="aarch64" + else + dl_arch="${arch}" fi - # The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli - if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then - PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli" + curl -o spc -fsSL "https://dl.static-php.dev/static-php-cli/spc-bin/nightly/spc-linux-${dl_arch}" + chmod +x spc + spcCommand="./spc" +elif [ -d "static-php-cli/src" ]; then + cd static-php-cli/ + git pull + composer install --no-dev -a --no-interaction + spcCommand="./bin/spc" +else + git clone --depth 1 https://github.com/crazywhalecc/static-php-cli --branch main + cd static-php-cli/ + composer install --no-dev -a --no-interaction + spcCommand="./bin/spc" +fi + +# Extensions to build +if [ -z "${PHP_EXTENSIONS}" ]; then + # enable EMBED mode, first check if project has dumped extensions + if [ -n "${EMBED}" ] && [ -f "${EMBED}/composer.json" ] && [ -f "${EMBED}/composer.lock" ] && [ -f "${EMBED}/vendor/installed.json" ]; then + cd "${EMBED}" + # read the extensions using spc dump-extensions + PHP_EXTENSIONS=$(${spcCommand} dump-extensions "${EMBED}" --format=text --no-dev --no-ext-output="${defaultExtensions}") + else + PHP_EXTENSIONS="${defaultExtensions}" fi - # The mimalloc library must be built if MIMALLOC is true - if [ -n "${MIMALLOC}" ]; then - if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bmimalloc\b"; then - PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},mimalloc" - fi +fi + +# Additional libraries to build +if [ -z "${PHP_EXTENSION_LIBS}" ]; then + PHP_EXTENSION_LIBS="${defaultExtensionLibs}" +fi + +# The Brotli library must always be built as it is required by http://github.com/dunglas/caddy-cbrotli +if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bbrotli\b"; then + PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},brotli" +fi + +# The mimalloc library must be built if MIMALLOC is true +if [ -n "${MIMALLOC}" ]; then + if ! echo "${PHP_EXTENSION_LIBS}" | grep -q "\bmimalloc\b"; then + PHP_EXTENSION_LIBS="${PHP_EXTENSION_LIBS},mimalloc" fi +fi +# Build libphp if necessary +cache_key="${PHP_VERSION}-${PHP_EXTENSIONS}-${PHP_EXTENSION_LIBS}" +if [ -f ../cache_key ] && [ "$(cat ../cache_key)" = "${cache_key}" ] && [ -f "buildroot/lib/libphp.a" ]; then + echo "Hit cache, skipping libphp build." +else ${spcCommand} doctor --auto-fix # shellcheck disable=SC2086 ${spcCommand} download --with-php="${PHP_VERSION}" --for-extensions="${PHP_EXTENSIONS}" --for-libs="${PHP_EXTENSION_LIBS}" ${SPC_OPT_DOWNLOAD_ARGS} # shellcheck disable=SC2086 ${spcCommand} build --enable-zts --build-embed ${SPC_OPT_BUILD_ARGS} "${PHP_EXTENSIONS}" --with-libs="${PHP_EXTENSION_LIBS}" + + echo -n "${cache_key}" >../cache_key fi if ! type "go" >/dev/null 2>&1; then diff --git a/static-builder-gnu.Dockerfile b/static-builder-gnu.Dockerfile index 9288a62018..f7224114d7 100644 --- a/static-builder-gnu.Dockerfile +++ b/static-builder-gnu.Dockerfile @@ -94,6 +94,9 @@ RUN yum install -y \ else \ GO_ARCH="amd64" ; \ fi ; \ + curl -o jq -fsSL https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-${GO_ARCH} && \ + chmod +x jq && \ + mv jq /usr/local/bin/jq && \ curl -o go.tgz -fsSL https://go.dev/dl/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \ rm -rf /usr/local/go && \ tar -C /usr/local -xzf go.tgz && \ From c96f53ca4a920b3fdf39772b0eaf38fecaf465ed Mon Sep 17 00:00:00 2001 From: Indra Gunawan Date: Wed, 23 Apr 2025 17:02:37 +0800 Subject: [PATCH 38/51] chore: update Go and toolchain version (#1526) --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 9a652bd04d..7444f61e80 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/dunglas/frankenphp -go 1.23.0 +go 1.24 -toolchain go1.23.3 +toolchain go1.24.2 retract v1.0.0-rc.1 // Human error From 26360fb0ea7970c862b780ec08fea951bdfd6c81 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 10:54:51 +0700 Subject: [PATCH 39/51] apply suggestions one be one - scriptpath only --- caddy/caddy.go | 34 +++++++++++++++------------------- context.go | 25 +++++-------------------- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 5eb689ab41..e4ef17ed3a 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -443,10 +443,13 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer) var documentRootOption frankenphp.RequestOption + var documentRoot string if f.resolvedDocumentRoot == "" { - documentRootOption = frankenphp.WithRequestDocumentRoot(repl.ReplaceKnown(f.Root, ""), *f.ResolveRootSymlink) + documentRoot = repl.ReplaceKnown(f.Root, "") + documentRootOption = frankenphp.WithRequestDocumentRoot(documentRoot, *f.ResolveRootSymlink) } else { - documentRootOption = frankenphp.WithRequestResolvedDocumentRoot(f.resolvedDocumentRoot) + documentRoot = f.resolvedDocumentRoot + documentRootOption = frankenphp.WithRequestResolvedDocumentRoot(documentRoot) } env := f.preparedEnv @@ -457,30 +460,23 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } } - filename, fc, err := frankenphp.NewFrankenPHPContext( - r, - documentRootOption, - frankenphp.WithRequestSplitPath(f.SplitPath), - frankenphp.WithRequestPreparedEnv(env), - frankenphp.WithOriginalRequest(&origReq), - ) - if err != nil { - return caddyhttp.Error(http.StatusInternalServerError, err) - } + fullScriptPath, _ := fastabs.FastAbs(documentRoot + "/" + r.URL.Path) workerName := "" for _, w := range f.Workers { - if p, _ := fastabs.FastAbs(w.FileName); p == filename { + if p, _ := fastabs.FastAbs(w.FileName); p == fullScriptPath { workerName = w.Name } } - err = frankenphp.WithModuleWorker(workerName)(fc) - if err != nil { - return caddyhttp.Error(http.StatusInternalServerError, err) - } - - fr := frankenphp.NewRequestWithExistingContext(r, fc) + fr, err := frankenphp.NewRequestWithContext( + r, + documentRootOption, + frankenphp.WithRequestSplitPath(f.SplitPath), + frankenphp.WithRequestPreparedEnv(env), + frankenphp.WithOriginalRequest(&origReq), + frankenphp.WithModuleWorker(workerName), + ) if err = frankenphp.ServeHTTP(w, fr); err != nil { return caddyhttp.Error(http.StatusInternalServerError, err) diff --git a/context.go b/context.go index a239549eac..9286ab629f 100644 --- a/context.go +++ b/context.go @@ -40,8 +40,8 @@ func fromContext(ctx context.Context) (fctx *frankenPHPContext, ok bool) { return } -// NewFrankenPHPContext parses out the correct filename and context to pass to NewRequestWithExistingContext -func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *frankenPHPContext, error) { +// NewRequestWithContext creates a new FrankenPHP request context. +func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { fc := &frankenPHPContext{ done: make(chan interface{}), startedAt: time.Now(), @@ -49,7 +49,7 @@ func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *fran } for _, o := range opts { if err := o(fc); err != nil { - return "", nil, err + return nil, err } } @@ -63,7 +63,7 @@ func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *fran } else { var err error if fc.documentRoot, err = os.Getwd(); err != nil { - return "", nil, err + return nil, err } } } @@ -92,24 +92,9 @@ func NewFrankenPHPContext(r *http.Request, opts ...RequestOption) (string, *fran // SCRIPT_FILENAME is the absolute path of SCRIPT_NAME fc.scriptFilename = sanitizedPathJoin(fc.documentRoot, fc.scriptName) - return fc.scriptFilename, fc, nil -} - -// NewRequestWithExistingContext wraps an http request with an existing FrankenPHP request context. -func NewRequestWithExistingContext(r *http.Request, fc *frankenPHPContext) *http.Request { c := context.WithValue(r.Context(), contextKey, fc) - return r.WithContext(c) -} - -// NewRequestWithContext creates a new FrankenPHP request context. -func NewRequestWithContext(r *http.Request, opts ...RequestOption) (*http.Request, error) { - _, fc, err2 := NewFrankenPHPContext(r, opts...) - if err2 != nil { - return nil, err2 - } - - return NewRequestWithExistingContext(r, fc), nil + return r.WithContext(c), nil } func newDummyContext(requestPath string, opts ...RequestOption) (*frankenPHPContext, error) { From 801e71c51418d1e741915709e9964642e3756e03 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 14:47:56 +0700 Subject: [PATCH 40/51] generate unique worker names by filename and number --- caddy/caddy.go | 79 +++++++++++++++----------------------------- caddy/config_test.go | 20 +++++------ worker.go | 4 +-- 3 files changed, 38 insertions(+), 65 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index e4ef17ed3a..72ad374855 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -9,7 +9,6 @@ import ( "fmt" "net/http" "path/filepath" - "sort" "strconv" "strings" "time" @@ -32,7 +31,7 @@ const defaultDocumentRoot = "public" var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") // FrankenPHPModule instances register their workers and FrankenPHPApp reads them at Start() time -var moduleWorkers = make([]workerConfig, 0) +var workerConfigs = make([]workerConfig, 0) func init() { caddy.RegisterModule(FrankenPHPApp{}) @@ -113,7 +112,7 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithMaxWaitTime(f.MaxWaitTime), } // Add workers from FrankenPHPApp and FrankenPHPModule configurations - for _, w := range append(f.Workers, moduleWorkers...) { + for _, w := range append(f.Workers, workerConfigs...) { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) } @@ -139,7 +138,7 @@ func (f *FrankenPHPApp) Stop() error { f.Workers = nil f.NumThreads = 0 f.MaxWaitTime = 0 - moduleWorkers = nil + workerConfigs = nil return nil } @@ -317,6 +316,9 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } wc.Name = name } + if strings.HasPrefix(wc.Name, "m#") { + return fmt.Errorf("global worker names must not start with 'm#': %q", wc.Name) + } f.Workers = append(f.Workers, wc) default: @@ -485,28 +487,25 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c return nil } -func getEnvString(env map[string]string) string { - // 1. Create a slice of keys from the map - keys := make([]string, 0, len(env)) - for k := range env { - keys = append(keys, k) - } - - // 2. Sort the keys alphabetically - sort.Strings(keys) - - // 3. Build the string using sorted keys - var builder strings.Builder - for i, k := range keys { - v := env[k] // Get value from the original map using the sorted key - if i > 0 { +func generateUniqueModuleWorkerName(filepath string) string { + name := "m#" + filepath + i := 0 + for { + nameExists := false + for _, wc := range workerConfigs { + if wc.Name == name { + nameExists = true + break + } + } + if !nameExists { + break } - builder.WriteString(k) - builder.WriteString("=") - builder.WriteString(v) - builder.WriteString(",") + i++ + name = fmt.Sprintf("m#%s_%d", filepath, i) } - return strings.TrimSuffix(builder.String(), ",") + + return name } // UnmarshalCaddyfile implements caddyfile.Unmarshaler. @@ -594,15 +593,8 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } - envString := getEnvString(wc.Env) - if wc.Name == "" { - if len(wc.Env) > 0 { - // Environment is required in order not to collide with other FrankenPHPModules - wc.Name += "env:" + envString - } - // Filename is required to avoid collisions with other workers in this module - wc.Name += "_" + wc.FileName + wc.Name = generateUniqueModuleWorkerName(wc.FileName) } if !strings.HasPrefix(wc.Name, "m#") { wc.Name = "m#" + wc.Name @@ -615,31 +607,14 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } } // Check if a worker with this name and a different environment or filename already exists - for i, existingWorker := range moduleWorkers { + for _, existingWorker := range workerConfigs { if existingWorker.Name == wc.Name { - efs, _ := fastabs.FastAbs(existingWorker.FileName) - wcfs, _ := fastabs.FastAbs(wc.FileName) - if efs != wcfs { - return fmt.Errorf("module workers with different filenames must not have duplicate names: %s", wc.Name) - } - if len(existingWorker.Env) != len(wc.Env) { - // If lengths are different, the maps are definitely different - return fmt.Errorf("module workers with different environments must not have duplicate names: %s", wc.Name) - } - // If lengths are the same, iterate and compare key-value pairs - if getEnvString(existingWorker.Env) != envString { - return fmt.Errorf("module workers with different environments must not have duplicate names: %s", wc.Name) - } - // If we reach this point, the maps are equal. - // Increase the number of threads for this worker and skip adding it to the moduleWorkers again - moduleWorkers[i].Num += wc.Num - f.Workers = append(f.Workers, wc) - return nil + return fmt.Errorf("workers must not have duplicate names: %s", wc.Name) } } f.Workers = append(f.Workers, wc) - moduleWorkers = append(moduleWorkers, wc) + workerConfigs = append(workerConfigs, wc) } } } diff --git a/caddy/config_test.go b/caddy/config_test.go index 54d1aa962b..bcfdd9e5c7 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" ) -// resetModuleWorkers resets the moduleWorkers slice for testing +// resetModuleWorkers resets the workerConfigs slice for testing func resetModuleWorkers() { - moduleWorkers = make([]workerConfig, 0) + workerConfigs = make([]workerConfig, 0) } func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { @@ -41,12 +41,11 @@ func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { resetModuleWorkers() } -func TestModuleWorkersDuplicateNameWithDifferentEnvironmentsFail(t *testing.T) { +func TestModuleWorkersDuplicateNameFail(t *testing.T) { // Create a test configuration with a worker name configWithWorkerName1 := ` { php_server { - env APP_ENV something worker { name test-worker file ../testdata/worker-with-env.php @@ -68,7 +67,6 @@ func TestModuleWorkersDuplicateNameWithDifferentEnvironmentsFail(t *testing.T) { { php_server { worker { - env APP_ENV mismatch name test-worker file ../testdata/worker-with-env.php num 1 @@ -85,7 +83,7 @@ func TestModuleWorkersDuplicateNameWithDifferentEnvironmentsFail(t *testing.T) { // Verify that an error was returned require.Error(t, err, "Expected an error when two workers have the same name, but different environments") - require.Contains(t, err.Error(), "module workers with different environments must not have duplicate names", "Error message should mention duplicate names") + require.Contains(t, err.Error(), "workers must not have duplicate names", "Error message should mention duplicate names") resetModuleWorkers() } @@ -160,10 +158,10 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) { // Verify that no error was returned require.NoError(t, err, "Expected no error when two workers have different names") - // Verify that both workers were added to moduleWorkers - require.Len(t, moduleWorkers, 2, "Expected two workers to be added to moduleWorkers") - require.Equal(t, "m#test-worker-1", moduleWorkers[0].Name, "First worker should have the correct name") - require.Equal(t, "m#test-worker-2", moduleWorkers[1].Name, "Second worker should have the correct name") + // Verify that both workers were added to workerConfigs + require.Len(t, workerConfigs, 2, "Expected two workers to be added to workerConfigs") + require.Equal(t, "m#test-worker-1", workerConfigs[0].Name, "First worker should have the correct name") + require.Equal(t, "m#test-worker-2", workerConfigs[1].Name, "Second worker should have the correct name") resetModuleWorkers() } @@ -269,7 +267,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to moduleWorkers with the m# prefix + // Verify that the worker was added to workerConfigs with the m# prefix require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() diff --git a/worker.go b/worker.go index 7c2f6c1ee0..2cad97dea1 100644 --- a/worker.go +++ b/worker.go @@ -82,8 +82,8 @@ func newWorker(o workerOpt) (*worker, error) { } key := getWorkerKey(o.name, absFileName) - if wrk, ok := workers[key]; ok { - return wrk, nil + if _, ok := workers[key]; ok { + return nil, fmt.Errorf("two workers must not share the same name %q", key) } if o.env == nil { From 665004526b182c74f1e498c6f5ddcb7985a4a4d1 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 15:47:31 +0700 Subject: [PATCH 41/51] support worker config from embedded apps --- caddy/caddy.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/caddy/caddy.go b/caddy/caddy.go index 72ad374855..9628d22a7b 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -448,6 +448,9 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c var documentRoot string if f.resolvedDocumentRoot == "" { documentRoot = repl.ReplaceKnown(f.Root, "") + if documentRoot == "" && frankenphp.EmbeddedAppPath != "" { + documentRoot = frankenphp.EmbeddedAppPath + } documentRootOption = frankenphp.WithRequestDocumentRoot(documentRoot, *f.ResolveRootSymlink) } else { documentRoot = f.resolvedDocumentRoot From 53e7bc08ea40a0c0d582612aed88298b66f2ef28 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 17:45:22 +0700 Subject: [PATCH 42/51] rename back to make sure we don't accidentally add FrankenPHPApp workers to the slice --- caddy/caddy.go | 24 ++++++++++++++++-------- caddy/config_test.go | 14 +++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 9628d22a7b..0d3b21e54d 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -30,8 +30,9 @@ const defaultDocumentRoot = "public" var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") -// FrankenPHPModule instances register their workers and FrankenPHPApp reads them at Start() time -var workerConfigs = make([]workerConfig, 0) +// FrankenPHPModule instances register their workers, and FrankenPHPApp reads them at Start() time. +// FrankenPHPApp.Workers may be set by JSON config, so keep them separate. +var moduleWorkerConfigs []workerConfig func init() { caddy.RegisterModule(FrankenPHPApp{}) @@ -112,7 +113,8 @@ func (f *FrankenPHPApp) Start() error { frankenphp.WithMaxWaitTime(f.MaxWaitTime), } // Add workers from FrankenPHPApp and FrankenPHPModule configurations - for _, w := range append(f.Workers, workerConfigs...) { + // f.Workers may have been set by JSON config, so keep them separate + for _, w := range append(f.Workers, moduleWorkerConfigs...) { opts = append(opts, frankenphp.WithWorkers(w.Name, repl.ReplaceKnown(w.FileName, ""), w.Num, w.Env, w.Watch)) } @@ -138,7 +140,7 @@ func (f *FrankenPHPApp) Stop() error { f.Workers = nil f.NumThreads = 0 f.MaxWaitTime = 0 - workerConfigs = nil + moduleWorkerConfigs = nil return nil } @@ -319,6 +321,12 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if strings.HasPrefix(wc.Name, "m#") { return fmt.Errorf("global worker names must not start with 'm#': %q", wc.Name) } + // check for duplicate workers + for _, existingWorker := range f.Workers { + if existingWorker.FileName == wc.FileName { + return fmt.Errorf("global workers must not have duplicate filenames: %s", wc.FileName) + } + } f.Workers = append(f.Workers, wc) default: @@ -495,7 +503,7 @@ func generateUniqueModuleWorkerName(filepath string) string { i := 0 for { nameExists := false - for _, wc := range workerConfigs { + for _, wc := range moduleWorkerConfigs { if wc.Name == name { nameExists = true break @@ -606,18 +614,18 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // Check if a worker with this filename already exists in this module for _, existingWorker := range f.Workers { if existingWorker.FileName == wc.FileName { - return fmt.Errorf("workers must not have duplicate filenames: %s", wc.FileName) + return fmt.Errorf("workers in a single `php_server` block must not have duplicate filenames: %s", wc.FileName) } } // Check if a worker with this name and a different environment or filename already exists - for _, existingWorker := range workerConfigs { + for _, existingWorker := range moduleWorkerConfigs { if existingWorker.Name == wc.Name { return fmt.Errorf("workers must not have duplicate names: %s", wc.Name) } } f.Workers = append(f.Workers, wc) - workerConfigs = append(workerConfigs, wc) + moduleWorkerConfigs = append(moduleWorkerConfigs, wc) } } } diff --git a/caddy/config_test.go b/caddy/config_test.go index bcfdd9e5c7..a5a47ebb7c 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -7,9 +7,9 @@ import ( "github.com/stretchr/testify/require" ) -// resetModuleWorkers resets the workerConfigs slice for testing +// resetModuleWorkers resets the moduleWorkerConfigs slice for testing func resetModuleWorkers() { - workerConfigs = make([]workerConfig, 0) + moduleWorkerConfigs = make([]workerConfig, 0) } func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { @@ -158,10 +158,10 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) { // Verify that no error was returned require.NoError(t, err, "Expected no error when two workers have different names") - // Verify that both workers were added to workerConfigs - require.Len(t, workerConfigs, 2, "Expected two workers to be added to workerConfigs") - require.Equal(t, "m#test-worker-1", workerConfigs[0].Name, "First worker should have the correct name") - require.Equal(t, "m#test-worker-2", workerConfigs[1].Name, "Second worker should have the correct name") + // Verify that both workers were added to moduleWorkerConfigs + require.Len(t, moduleWorkerConfigs, 2, "Expected two workers to be added to moduleWorkerConfigs") + require.Equal(t, "m#test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name") + require.Equal(t, "m#test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name") resetModuleWorkers() } @@ -267,7 +267,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to workerConfigs with the m# prefix + // Verify that the worker was added to moduleWorkerConfigs with the m# prefix require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() From 78be813e003a7785ac4403d090f8b07ebbb44bd4 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 17:51:23 +0700 Subject: [PATCH 43/51] fix test after changing error message --- caddy/config_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/caddy/config_test.go b/caddy/config_test.go index a5a47ebb7c..9a4c9aa230 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -37,7 +37,7 @@ func TestModuleWorkerDuplicateFilenamesFail(t *testing.T) { // Verify that an error was returned require.Error(t, err, "Expected an error when two workers in the same module have the same filename") - require.Contains(t, err.Error(), "workers must not have duplicate filenames", "Error message should mention duplicate filenames") + require.Contains(t, err.Error(), "must not have duplicate filenames", "Error message should mention duplicate filenames") resetModuleWorkers() } @@ -83,7 +83,7 @@ func TestModuleWorkersDuplicateNameFail(t *testing.T) { // Verify that an error was returned require.Error(t, err, "Expected an error when two workers have the same name, but different environments") - require.Contains(t, err.Error(), "workers must not have duplicate names", "Error message should mention duplicate names") + require.Contains(t, err.Error(), "must not have duplicate names", "Error message should mention duplicate names") resetModuleWorkers() } From 4cc8893cedc8a2c9e2195ca0e83e8e9cc359e136 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 18:24:30 +0700 Subject: [PATCH 44/51] =?UTF-8?q?use=20=F0=9F=A7=A9=20for=20module=20worke?= =?UTF-8?q?rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- caddy/caddy.go | 14 +++++++------- caddy/config_test.go | 8 ++++---- worker.go | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 0d3b21e54d..8af78fcc62 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -49,7 +49,7 @@ func init() { } type workerConfig struct { - // Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "m#" for FrankenPHPModule workers. + // Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "🧩 " for FrankenPHPModule workers. Name string `json:"name,omitempty"` // FileName sets the path to the worker script. FileName string `json:"file_name,omitempty"` @@ -318,8 +318,8 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } wc.Name = name } - if strings.HasPrefix(wc.Name, "m#") { - return fmt.Errorf("global worker names must not start with 'm#': %q", wc.Name) + if strings.HasPrefix(wc.Name, "🧩 ") { + return fmt.Errorf("global worker names must not start with '🧩 ': %q", wc.Name) } // check for duplicate workers for _, existingWorker := range f.Workers { @@ -499,7 +499,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } func generateUniqueModuleWorkerName(filepath string) string { - name := "m#" + filepath + name := "🧩 " + filepath i := 0 for { nameExists := false @@ -513,7 +513,7 @@ func generateUniqueModuleWorkerName(filepath string) string { break } i++ - name = fmt.Sprintf("m#%s_%d", filepath, i) + name = fmt.Sprintf("🧩 %s_%d", filepath, i) } return name @@ -607,8 +607,8 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if wc.Name == "" { wc.Name = generateUniqueModuleWorkerName(wc.FileName) } - if !strings.HasPrefix(wc.Name, "m#") { - wc.Name = "m#" + wc.Name + if !strings.HasPrefix(wc.Name, "🧩 ") { + wc.Name = "🧩 " + wc.Name } // Check if a worker with this filename already exists in this module diff --git a/caddy/config_test.go b/caddy/config_test.go index 9a4c9aa230..dc075ee41d 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -160,8 +160,8 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) { // Verify that both workers were added to moduleWorkerConfigs require.Len(t, moduleWorkerConfigs, 2, "Expected two workers to be added to moduleWorkerConfigs") - require.Equal(t, "m#test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name") - require.Equal(t, "m#test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name") + require.Equal(t, "🧩 test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name") + require.Equal(t, "🧩 test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name") resetModuleWorkers() } @@ -267,8 +267,8 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to moduleWorkerConfigs with the m# prefix - require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") + // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix + require.Equal(t, "🧩 custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() } diff --git a/worker.go b/worker.go index 2cad97dea1..0f87857a77 100644 --- a/worker.go +++ b/worker.go @@ -69,7 +69,7 @@ func initWorkers(opt []workerOpt) error { func getWorkerKey(name string, filename string) string { key := filename - if strings.HasPrefix(name, "m#") { + if strings.HasPrefix(name, "🧩 ") { key = name } return key From 1c414cebbc4380b26c4ac46a8662f88bd807aa09 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Thu, 24 Apr 2025 18:31:50 +0700 Subject: [PATCH 45/51] =?UTF-8?q?use=20=F0=9F=8C=8D=20for=20global=20worke?= =?UTF-8?q?rs=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- caddy/caddy.go | 4 ++-- caddy/caddy_test.go | 44 ++++++++++++++++++++++---------------------- caddy/config_test.go | 2 +- metrics_test.go | 28 ++++++++++++++-------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 8af78fcc62..6feaebb8b6 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -318,8 +318,8 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } wc.Name = name } - if strings.HasPrefix(wc.Name, "🧩 ") { - return fmt.Errorf("global worker names must not start with '🧩 ': %q", wc.Name) + if !strings.HasPrefix(wc.Name, "🌍 ") { + wc.Name = "🌍 " + wc.Name } // check for duplicate workers for _, existingWorker := range f.Workers { diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 159d514848..2bdb9fd01a 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -574,19 +574,19 @@ func TestWorkerMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="` + workerName + `"} 0 + frankenphp_busy_workers{worker="🌍 ` + workerName + `"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="` + workerName + `"} 2 + frankenphp_total_workers{worker="🌍 ` + workerName + `"} 2 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="` + workerName + `"} 10 + frankenphp_worker_request_count{worker="🌍 ` + workerName + `"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="` + workerName + `"} 2 + frankenphp_ready_workers{worker="🌍 ` + workerName + `"} 2 ` ctx := caddy.ActiveContext() @@ -666,19 +666,19 @@ func TestNamedWorkerMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="my_app"} 0 + frankenphp_busy_workers{worker="🌍 my_app"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="my_app"} 2 + frankenphp_total_workers{worker="🌍 my_app"} 2 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="my_app"} 10 + frankenphp_worker_request_count{worker="🌍 my_app"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="my_app"} 2 + frankenphp_ready_workers{worker="🌍 my_app"} 2 ` ctx := caddy.ActiveContext() @@ -758,19 +758,19 @@ func TestAutoWorkerConfig(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="` + workerName + `"} 0 + frankenphp_busy_workers{worker="🌍 ` + workerName + `"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="` + workerName + `"} ` + workers + ` + frankenphp_total_workers{worker="🌍 ` + workerName + `"} ` + workers + ` # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="` + workerName + `"} 10 + frankenphp_worker_request_count{worker="🌍 ` + workerName + `"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="` + workerName + `"} ` + workers + ` + frankenphp_ready_workers{worker="🌍 ` + workerName + `"} ` + workers + ` ` ctx := caddy.ActiveContext() @@ -1052,21 +1052,21 @@ func TestMultiWorkersMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="service1"} 0 + frankenphp_busy_workers{worker="🌍 service1"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="service1"} 2 - frankenphp_total_workers{worker="service2"} 3 + frankenphp_total_workers{worker="🌍 service1"} 2 + frankenphp_total_workers{worker="🌍 service2"} 3 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="service1"} 10 + frankenphp_worker_request_count{worker="🌍 service1"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="service1"} 2 - frankenphp_ready_workers{worker="service2"} 3 + frankenphp_ready_workers{worker="🌍 service1"} 2 + frankenphp_ready_workers{worker="🌍 service2"} 3 ` ctx := caddy.ActiveContext() @@ -1159,19 +1159,19 @@ func TestMultiWorkersMetricsWithDuplicateName(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="service1"} 0 + frankenphp_busy_workers{worker="🌍 service1"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="service1"} 5 + frankenphp_total_workers{worker="🌍 service1"} 5 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="service1"} 10 + frankenphp_worker_request_count{worker="🌍 service1"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="service1"} 5 + frankenphp_ready_workers{worker="🌍 service1"} 5 ` ctx := caddy.ActiveContext() diff --git a/caddy/config_test.go b/caddy/config_test.go index dc075ee41d..9b98a0f670 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -267,7 +267,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix + // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix require.Equal(t, "🧩 custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() diff --git a/metrics_test.go b/metrics_test.go index 41d6518367..73f770bde0 100644 --- a/metrics_test.go +++ b/metrics_test.go @@ -32,7 +32,7 @@ func TestPrometheusMetrics_TotalWorkers(t *testing.T) { require.Nil(t, m.workerRequestTime) require.Nil(t, m.workerRequestCount) - m.TotalWorkers("test_worker", 2) + m.TotalWorkers("🌍 test_worker", 2) require.NotNil(t, m.totalWorkers) require.NotNil(t, m.busyWorkers) @@ -45,8 +45,8 @@ func TestPrometheusMetrics_TotalWorkers(t *testing.T) { func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("test_worker", 2) - m.StopWorkerRequest("test_worker", 2*time.Second) + m.TotalWorkers("🌍 test_worker", 2) + m.StopWorkerRequest("🌍 test_worker", 2*time.Second) inputs := []struct { name string @@ -62,7 +62,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_worker_request_count counter `, expect: ` - frankenphp_worker_request_count{worker="test_worker"} 1 + frankenphp_worker_request_count{worker="🌍 test_worker"} 1 `, }, { @@ -73,7 +73,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_busy_workers gauge `, expect: ` - frankenphp_busy_workers{worker="test_worker"} -1 + frankenphp_busy_workers{worker="🌍 test_worker"} -1 `, }, { @@ -84,7 +84,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_worker_request_time counter `, expect: ` - frankenphp_worker_request_time{worker="test_worker"} 2 + frankenphp_worker_request_time{worker="🌍 test_worker"} 2 `, }, } @@ -99,8 +99,8 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("test_worker", 2) - m.StartWorkerRequest("test_worker") + m.TotalWorkers("🌍 test_worker", 2) + m.StartWorkerRequest("🌍 test_worker") inputs := []struct { name string @@ -116,7 +116,7 @@ func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { # TYPE frankenphp_busy_workers gauge `, expect: ` - frankenphp_busy_workers{worker="test_worker"} 1 + frankenphp_busy_workers{worker="🌍 test_worker"} 1 `, }, } @@ -131,8 +131,8 @@ func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("test_worker", 2) - m.StopWorker("test_worker", StopReasonCrash) + m.TotalWorkers("🌍 test_worker", 2) + m.StopWorker("🌍 test_worker", StopReasonCrash) inputs := []struct { name string @@ -159,7 +159,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_total_workers gauge `, expect: ` - frankenphp_total_workers{worker="test_worker"} -1 + frankenphp_total_workers{worker="🌍 test_worker"} -1 `, }, { @@ -170,7 +170,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_ready_workers gauge `, expect: ` - frankenphp_ready_workers{worker="test_worker"} -1 + frankenphp_ready_workers{worker="🌍 test_worker"} -1 `, }, { @@ -181,7 +181,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_worker_crashes counter `, expect: ` - frankenphp_worker_crashes{worker="test_worker"} 1 + frankenphp_worker_crashes{worker="🌍 test_worker"} 1 `, }, } From 3f8f5ecd5f03be74b894494c38cd05c5642fcd6e Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sat, 26 Apr 2025 19:01:44 +0700 Subject: [PATCH 46/51] revert 1c414cebbc4380b26c4ac46a8662f88bd807aa09 --- caddy/caddy.go | 4 ++-- caddy/caddy_test.go | 44 ++++++++++++++++++++++---------------------- caddy/config_test.go | 2 +- metrics_test.go | 28 ++++++++++++++-------------- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 32f676b243..862c660be2 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -318,8 +318,8 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } wc.Name = name } - if !strings.HasPrefix(wc.Name, "🌍 ") { - wc.Name = "🌍 " + wc.Name + if strings.HasPrefix(wc.Name, "🧩 ") { + return fmt.Errorf("global worker names must not start with '🧩 ': %q", wc.Name) } // check for duplicate workers for _, existingWorker := range f.Workers { diff --git a/caddy/caddy_test.go b/caddy/caddy_test.go index 2bdb9fd01a..159d514848 100644 --- a/caddy/caddy_test.go +++ b/caddy/caddy_test.go @@ -574,19 +574,19 @@ func TestWorkerMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="🌍 ` + workerName + `"} 0 + frankenphp_busy_workers{worker="` + workerName + `"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="🌍 ` + workerName + `"} 2 + frankenphp_total_workers{worker="` + workerName + `"} 2 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="🌍 ` + workerName + `"} 10 + frankenphp_worker_request_count{worker="` + workerName + `"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="🌍 ` + workerName + `"} 2 + frankenphp_ready_workers{worker="` + workerName + `"} 2 ` ctx := caddy.ActiveContext() @@ -666,19 +666,19 @@ func TestNamedWorkerMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="🌍 my_app"} 0 + frankenphp_busy_workers{worker="my_app"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="🌍 my_app"} 2 + frankenphp_total_workers{worker="my_app"} 2 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="🌍 my_app"} 10 + frankenphp_worker_request_count{worker="my_app"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="🌍 my_app"} 2 + frankenphp_ready_workers{worker="my_app"} 2 ` ctx := caddy.ActiveContext() @@ -758,19 +758,19 @@ func TestAutoWorkerConfig(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="🌍 ` + workerName + `"} 0 + frankenphp_busy_workers{worker="` + workerName + `"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="🌍 ` + workerName + `"} ` + workers + ` + frankenphp_total_workers{worker="` + workerName + `"} ` + workers + ` # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="🌍 ` + workerName + `"} 10 + frankenphp_worker_request_count{worker="` + workerName + `"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="🌍 ` + workerName + `"} ` + workers + ` + frankenphp_ready_workers{worker="` + workerName + `"} ` + workers + ` ` ctx := caddy.ActiveContext() @@ -1052,21 +1052,21 @@ func TestMultiWorkersMetrics(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="🌍 service1"} 0 + frankenphp_busy_workers{worker="service1"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="🌍 service1"} 2 - frankenphp_total_workers{worker="🌍 service2"} 3 + frankenphp_total_workers{worker="service1"} 2 + frankenphp_total_workers{worker="service2"} 3 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="🌍 service1"} 10 + frankenphp_worker_request_count{worker="service1"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="🌍 service1"} 2 - frankenphp_ready_workers{worker="🌍 service2"} 3 + frankenphp_ready_workers{worker="service1"} 2 + frankenphp_ready_workers{worker="service2"} 3 ` ctx := caddy.ActiveContext() @@ -1159,19 +1159,19 @@ func TestMultiWorkersMetricsWithDuplicateName(t *testing.T) { # HELP frankenphp_busy_workers Number of busy PHP workers for this worker # TYPE frankenphp_busy_workers gauge - frankenphp_busy_workers{worker="🌍 service1"} 0 + frankenphp_busy_workers{worker="service1"} 0 # HELP frankenphp_total_workers Total number of PHP workers for this worker # TYPE frankenphp_total_workers gauge - frankenphp_total_workers{worker="🌍 service1"} 5 + frankenphp_total_workers{worker="service1"} 5 # HELP frankenphp_worker_request_count # TYPE frankenphp_worker_request_count counter - frankenphp_worker_request_count{worker="🌍 service1"} 10 + frankenphp_worker_request_count{worker="service1"} 10 # HELP frankenphp_ready_workers Running workers that have successfully called frankenphp_handle_request at least once # TYPE frankenphp_ready_workers gauge - frankenphp_ready_workers{worker="🌍 service1"} 5 + frankenphp_ready_workers{worker="service1"} 5 ` ctx := caddy.ActiveContext() diff --git a/caddy/config_test.go b/caddy/config_test.go index 9b98a0f670..dc075ee41d 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -267,7 +267,7 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix + // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix require.Equal(t, "🧩 custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() diff --git a/metrics_test.go b/metrics_test.go index 73f770bde0..41d6518367 100644 --- a/metrics_test.go +++ b/metrics_test.go @@ -32,7 +32,7 @@ func TestPrometheusMetrics_TotalWorkers(t *testing.T) { require.Nil(t, m.workerRequestTime) require.Nil(t, m.workerRequestCount) - m.TotalWorkers("🌍 test_worker", 2) + m.TotalWorkers("test_worker", 2) require.NotNil(t, m.totalWorkers) require.NotNil(t, m.busyWorkers) @@ -45,8 +45,8 @@ func TestPrometheusMetrics_TotalWorkers(t *testing.T) { func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("🌍 test_worker", 2) - m.StopWorkerRequest("🌍 test_worker", 2*time.Second) + m.TotalWorkers("test_worker", 2) + m.StopWorkerRequest("test_worker", 2*time.Second) inputs := []struct { name string @@ -62,7 +62,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_worker_request_count counter `, expect: ` - frankenphp_worker_request_count{worker="🌍 test_worker"} 1 + frankenphp_worker_request_count{worker="test_worker"} 1 `, }, { @@ -73,7 +73,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_busy_workers gauge `, expect: ` - frankenphp_busy_workers{worker="🌍 test_worker"} -1 + frankenphp_busy_workers{worker="test_worker"} -1 `, }, { @@ -84,7 +84,7 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { # TYPE frankenphp_worker_request_time counter `, expect: ` - frankenphp_worker_request_time{worker="🌍 test_worker"} 2 + frankenphp_worker_request_time{worker="test_worker"} 2 `, }, } @@ -99,8 +99,8 @@ func TestPrometheusMetrics_StopWorkerRequest(t *testing.T) { func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("🌍 test_worker", 2) - m.StartWorkerRequest("🌍 test_worker") + m.TotalWorkers("test_worker", 2) + m.StartWorkerRequest("test_worker") inputs := []struct { name string @@ -116,7 +116,7 @@ func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { # TYPE frankenphp_busy_workers gauge `, expect: ` - frankenphp_busy_workers{worker="🌍 test_worker"} 1 + frankenphp_busy_workers{worker="test_worker"} 1 `, }, } @@ -131,8 +131,8 @@ func TestPrometheusMetrics_StartWorkerRequest(t *testing.T) { func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { m := createPrometheusMetrics() - m.TotalWorkers("🌍 test_worker", 2) - m.StopWorker("🌍 test_worker", StopReasonCrash) + m.TotalWorkers("test_worker", 2) + m.StopWorker("test_worker", StopReasonCrash) inputs := []struct { name string @@ -159,7 +159,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_total_workers gauge `, expect: ` - frankenphp_total_workers{worker="🌍 test_worker"} -1 + frankenphp_total_workers{worker="test_worker"} -1 `, }, { @@ -170,7 +170,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_ready_workers gauge `, expect: ` - frankenphp_ready_workers{worker="🌍 test_worker"} -1 + frankenphp_ready_workers{worker="test_worker"} -1 `, }, { @@ -181,7 +181,7 @@ func TestPrometheusMetrics_TestStopReasonCrash(t *testing.T) { # TYPE frankenphp_worker_crashes counter `, expect: ` - frankenphp_worker_crashes{worker="🌍 test_worker"} 1 + frankenphp_worker_crashes{worker="test_worker"} 1 `, }, } From a6596c7330cabb079b977b4c07472c93367d206b Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Sun, 27 Apr 2025 08:26:46 +0700 Subject: [PATCH 47/51] revert 4cc8893cedc8a2c9e2195ca0e83e8e9cc359e136 --- caddy/caddy.go | 14 +++++++------- caddy/config_test.go | 8 ++++---- worker.go | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 862c660be2..765a29dc31 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -49,7 +49,7 @@ func init() { } type workerConfig struct { - // Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "🧩 " for FrankenPHPModule workers. + // Name for the worker. Default: the filename for FrankenPHPApp workers, always prefixed with "m#" for FrankenPHPModule workers. Name string `json:"name,omitempty"` // FileName sets the path to the worker script. FileName string `json:"file_name,omitempty"` @@ -318,8 +318,8 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { } wc.Name = name } - if strings.HasPrefix(wc.Name, "🧩 ") { - return fmt.Errorf("global worker names must not start with '🧩 ': %q", wc.Name) + if strings.HasPrefix(wc.Name, "m#") { + return fmt.Errorf("global worker names must not start with 'm#': %q", wc.Name) } // check for duplicate workers for _, existingWorker := range f.Workers { @@ -499,7 +499,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } func generateUniqueModuleWorkerName(filepath string) string { - name := "🧩 " + filepath + name := "m#" + filepath i := 0 for { nameExists := false @@ -513,7 +513,7 @@ func generateUniqueModuleWorkerName(filepath string) string { break } i++ - name = fmt.Sprintf("🧩 %s_%d", filepath, i) + name = fmt.Sprintf("m#%s_%d", filepath, i) } return name @@ -607,8 +607,8 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { if wc.Name == "" { wc.Name = generateUniqueModuleWorkerName(wc.FileName) } - if !strings.HasPrefix(wc.Name, "🧩 ") { - wc.Name = "🧩 " + wc.Name + if !strings.HasPrefix(wc.Name, "m#") { + wc.Name = "m#" + wc.Name } // Check if a worker with this filename already exists in this module diff --git a/caddy/config_test.go b/caddy/config_test.go index dc075ee41d..9a4c9aa230 100644 --- a/caddy/config_test.go +++ b/caddy/config_test.go @@ -160,8 +160,8 @@ func TestModuleWorkersDifferentNamesSucceed(t *testing.T) { // Verify that both workers were added to moduleWorkerConfigs require.Len(t, moduleWorkerConfigs, 2, "Expected two workers to be added to moduleWorkerConfigs") - require.Equal(t, "🧩 test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name") - require.Equal(t, "🧩 test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name") + require.Equal(t, "m#test-worker-1", moduleWorkerConfigs[0].Name, "First worker should have the correct name") + require.Equal(t, "m#test-worker-2", moduleWorkerConfigs[1].Name, "Second worker should have the correct name") resetModuleWorkers() } @@ -267,8 +267,8 @@ func TestModuleWorkerWithCustomName(t *testing.T) { require.Len(t, module.Workers, 1, "Expected one worker to be added to the module") require.Equal(t, "../testdata/worker-with-env.php", module.Workers[0].FileName, "Worker should have the correct filename") - // Verify that the worker was added to moduleWorkerConfigs with the 🧩 prefix - require.Equal(t, "🧩 custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") + // Verify that the worker was added to moduleWorkerConfigs with the m# prefix + require.Equal(t, "m#custom-worker-name", module.Workers[0].Name, "Worker should have the custom name") resetModuleWorkers() } diff --git a/worker.go b/worker.go index 0f87857a77..2cad97dea1 100644 --- a/worker.go +++ b/worker.go @@ -69,7 +69,7 @@ func initWorkers(opt []workerOpt) error { func getWorkerKey(name string, filename string) string { key := filename - if strings.HasPrefix(name, "🧩 ") { + if strings.HasPrefix(name, "m#") { key = name } return key From d5d2eb32eab010ac336fb81c6b795474014d336c Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 29 Apr 2025 08:28:13 +0700 Subject: [PATCH 48/51] apply suggestions --- caddy/caddy.go | 22 +++++++++++----------- caddy/php-server.go | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index 765a29dc31..9ef91cf90b 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -155,17 +155,17 @@ func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) { if d.Val() == "watch" { wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") } else { - v, err := strconv.Atoi(d.Val()) + v, err := strconv.ParseUint(d.Val(), 10, 32) if err != nil { return wc, err } - wc.Num = v + wc.Num = int(v) } } if d.NextArg() { - return wc, errors.New("FrankenPHP: too many 'worker' arguments: " + d.Val()) + return wc, errors.New(`FrankenPHP: too many "worker" arguments: ` + d.Val()) } for d.NextBlock(1) { @@ -186,12 +186,12 @@ func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) { return wc, d.ArgErr() } - v, err := strconv.Atoi(d.Val()) + v, err := strconv.ParseUint(d.Val(), 10, 32) if err != nil { return wc, err } - wc.Num = v + wc.Num = int(v) case "env": args := d.RemainingArgs() if len(args) != 2 { @@ -236,12 +236,12 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { return d.ArgErr() } - v, err := strconv.Atoi(d.Val()) + v, err := strconv.ParseUint(d.Val(), 10, 32) if err != nil { return err } - f.NumThreads = v + f.NumThreads = int(v) case "max_threads": if !d.NextArg() { return d.ArgErr() @@ -319,12 +319,12 @@ func (f *FrankenPHPApp) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { wc.Name = name } if strings.HasPrefix(wc.Name, "m#") { - return fmt.Errorf("global worker names must not start with 'm#': %q", wc.Name) + return fmt.Errorf(`global worker names must not start with "m#": %q`, wc.Name) } // check for duplicate workers for _, existingWorker := range f.Workers { if existingWorker.FileName == wc.FileName { - return fmt.Errorf("global workers must not have duplicate filenames: %s", wc.FileName) + return fmt.Errorf("global workers must not have duplicate filenames: %q", wc.FileName) } } @@ -614,13 +614,13 @@ func (f *FrankenPHPModule) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { // Check if a worker with this filename already exists in this module for _, existingWorker := range f.Workers { if existingWorker.FileName == wc.FileName { - return fmt.Errorf("workers in a single `php_server` block must not have duplicate filenames: %s", wc.FileName) + return fmt.Errorf(`workers in a single "php_server" block must not have duplicate filenames: %q`, wc.FileName) } } // Check if a worker with this name and a different environment or filename already exists for _, existingWorker := range moduleWorkerConfigs { if existingWorker.Name == wc.Name { - return fmt.Errorf("workers must not have duplicate names: %s", wc.Name) + return fmt.Errorf("workers must not have duplicate names: %q", wc.Name) } } diff --git a/caddy/php-server.go b/caddy/php-server.go index 711b9ec3d9..97031dc0eb 100644 --- a/caddy/php-server.go +++ b/caddy/php-server.go @@ -88,12 +88,12 @@ func cmdPHPServer(fs caddycmd.Flags) (int, error) { parts[0] = filepath.Join(frankenphp.EmbeddedAppPath, parts[0]) } - var num int + var num uint64 if len(parts) > 1 { - num, _ = strconv.Atoi(parts[1]) + num, _ = strconv.ParseUint(parts[1], 10, 32) } - workersOption = append(workersOption, workerConfig{FileName: parts[0], Num: num}) + workersOption = append(workersOption, workerConfig{FileName: parts[0], Num: int(num)}) } workersOption[0].Watch = watch } From 6f2789593377b5db90dbceac70c8b093423d1e8c Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 29 Apr 2025 16:37:14 +0700 Subject: [PATCH 49/51] add dynamic config loading test of module worker --- caddy/admin_test.go | 82 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/caddy/admin_test.go b/caddy/admin_test.go index 4a970ffda2..4c84c2348b 100644 --- a/caddy/admin_test.go +++ b/caddy/admin_test.go @@ -1,7 +1,10 @@ package caddy_test import ( + "bytes" "encoding/json" + "fmt" + "github.com/dunglas/frankenphp/internal/fastabs" "io" "net/http" "sync" @@ -213,3 +216,82 @@ func getDebugState(t *testing.T, tester *caddytest.Tester) frankenphp.FrankenPHP return debugStates } + +func TestAddModuleWorkerViaAdminApi(t *testing.T) { + // Initialize a server with admin API enabled + tester := caddytest.NewTester(t) + tester.InitServer(` + { + skip_install_trust + admin localhost:2999 + http_port `+testPort+` + + frankenphp + } + + localhost:`+testPort+` { + route { + root ../testdata + php + } + } + `, "caddyfile") + + // Get initial debug state to check number of workers + initialDebugState := getDebugState(t, tester) + initialWorkerCount := 0 + for _, thread := range initialDebugState.ThreadDebugStates { + if thread.Name != "" && thread.Name != "ready" { + initialWorkerCount++ + } + } + + // Create a Caddyfile configuration with a module worker + workerConfig := ` + { + skip_install_trust + admin localhost:2999 + http_port ` + testPort + ` + + frankenphp + } + + localhost:` + testPort + ` { + route { + root ../testdata + php { + worker ../testdata/worker-with-counter.php 1 + } + } + } + ` + + // Send the configuration to the admin API + adminUrl := "http://localhost:2999/load" + r, err := http.NewRequest("POST", adminUrl, bytes.NewBufferString(workerConfig)) + assert.NoError(t, err) + r.Header.Set("Content-Type", "text/caddyfile") + resp := tester.AssertResponseCode(r, http.StatusOK) + defer resp.Body.Close() + + // Get the updated debug state to check if the worker was added + updatedDebugState := getDebugState(t, tester) + updatedWorkerCount := 0 + workerFound := false + filename, _ := fastabs.FastAbs("../testdata/worker-with-counter.php") + for _, thread := range updatedDebugState.ThreadDebugStates { + if thread.Name != "" && thread.Name != "ready" { + updatedWorkerCount++ + if thread.Name == "Worker PHP Thread - "+filename { + workerFound = true + } + } + } + + // Assert that the worker was added + assert.Greater(t, updatedWorkerCount, initialWorkerCount, "Worker count should have increased") + assert.True(t, workerFound, fmt.Sprintf("Worker with name %q should be found", "Worker PHP Thread - "+filename)) + + // Make a request to the worker to verify it's working + tester.AssertGetResponse("http://localhost:"+testPort+"/worker-with-counter.php", http.StatusOK, "requests:1") +} From 877a6ceae8d2ce3d6fd88b488817b05a3ac9ddc6 Mon Sep 17 00:00:00 2001 From: DubbleClick Date: Tue, 29 Apr 2025 16:53:10 +0700 Subject: [PATCH 50/51] fix test --- phpmainthread_test.go | 6 +++--- worker.go | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/phpmainthread_test.go b/phpmainthread_test.go index 96e34f6c2d..08020ea625 100644 --- a/phpmainthread_test.go +++ b/phpmainthread_test.go @@ -186,16 +186,16 @@ func TestReturnAnErrorIf2WorkersHaveTheSameFileName(t *testing.T) { _, err2 := newWorker(workerOpt{fileName: "filename.php"}) assert.NoError(t, err1) - assert.Error(t, err2, "2 workers cannot have the same filename") + assert.Error(t, err2, "two workers cannot have the same filename") } -func TestReturnAnErrorIf2WorkersHaveTheSameName(t *testing.T) { +func TestReturnAnErrorIf2ModuleWorkersHaveTheSameName(t *testing.T) { workers = make(map[string]*worker) _, err1 := newWorker(workerOpt{fileName: "filename.php", name: "workername"}) _, err2 := newWorker(workerOpt{fileName: "filename2.php", name: "workername"}) assert.NoError(t, err1) - assert.Error(t, err2, "2 workers cannot have the same name") + assert.Error(t, err2, "two workers cannot have the same name") } func getDummyWorker(fileName string) *worker { diff --git a/worker.go b/worker.go index 69991a30ba..22d904a2f9 100644 --- a/worker.go +++ b/worker.go @@ -81,7 +81,12 @@ func newWorker(o workerOpt) (*worker, error) { key := getWorkerKey(o.name, absFileName) if _, ok := workers[key]; ok { - return nil, fmt.Errorf("two workers must not share the same key %q", key) + return nil, fmt.Errorf("two workers cannot use the same key %q", key) + } + for _, w := range workers { + if w.name == o.name { + return w, fmt.Errorf("two workers cannot have the same name: %q", o.name) + } } if o.env == nil { From 73d32661c8c80c5195e03fea69062d35395b7b13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 5 May 2025 13:50:40 +0200 Subject: [PATCH 51/51] minor changes --- caddy/caddy.go | 31 ++++++++++++++++--------------- request_options.go | 4 ++-- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/caddy/caddy.go b/caddy/caddy.go index e836cc53ad..5a54ca8e85 100644 --- a/caddy/caddy.go +++ b/caddy/caddy.go @@ -26,7 +26,10 @@ import ( "github.com/dunglas/frankenphp" ) -const defaultDocumentRoot = "public" +const ( + defaultDocumentRoot = "public" + defaultWatchPattern = "./**/*.{php,yaml,yml,twig,env}" +) var iniError = errors.New("'php_ini' must be in the format: php_ini \"\" \"\"") @@ -153,7 +156,7 @@ func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) { if d.NextArg() { if d.Val() == "watch" { - wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") + wc.Watch = append(wc.Watch, defaultWatchPattern) } else { v, err := strconv.ParseUint(d.Val(), 10, 32) if err != nil { @@ -204,7 +207,7 @@ func parseWorkerConfig(d *caddyfile.Dispenser) (workerConfig, error) { case "watch": if !d.NextArg() { // the default if the watch directory is left empty: - wc.Watch = append(wc.Watch, "./**/*.{php,yaml,yml,twig,env}") + wc.Watch = append(wc.Watch, defaultWatchPattern) } else { wc.Watch = append(wc.Watch, d.Val()) } @@ -491,7 +494,7 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c frankenphp.WithRequestSplitPath(f.SplitPath), frankenphp.WithRequestPreparedEnv(env), frankenphp.WithOriginalRequest(&origReq), - frankenphp.WithModuleWorker(workerName), + frankenphp.WithWorkerName(workerName), ) if err = frankenphp.ServeHTTP(w, fr); err != nil { @@ -502,24 +505,22 @@ func (f *FrankenPHPModule) ServeHTTP(w http.ResponseWriter, r *http.Request, _ c } func generateUniqueModuleWorkerName(filepath string) string { + var i uint name := "m#" + filepath - i := 0 + +outer: for { - nameExists := false for _, wc := range moduleWorkerConfigs { if wc.Name == name { - nameExists = true - break + name = fmt.Sprintf("m#%s_%d", filepath, i) + i++ + + continue outer } } - if !nameExists { - break - } - i++ - name = fmt.Sprintf("m#%s_%d", filepath, i) - } - return name + return name + } } // UnmarshalCaddyfile implements caddyfile.Unmarshaler. diff --git a/request_options.go b/request_options.go index d3212148a8..6c1cb59491 100644 --- a/request_options.go +++ b/request_options.go @@ -124,8 +124,8 @@ func WithRequestLogger(logger *slog.Logger) RequestOption { } } -// WithModuleWorker sets the worker that should handle the request -func WithModuleWorker(name string) RequestOption { +// WithWorkerName sets the worker that should handle the request +func WithWorkerName(name string) RequestOption { return func(o *frankenPHPContext) error { o.workerName = name