From 8f2a38e11bed732d51669b5f39e6e471b5da9b51 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 4 Aug 2023 20:35:56 +0300 Subject: [PATCH 01/14] cleaning up --- .env.example | 38 -------- Dockerfile | 21 ----- README.md | 22 ----- cmd/main.go | 34 ------- cmd/serve/config.go | 55 ------------ cmd/serve/middlewares.go | 78 ---------------- cmd/serve/serve.go | 186 --------------------------------------- go.mod | 24 ----- go.sum | 83 ----------------- pkg/fastcgi/client.go | 87 ------------------ pkg/fpm/config.ini | 14 --- pkg/fpm/fpm.go | 70 --------------- pkg/symbols/sym.go | 31 ------- 13 files changed, 743 deletions(-) delete mode 100644 .env.example delete mode 100644 Dockerfile delete mode 100644 README.md delete mode 100644 cmd/main.go delete mode 100644 cmd/serve/config.go delete mode 100644 cmd/serve/middlewares.go delete mode 100644 cmd/serve/serve.go delete mode 100644 go.mod delete mode 100644 go.sum delete mode 100644 pkg/fastcgi/client.go delete mode 100644 pkg/fpm/config.ini delete mode 100644 pkg/fpm/fpm.go delete mode 100644 pkg/symbols/sym.go diff --git a/.env.example b/.env.example deleted file mode 100644 index c32299c..0000000 --- a/.env.example +++ /dev/null @@ -1,38 +0,0 @@ -# the http server listening address (required) -# [host]: -PHOO_LISTEN="0.0.0.0:8000" - -# the document root (required) -# from where you would like to serve static files? -PHOO_DOCUMENT_ROOT="/var/www/html/public" - -# the router (required) -# where is your main script (the default script) -# till now we don't support serving multiple php files, it is only one, -# this works with modern frameworks -PHOO_ROUTER="/var/www/html/public/index.php" - -# whether to enable/disable logs (optional, default: true) -# logs here means the http server level logs -PHOO_LOGS=true - -# where is the php-fpm binary? (optional, default: php-fpm) -PHOO_FPM_BIN="php-fpm8.1" - -# the php-fpm workers count (optional, default: CPU cors count) -PHOO_WORKERS_COUNT=100 - -# the maximum number each worker should handle before restarting -# this prevent memory-leaks some how (required). -PHOO_WORKER_MAX_REQUESTS=100 - -# the maximum time the request should take before killing it and its worker -PHOO_REQUEST_TIMEOUT=15s - -# additional ini settings (optional, default: "") -# example: "extension=x.so;some_key=some_value;another_key=another_value" -PHOO_PHP_INI="" - -# the user and the group used to run PHP-FPM as, (optional, default: www-data) -PHOO_PHP_USER="www-data" -PHOO_PHP_GROUP="www-data" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 34122a2..0000000 --- a/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM golang:1.18-alpine As builder - -WORKDIR /phoo/ - -RUN apk update && apk add git upx - -COPY go.mod go.sum ./ - -RUN go mod download - -COPY . . - -RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o /usr/bin/phoo ./cmd/ - -RUN upx -9 /usr/bin/phoo - -FROM alpine - -WORKDIR /phoo/ - -COPY --from=builder /usr/bin/phoo /usr/bin/phoo \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 6b39ab6..0000000 --- a/README.md +++ /dev/null @@ -1,22 +0,0 @@ -PHOO -==== -> PHP high-performance application server and `php-fpm` supervisor. - -Why? -==== -> PHP isn't built for async world, so adopting the community, ecosystem and the mindset -> to be async isn't an easy task, -> but also I want very simple command to run, and it handles everything without too many configurations files, -> today most of the apps are using environment variables and the well-known `.env` file, so why there isn't a tool -> that you can ask to just run and configure everything from a single `.env` file, I don't want to add a hassle for understanding -> how `PHP-FPM` is working or anything else, all what I need it `$ phoo serve`, that's all. - -How? -==== -> Basically, `phoo` is a simple static-file as well a fastcgi reverse-proxy, but mainly focuses on `PHP`, not only that, -> but also, you can consider `phoo` a supervisor that manages `PHP-FPM` and its configurations to match today's setup. -> `phoo` is loading all the files in the document root into memory to accelerate static files serving, so don't put any huge file there. - -Usage? -====== -> for now, use our official docker image [here](https://github.com/alash3al/phoo/pkgs/container/phoo) \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 06bb5c8..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "github.com/alash3al/phoo/cmd/serve" - "github.com/alash3al/phoo/pkg/symbols" - "github.com/joho/godotenv" - "github.com/labstack/gommon/log" - "github.com/urfave/cli/v2" - "os" -) - -func main() { - app := cli.NewApp() - app.Name = symbols.AppName - app.Version = symbols.AppVersion - app.Before = func(ctxCli *cli.Context) error { - filename := ctxCli.String(symbols.FlagNameEnvFilename) - if len(filename) < 1 { - return nil - } - return godotenv.Load(filename) - } - - app.Flags = append(app.Flags, &cli.StringFlag{ - Name: symbols.FlagNameEnvFilename, - Usage: "if provided, the configuration values will be loaded from it", - }) - - app.Commands = append(app.Commands, serve.Command()) - - if err := app.Run(os.Args); err != nil { - log.Error(err.Error()) - } -} diff --git a/cmd/serve/config.go b/cmd/serve/config.go deleted file mode 100644 index b919925..0000000 --- a/cmd/serve/config.go +++ /dev/null @@ -1,55 +0,0 @@ -package serve - -import ( - "github.com/alash3al/phoo/pkg/fastcgi" - "github.com/alash3al/phoo/pkg/fpm" - "os" - "os/exec" - "os/signal" - "path/filepath" - "syscall" -) - -type Config struct { - FPM fpm.Config - FastCGI fastcgi.Config - HTTPListenAddr string - DocumentRoot string - EnableLogs bool -} - -func (c *Config) Verify() error { - paths := []*string{ - &(c.FPM.ConfigFilename), - &(c.FPM.PIDFilename), - &(c.FPM.SocketFilename), - &(c.FastCGI.DefaultScript), - &(c.DocumentRoot), - } - - for _, path := range paths { - abs, err := filepath.Abs(*path) - if err != nil { - return err - } - *path = abs - } - - c.FPM.Clean() - - if _, err := exec.LookPath(c.FPM.Bin); err != nil { - return err - } - - c.FastCGI.FastCGIServerURL = "unix://" + c.FPM.SocketFilename - - signalChannel := make(chan os.Signal, 2) - signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) - go func() { - _ = <-signalChannel - c.FPM.Clean() - os.Exit(0) - }() - - return nil -} diff --git a/cmd/serve/middlewares.go b/cmd/serve/middlewares.go deleted file mode 100644 index 698ea92..0000000 --- a/cmd/serve/middlewares.go +++ /dev/null @@ -1,78 +0,0 @@ -package serve - -import ( - "github.com/labstack/gommon/log" - "io/fs" - "mime" - "net/http" - "os" - "path/filepath" - "strings" - "sync" -) - -func loggerMiddleware(enable bool, handlerFunc http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - if enable { - log.Infoj(map[string]interface{}{ - "host": r.Host, - "uri": r.URL.RequestURI(), - }) - } - - handlerFunc(w, r) - } -} - -func recoverMiddleware(handlerFunc http.HandlerFunc) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - defer (func() { - if err := recover(); err != nil { - log.Error(err) - } - })() - - handlerFunc(w, r) - } -} - -func assetsCacheMiddleware(config *Config, handlerFunc http.HandlerFunc) (http.HandlerFunc, error) { - memfs := sync.Map{} - - if err := filepath.WalkDir(config.DocumentRoot, func(path string, d fs.DirEntry, err error) error { - if d.IsDir() { - return nil - } - - if filepath.Ext(config.DocumentRoot) == filepath.Ext(path) { - return nil - } - - if strings.HasPrefix(filepath.Base(path), ".") { - return nil - } - - data, err := os.ReadFile(path) - if err != nil { - return err - } - - memfs.Store(path, data) - - return nil - }); err != nil { - return nil, err - } - - return func(w http.ResponseWriter, r *http.Request) { - filename := filepath.Join(config.DocumentRoot, r.URL.Path) - contents, found := memfs.Load(filename) - if !found { - handlerFunc(w, r) - return - } - - w.Header().Set("Content-Type", mime.TypeByExtension(filepath.Ext(r.URL.Path))) - w.Write(contents.([]byte)) - }, nil -} diff --git a/cmd/serve/serve.go b/cmd/serve/serve.go deleted file mode 100644 index 2ed7454..0000000 --- a/cmd/serve/serve.go +++ /dev/null @@ -1,186 +0,0 @@ -package serve - -import ( - "fmt" - "github.com/NYTimes/gziphandler" - "github.com/alash3al/phoo/pkg/fastcgi" - "github.com/alash3al/phoo/pkg/fpm" - "github.com/alash3al/phoo/pkg/symbols" - "github.com/labstack/gommon/log" - "github.com/urfave/cli/v2" - "net/http" - "os" - "runtime" - "strings" - "time" -) - -func Command() *cli.Command { - return &cli.Command{ - Name: "serve", - Description: "start the http server", - Action: listenAndServe(), - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: symbols.FlagNameHTTPListenAddr, - Usage: "the http address to listen on", - EnvVars: []string{symbols.EnvKeyListen}, - Required: true, - Category: symbols.AppName, - }, - &cli.StringFlag{ - Name: symbols.FlagNameDocumentRoot, - Usage: "the document root", - EnvVars: []string{symbols.EnvKeyDocumentRoot}, - Required: true, - Category: symbols.AppName, - }, - &cli.BoolFlag{ - Name: symbols.FlagNameEnableLogs, - Usage: "whether to enable/disable access log", - EnvVars: []string{symbols.EnvKeyEnableLogs}, - Value: true, - Category: symbols.AppName, - }, - &cli.StringFlag{ - Name: symbols.FlagNamePHPFPMBinary, - Usage: "the PHP-FPM binary", - EnvVars: []string{symbols.EnvKeyFPMBin}, - Value: "php-fpm", - Category: "php", - }, - &cli.StringFlag{ - Name: symbols.FlagNamePHPINI, - Usage: "additional PHP INI settings separated with semicolon (;)", - EnvVars: []string{symbols.EnvKeyPHPINI}, - Category: "php", - }, - &cli.StringFlag{ - Name: symbols.FlagNamePHPUser, - Usage: "the user who will PHP-FPM listen as", - EnvVars: []string{symbols.EnvKeyPHPUser}, - Value: "www-data", - Category: "php", - }, - &cli.StringFlag{ - Name: symbols.FlagNamePHPGroup, - Usage: "the group who will PHP-FPM listen as", - EnvVars: []string{symbols.EnvKeyPHPGroup}, - Value: "www-data", - Category: "php", - }, - &cli.Int64Flag{ - Name: symbols.FlagNameWorkersCount, - Usage: "the PHP workers count", - EnvVars: []string{symbols.EnvKeyWorkersCount}, - Value: int64(runtime.NumCPU()), - Category: "php", - }, - &cli.Int64Flag{ - Name: symbols.FlagNameWorkerMaxRequests, - Usage: "the PHP worker max requests (the worker will be restarted after reaching this value)", - EnvVars: []string{symbols.EnvKeyWorkerMaxRequests}, - Value: 500, - Category: "php", - }, - &cli.StringFlag{ - Name: symbols.FlagNameRequestTimeout, - Usage: "the request timeout", - EnvVars: []string{symbols.EnvKeyRequestTimeout}, - Value: "0", - Category: "php", - }, - &cli.StringFlag{ - Name: symbols.FlagNameDefaultScript, - Usage: "the default script used as router", - EnvVars: []string{symbols.EnvKeyRouter}, - Required: true, - Category: "php", - }, - }, - } -} - -func listenAndServe() cli.ActionFunc { - return func(cliCtx *cli.Context) error { - config := Config{ - HTTPListenAddr: cliCtx.String(symbols.FlagNameHTTPListenAddr), - DocumentRoot: cliCtx.String(symbols.FlagNameDocumentRoot), - EnableLogs: cliCtx.Bool(symbols.FlagNameEnableLogs), - FPM: fpm.Config{ - ConfigFilename: ".fpm.config.ini", - PIDFilename: ".fpm.pid", - SocketFilename: ".fpm.sock", - User: cliCtx.String(symbols.FlagNamePHPUser), - Group: cliCtx.String(symbols.FlagNamePHPGroup), - Bin: cliCtx.String(symbols.FlagNamePHPFPMBinary), - RequestTimeout: cliCtx.String(symbols.FlagNameRequestTimeout), - WorkerMaxRequests: cliCtx.Int64(symbols.FlagNameWorkerMaxRequests), - WorkersCount: cliCtx.Int64(symbols.FlagNameWorkersCount), - INI: strings.Split(cliCtx.String(symbols.FlagNamePHPINI), ";"), - Stdout: os.Stdout, - Stderr: os.Stderr, - }, - FastCGI: fastcgi.Config{ - DefaultScript: cliCtx.String(symbols.FlagNameDefaultScript), - RestrictDotFilesAccess: true, - FastCGIParams: map[string]string{ - "SERVER_SOFTWARE": fmt.Sprintf("%s/%s", symbols.AppName, symbols.AppVersion), - }, - }, - } - - if err := config.Verify(); err != nil { - return err - } - - fastCGIHandler, err := fastcgi.New(config.FastCGI) - if err != nil { - return err - } - - mainHandler, err := assetsCacheMiddleware(&config, recoverMiddleware( - fastCGIHandler.ServeHTTP, - )) - - if err != nil { - return err - } - - runner, err := fpm.New(config.FPM) - if err != nil { - return err - } - - for { - if _, err := os.Stat(config.FPM.SocketFilename); err != nil { - log.Warn("waiting till fastcgi server starts ...") - time.Sleep(time.Second * 1) - continue - } - - log.Info("the fastcgi server has been started ...") - break - } - - go (func() { - if err := runner.Wait(); err != nil { - log.Fatal(err.Error()) - } - })() - - log.Infoj(map[string]interface{}{ - "message": "configurations", - "configs": config, - "fpm-cmd": runner.String(), - }) - - return http.ListenAndServe( - config.HTTPListenAddr, - gziphandler.GzipHandler(loggerMiddleware( - config.EnableLogs, - mainHandler, - )), - ) - } -} diff --git a/go.mod b/go.mod deleted file mode 100644 index 7835ca6..0000000 --- a/go.mod +++ /dev/null @@ -1,24 +0,0 @@ -module github.com/alash3al/phoo - -go 1.19 - -require ( - github.com/NYTimes/gziphandler v1.1.1 - github.com/joho/godotenv v1.4.0 - github.com/labstack/gommon v0.4.0 - github.com/urfave/cli/v2 v2.23.7 - github.com/yookoala/gofast v0.7.0 -) - -require ( - github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/stretchr/testify v1.8.1 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect - github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/sys v0.3.0 // indirect - golang.org/x/tools v0.1.12 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index a307e58..0000000 --- a/go.sum +++ /dev/null @@ -1,83 +0,0 @@ -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= -github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-restit/lzjson v0.0.0-20161206095556-efe3c53acc68/go.mod h1:7vXSKQt83WmbPeyVjCfNT9YDJ5BUFmcwFsEjI9SCvYM= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= -github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= -github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= -github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -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/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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/urfave/cli/v2 v2.23.7 h1:YHDQ46s3VghFHFf1DdF+Sh7H4RqhcM+t0TmZRJx4oJY= -github.com/urfave/cli/v2 v2.23.7/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= -github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= -github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -github.com/yookoala/gofast v0.7.0 h1:wVqXc+S0FDmlkieRNDxabGRX44znHT++Hb9lEfWi4iM= -github.com/yookoala/gofast v0.7.0/go.mod h1:OJU201Q6HCaE1cASckaTbMm3KB6e0cZxK0mgqfwOKvQ= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200908211811-12e1bf57a112/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/fastcgi/client.go b/pkg/fastcgi/client.go deleted file mode 100644 index e294a41..0000000 --- a/pkg/fastcgi/client.go +++ /dev/null @@ -1,87 +0,0 @@ -package fastcgi - -import ( - "errors" - "github.com/yookoala/gofast" - "net/http" - "strings" -) - -type Config struct { - FastCGIServerURL string - DefaultScript string - RestrictDotFilesAccess bool - FastCGIParams map[string]string -} - -type Client struct { - config Config - handler http.Handler - fastCGIServerNetwork string - fastCGIServerAddr string - defaultScriptExtension string -} - -func New(config Config) (*Client, error) { - client := Client{ - config: config, - } - - if err := client.setFastCGIServerDetails(); err != nil { - return nil, err - } - - client.setFastCGIHandler() - - return &client, nil -} - -func (c *Client) setFastCGIServerDetails() error { - urlParts := strings.Split(c.config.FastCGIServerURL, "://") - - if len(urlParts) != 2 { - return errors.New("invalid 'FastCGI Server Address' specified") - } - - c.fastCGIServerNetwork = urlParts[0] - c.fastCGIServerAddr = urlParts[1] - - return nil -} - -func (c *Client) setFastCGIHandler() { - sessionHandler := gofast.Chain( - gofast.MapHeader, - gofast.BasicParamsMap, - gofast.MapRemoteHost, - c.addParams(c.config.FastCGIParams), - )(gofast.BasicSession) - - c.handler = gofast.NewHandler( - gofast.NewFileEndpoint(c.config.DefaultScript)(sessionHandler), - gofast.SimpleClientFactory( - gofast.SimpleConnFactory( - c.fastCGIServerNetwork, - c.fastCGIServerAddr, - ), - ), - ) -} - -func (c *Client) addParams(params map[string]string) gofast.Middleware { - return func(inner gofast.SessionHandler) gofast.SessionHandler { - return func(client gofast.Client, req *gofast.Request) (*gofast.ResponsePipe, error) { - req.KeepConn = true - - for k, v := range params { - req.Params[k] = v - } - - return inner(client, req) - } - } -} - -func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { - c.handler.ServeHTTP(w, r) -} diff --git a/pkg/fpm/config.ini b/pkg/fpm/config.ini deleted file mode 100644 index 4f4dc1d..0000000 --- a/pkg/fpm/config.ini +++ /dev/null @@ -1,14 +0,0 @@ -[global] -pid = {{.PIDFilename}} -error_log = /dev/null - -[www] -user = {{.User}} -group = {{.Group}} -listen = {{.SocketFilename}} - -pm = static -pm.max_children = {{.WorkersCount}} -pm.max_requests = {{.WorkerMaxRequests}} -request_terminate_timeout = {{.RequestTimeout}} -clear_env = no \ No newline at end of file diff --git a/pkg/fpm/fpm.go b/pkg/fpm/fpm.go deleted file mode 100644 index 89f377a..0000000 --- a/pkg/fpm/fpm.go +++ /dev/null @@ -1,70 +0,0 @@ -package fpm - -import ( - "bytes" - _ "embed" - "io" - "os" - "os/exec" - "strings" - "text/template" -) - -//go:embed config.ini -var configTemplate string - -type Config struct { - PIDFilename string - SocketFilename string - ConfigFilename string - User string - Group string - Bin string - WorkersCount int64 - WorkerMaxRequests int64 - RequestTimeout string - INI []string - Stdout io.Writer - Stderr io.Writer -} - -func (c *Config) Clean() { - _ = os.Remove(c.ConfigFilename) - _ = os.Remove(c.PIDFilename) - _ = os.Remove(c.SocketFilename) -} - -func New(config Config) (*exec.Cmd, error) { - tpl, err := template.New("template").Parse(configTemplate) - if err != nil { - return nil, err - } - - var finalConfig bytes.Buffer - - if err := tpl.Execute(&finalConfig, config); err != nil { - return nil, err - } - - if err := os.WriteFile(config.ConfigFilename, finalConfig.Bytes(), 0755); err != nil { - return nil, err - } - - cmd := exec.Command(config.Bin, "-F", "-O", "-y", config.ConfigFilename) - cmd.Stdout = config.Stdout - cmd.Stderr = config.Stderr - cmd.Env = os.Environ() - - for _, entry := range config.INI { - entry = strings.TrimSpace(entry) - if entry != "" { - cmd.Args = append(cmd.Args, "-d", entry) - } - } - - if err := cmd.Start(); err != nil { - return nil, err - } - - return cmd, nil -} diff --git a/pkg/symbols/sym.go b/pkg/symbols/sym.go deleted file mode 100644 index 2e7e2a7..0000000 --- a/pkg/symbols/sym.go +++ /dev/null @@ -1,31 +0,0 @@ -package symbols - -const ( - AppName = "phoo" - AppVersion = "v2.0.0" - - FlagNameHTTPListenAddr = "listen" - FlagNameDocumentRoot = "root" - FlagNamePHPFPMBinary = "php-fpm" - FlagNamePHPINI = "php-ini" - FlagNamePHPUser = "php-user" - FlagNamePHPGroup = "php-group" - FlagNameWorkersCount = "workers" - FlagNameWorkerMaxRequests = "worker-max-requests" - FlagNameRequestTimeout = "timeout" - FlagNameDefaultScript = "router" - FlagNameEnableLogs = "logs" - FlagNameEnvFilename = "env-file" - - EnvKeyDocumentRoot = "PHOO_DOCUMENT_ROOT" - EnvKeyListen = "PHOO_LISTEN" - EnvKeyFPMBin = "PHOO_FPM_BIN" - EnvKeyWorkersCount = "PHOO_WORKERS_COUNT" - EnvKeyWorkerMaxRequests = "PHOO_WORKER_MAX_REQUESTS" - EnvKeyRequestTimeout = "PHOO_REQUEST_TIMEOUT" - EnvKeyRouter = "PHOO_ROUTER" - EnvKeyEnableLogs = "PHOO_LOGS" - EnvKeyPHPINI = "PHOO_PHP_INI" - EnvKeyPHPUser = "PHOO_PHP_USER" - EnvKeyPHPGroup = "PHOO_PHP_GROUP" -) From e1bbe6c57b028035fc3a4660fdd0ba2958547d52 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Sat, 5 Aug 2023 00:14:06 +0300 Subject: [PATCH 02/14] refactoring to simplify the codebase --- fpm.go | 45 ++++++++++++++++++++++++++ go.mod | 28 ++++++++++++++++ go.sum | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ init.go | 78 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 30 +++++++++++++++++ middlewares.go | 36 +++++++++++++++++++++ php-fpm.conf | 12 +++++++ 7 files changed, 317 insertions(+) create mode 100644 fpm.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 init.go create mode 100644 main.go create mode 100644 middlewares.go create mode 100644 php-fpm.conf diff --git a/fpm.go b/fpm.go new file mode 100644 index 0000000..15ab1d4 --- /dev/null +++ b/fpm.go @@ -0,0 +1,45 @@ +package main + +import ( + "os" + "os/exec" + "strings" + "time" +) + +func startPHPFPM() error { + cmd := exec.Command(*flagFPMCommand, "-F", "-O", "-y", fpmConfigFilename) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = os.Environ() + + for _, entry := range strings.Split(*flagPHPINIVars, ";") { + entry = strings.TrimSpace(entry) + if entry != "" { + cmd.Args = append(cmd.Args, "-d", entry) + } + } + + if err := cmd.Start(); err != nil { + return err + } + + for { + if _, err := os.Stat(fpmSocketFilename); err != nil { + server.Logger.Warn("waiting till php-fpm starts ...") + time.Sleep(1 * time.Second) + continue + } + + server.Logger.Info("the php-fpm process has been started ...") + break + } + + go (func() { + if err := cmd.Wait(); err != nil { + server.Logger.Fatal(err.Error()) + } + })() + + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..539c53d --- /dev/null +++ b/go.mod @@ -0,0 +1,28 @@ +module github.com/alash3al/phoo + +go 1.20 + +require ( + github.com/labstack/echo/v4 v4.11.1 + github.com/urfave/cli/v2 v2.25.7 +) + +require ( + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/labstack/gommon v0.4.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect + github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect + github.com/yookoala/gofast v0.7.0 // indirect + golang.org/x/crypto v0.11.0 // indirect + golang.org/x/net v0.12.0 // indirect + golang.org/x/sys v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.6.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..667dbb8 --- /dev/null +++ b/go.sum @@ -0,0 +1,88 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-restit/lzjson v0.0.0-20161206095556-efe3c53acc68/go.mod h1:7vXSKQt83WmbPeyVjCfNT9YDJ5BUFmcwFsEjI9SCvYM= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= +github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= +github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= +github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= +github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= +github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +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/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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= +github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= +github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yookoala/gofast v0.7.0 h1:wVqXc+S0FDmlkieRNDxabGRX44znHT++Hb9lEfWi4iM= +github.com/yookoala/gofast v0.7.0/go.mod h1:OJU201Q6HCaE1cASckaTbMm3KB6e0cZxK0mgqfwOKvQ= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200908211811-12e1bf57a112/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/init.go b/init.go new file mode 100644 index 0000000..b79327f --- /dev/null +++ b/init.go @@ -0,0 +1,78 @@ +package main + +import ( + _ "embed" + "flag" + "fmt" + "github.com/labstack/echo/v4" + "github.com/valyala/fasttemplate" + "log" + "os" + "path/filepath" + "runtime" +) + +var ( + flagHttpListenAddr = flag.String("listen", ":8000", "the http server listen address in the form of [host]:port") + flagEnableLogging = flag.Bool("logging", false, "whether to enable logging or not") + flagGzipLevel = flag.Int("gzip", 0, "gzip level, 0 means disable") + flagDocumentRoot = flag.String("docroot", "./", "the webserver document root") + flagRouterFileName = flag.String("script", "./index.php", "the default script filename") + flagFPMCommand = flag.String("fpm.cmd", "php-fpm", "the php-fpm command") + flagFPMWorkerCount = flag.Int("fpm.worker.count", runtime.NumCPU(), "the fpm workers count") + flagFPMWorkerMaxRequests = flag.Int("fpm.worker.max_requests", 500, "the maximum number of requests that a single worker will restart after reaching it") + flagFPMRequestTimeout = flag.Int("fpm.request.timeout", -1, "the request timeout") + flagPHPINIVars = flag.String("php.ini", "", "semicolon delimited string of ini key=value pairs") +) + +var ( + //go:embed php-fpm.conf + fpmConfTemplate string + + fpmPIDFilename string + fpmConfigFilename string + fpmSocketFilename string + + server = echo.New() +) + +func init() { + flag.Parse() + + server.HideBanner = true + + for _, p := range []*string{flagDocumentRoot, flagRouterFileName} { + if abs, err := filepath.Abs(*p); err != nil { + log.Fatal(err.Error()) + } else { + *p = abs + } + } + + _ = os.RemoveAll(".phoo") + + if err := os.MkdirAll(".phoo/fpm", 0775); err != nil && !os.IsExist(err) { + log.Fatal(err.Error()) + } + + phooDir, err := filepath.Abs(".phoo") + if err != nil { + server.Logger.Fatal(err.Error()) + } + + fpmConfigFilename = filepath.Join(phooDir, "fpm", "config") + fpmPIDFilename = filepath.Join(phooDir, "fpm", "pid") + fpmSocketFilename = filepath.Join(phooDir, "fpm", "sock") + + fpmConfTemplate = fasttemplate.ExecuteString(fpmConfTemplate, "{{", "}}", map[string]any{ + "files.pid": fpmPIDFilename, + "files.socket": fpmSocketFilename, + "worker.count": fmt.Sprintf("%d", *flagFPMWorkerCount), + "worker.max_requests": fmt.Sprintf("%d", *flagFPMWorkerMaxRequests), + "timeout": fmt.Sprintf("%d", *flagFPMRequestTimeout), + }) + + if err := os.WriteFile(fpmConfigFilename, []byte(fpmConfTemplate), 0775); err != nil { + server.Logger.Fatal(err.Error()) + } +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..b9b6fc6 --- /dev/null +++ b/main.go @@ -0,0 +1,30 @@ +package main + +import ( + "github.com/labstack/echo/v4/middleware" + "log" +) + +func main() { + if *flagEnableLogging { + server.Use(middleware.Logger()) + } + + server.Use(middleware.GzipWithConfig(middleware.GzipConfig{ + Level: *flagGzipLevel, + })) + + server.Use(middleware.Recover()) + server.Use(serveStaticFilesOnlyMiddleware(*flagDocumentRoot)) + server.Use(serveFastCGIMiddleware( + *flagRouterFileName, + "unix", + fpmSocketFilename, + )) + + if err := startPHPFPM(); err != nil { + server.Logger.Fatal(err.Error()) + } + + log.Fatal(server.Start(*flagHttpListenAddr)) +} diff --git a/middlewares.go b/middlewares.go new file mode 100644 index 0000000..3baba36 --- /dev/null +++ b/middlewares.go @@ -0,0 +1,36 @@ +package main + +import ( + "github.com/labstack/echo/v4" + "github.com/yookoala/gofast" + "os" + "path" + "strings" +) + +func serveStaticFilesOnlyMiddleware(documentRoot string) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + filename := path.Join(documentRoot, path.Clean(c.Request().URL.Path)) + ext := strings.ToLower(path.Ext(filename)) + + stat, err := os.Stat(filename) + if err != nil || stat.IsDir() || (ext == "php") || strings.HasPrefix(path.Base(filename), ".") { + return next(c) + } + + return c.File(filename) + } + } +} + +func serveFastCGIMiddleware(routerFilename, fastcgiServerNetwork, fastcgiServerAddr string) echo.MiddlewareFunc { + connFactory := gofast.SimpleConnFactory(fastcgiServerNetwork, fastcgiServerAddr) + + return func(next echo.HandlerFunc) echo.HandlerFunc { + return echo.WrapHandler(gofast.NewHandler( + gofast.NewFileEndpoint(routerFilename)(gofast.BasicSession), + gofast.SimpleClientFactory(connFactory), + )) + } +} diff --git a/php-fpm.conf b/php-fpm.conf new file mode 100644 index 0000000..1350ba2 --- /dev/null +++ b/php-fpm.conf @@ -0,0 +1,12 @@ +[global] +pid = "{{files.pid}}" +error_log = /dev/null + +[www] +listen = "{{files.socket}}" + +pm = static +pm.max_children = {{worker.count}} +pm.max_requests = {{worker.max_requests}} +request_terminate_timeout = {{timeout}} +clear_env = no From 23b13ba030eae746270e34f3f4e69ca9dbf19a71 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Sun, 6 Aug 2023 14:38:46 +0300 Subject: [PATCH 03/14] finalized the revamp cleanup --- cmd/main.go | 48 ++++++++ middlewares.go => cmd/server/middlewares.go | 2 +- cmd/server/server.go | 79 +++++++++++++ example/css/style.css | 7 ++ example/index.php | 13 +++ example/phoo.yaml | 18 +++ fpm.go | 45 -------- go.mod | 8 +- go.sum | 3 +- init.go | 78 ------------- internals/config/parser.go | 109 ++++++++++++++++++ php-fpm.conf => internals/config/php-fpm.conf | 8 +- main.go | 30 ----- 13 files changed, 285 insertions(+), 163 deletions(-) create mode 100644 cmd/main.go rename middlewares.go => cmd/server/middlewares.go (98%) create mode 100644 cmd/server/server.go create mode 100644 example/css/style.css create mode 100644 example/index.php create mode 100644 example/phoo.yaml delete mode 100644 fpm.go delete mode 100644 init.go create mode 100644 internals/config/parser.go rename php-fpm.conf => internals/config/php-fpm.conf (54%) delete mode 100644 main.go diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 0000000..4885f07 --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "github.com/alash3al/phoo/cmd/server" + "github.com/alash3al/phoo/internals/config" + "github.com/urfave/cli/v2" + "log" + "os" +) + +var ( + globalConfig config.Config +) + +func main() { + app := &cli.App{ + Name: "phoo", + Description: "php modern applications server that utilizes the bullet-proof php-fpm under-the-hood", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + EnvVars: []string{"PHOO_CONFIG"}, + Value: "phoo.yaml", + }, + }, + Before: func(ctx *cli.Context) error { + c, err := config.LoadFile(ctx.String("config")) + if err != nil { + return err + } + + globalConfig = *c + + return nil + }, + } + + app.Commands = append(app.Commands, &cli.Command{ + Name: "serve", + Aliases: []string{"s"}, + Action: server.Serve(&globalConfig), + }) + + if err := app.Run(os.Args); err != nil { + log.Fatal(err.Error()) + } +} diff --git a/middlewares.go b/cmd/server/middlewares.go similarity index 98% rename from middlewares.go rename to cmd/server/middlewares.go index 3baba36..09dc3f2 100644 --- a/middlewares.go +++ b/cmd/server/middlewares.go @@ -1,4 +1,4 @@ -package main +package server import ( "github.com/labstack/echo/v4" diff --git a/cmd/server/server.go b/cmd/server/server.go new file mode 100644 index 0000000..3e3e929 --- /dev/null +++ b/cmd/server/server.go @@ -0,0 +1,79 @@ +package server + +import ( + "fmt" + "github.com/alash3al/phoo/internals/config" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/urfave/cli/v2" + "log" + "os" + "os/exec" + "time" +) + +func Serve(conf *config.Config) cli.ActionFunc { + return func(ctx *cli.Context) error { + e := echo.New() + e.HideBanner = true + + if conf.EnableAccessLogs { + e.Use(middleware.Logger()) + } + + e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ + Level: conf.GZIPLevel, + })) + + e.Use(middleware.Recover()) + e.Use(serveStaticFilesOnlyMiddleware(conf.DocumentRoot)) + e.Use(serveFastCGIMiddleware( + conf.DefaultScript, + "unix", + conf.FPM.SocketFilename, + )) + + if err := startPHPFPM(conf); err != nil { + e.Logger.Fatal(err.Error()) + } + + return e.Start(conf.HTTPListenAddr) + } +} + +func startPHPFPM(conf *config.Config) error { + cmd := exec.Command(conf.FPM.Bin, "-F", "-O", "-y", conf.FPM.ConfigFilename) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + for k, v := range conf.Env { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) + } + + cmd.Env = append(cmd.Env, os.Environ()...) + + for k, v := range conf.INI { + cmd.Args = append(cmd.Args, "-d", fmt.Sprintf("%s=%s", k, v)) + } + + if err := cmd.Start(); err != nil { + return err + } + + for { + if _, err := os.Stat(conf.FPM.SocketFilename); err != nil { + time.Sleep(1 * time.Second) + continue + } + + break + } + + go (func() { + if err := cmd.Wait(); err != nil { + log.Fatal(err.Error()) + } + })() + + return nil +} diff --git a/example/css/style.css b/example/css/style.css new file mode 100644 index 0000000..f69c279 --- /dev/null +++ b/example/css/style.css @@ -0,0 +1,7 @@ +body { + font-weight: bold; + font-size: 100px; + color: #444; + text-align: center; + margin: auto; +} \ No newline at end of file diff --git a/example/index.php b/example/index.php new file mode 100644 index 0000000..3137003 --- /dev/null +++ b/example/index.php @@ -0,0 +1,13 @@ +"; + +echo "PHOOOOOOOO ;)"; + +echo sprintf(<<<"HTML" +
+         
+             %s
+         
+     
+HTML, print_r($_SERVER, true)); diff --git a/example/phoo.yaml b/example/phoo.yaml new file mode 100644 index 0000000..cdaa4af --- /dev/null +++ b/example/phoo.yaml @@ -0,0 +1,18 @@ +document_root: "./example" +default_script: "./example/index.php" +gzip_level: 0 +http_listen_addr: ":8000" +data_dir: ".phoo" +enable_access_logs: true + +env: + APP_NAME: "laravel" + APP_ENV: "debug" + +fpm: + bin: "php-fpm8.2" + worker_count: 8 + worker_max_requests: 500 + +ini: + display_errors: On diff --git a/fpm.go b/fpm.go deleted file mode 100644 index 15ab1d4..0000000 --- a/fpm.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "os" - "os/exec" - "strings" - "time" -) - -func startPHPFPM() error { - cmd := exec.Command(*flagFPMCommand, "-F", "-O", "-y", fpmConfigFilename) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - cmd.Env = os.Environ() - - for _, entry := range strings.Split(*flagPHPINIVars, ";") { - entry = strings.TrimSpace(entry) - if entry != "" { - cmd.Args = append(cmd.Args, "-d", entry) - } - } - - if err := cmd.Start(); err != nil { - return err - } - - for { - if _, err := os.Stat(fpmSocketFilename); err != nil { - server.Logger.Warn("waiting till php-fpm starts ...") - time.Sleep(1 * time.Second) - continue - } - - server.Logger.Info("the php-fpm process has been started ...") - break - } - - go (func() { - if err := cmd.Wait(); err != nil { - server.Logger.Fatal(err.Error()) - } - })() - - return nil -} diff --git a/go.mod b/go.mod index 539c53d..e8d05a2 100644 --- a/go.mod +++ b/go.mod @@ -4,25 +4,25 @@ go 1.20 require ( github.com/labstack/echo/v4 v4.11.1 - github.com/urfave/cli/v2 v2.25.7 + github.com/valyala/fasttemplate v1.2.2 + github.com/yookoala/gofast v0.7.0 ) require ( github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect - github.com/joho/godotenv v1.5.1 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/urfave/cli/v2 v2.25.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasttemplate v1.2.2 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - github.com/yookoala/gofast v0.7.0 // indirect golang.org/x/crypto v0.11.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 667dbb8..ab0a35c 100644 --- a/go.sum +++ b/go.sum @@ -8,8 +8,6 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= @@ -86,3 +84,4 @@ gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/init.go b/init.go deleted file mode 100644 index b79327f..0000000 --- a/init.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - _ "embed" - "flag" - "fmt" - "github.com/labstack/echo/v4" - "github.com/valyala/fasttemplate" - "log" - "os" - "path/filepath" - "runtime" -) - -var ( - flagHttpListenAddr = flag.String("listen", ":8000", "the http server listen address in the form of [host]:port") - flagEnableLogging = flag.Bool("logging", false, "whether to enable logging or not") - flagGzipLevel = flag.Int("gzip", 0, "gzip level, 0 means disable") - flagDocumentRoot = flag.String("docroot", "./", "the webserver document root") - flagRouterFileName = flag.String("script", "./index.php", "the default script filename") - flagFPMCommand = flag.String("fpm.cmd", "php-fpm", "the php-fpm command") - flagFPMWorkerCount = flag.Int("fpm.worker.count", runtime.NumCPU(), "the fpm workers count") - flagFPMWorkerMaxRequests = flag.Int("fpm.worker.max_requests", 500, "the maximum number of requests that a single worker will restart after reaching it") - flagFPMRequestTimeout = flag.Int("fpm.request.timeout", -1, "the request timeout") - flagPHPINIVars = flag.String("php.ini", "", "semicolon delimited string of ini key=value pairs") -) - -var ( - //go:embed php-fpm.conf - fpmConfTemplate string - - fpmPIDFilename string - fpmConfigFilename string - fpmSocketFilename string - - server = echo.New() -) - -func init() { - flag.Parse() - - server.HideBanner = true - - for _, p := range []*string{flagDocumentRoot, flagRouterFileName} { - if abs, err := filepath.Abs(*p); err != nil { - log.Fatal(err.Error()) - } else { - *p = abs - } - } - - _ = os.RemoveAll(".phoo") - - if err := os.MkdirAll(".phoo/fpm", 0775); err != nil && !os.IsExist(err) { - log.Fatal(err.Error()) - } - - phooDir, err := filepath.Abs(".phoo") - if err != nil { - server.Logger.Fatal(err.Error()) - } - - fpmConfigFilename = filepath.Join(phooDir, "fpm", "config") - fpmPIDFilename = filepath.Join(phooDir, "fpm", "pid") - fpmSocketFilename = filepath.Join(phooDir, "fpm", "sock") - - fpmConfTemplate = fasttemplate.ExecuteString(fpmConfTemplate, "{{", "}}", map[string]any{ - "files.pid": fpmPIDFilename, - "files.socket": fpmSocketFilename, - "worker.count": fmt.Sprintf("%d", *flagFPMWorkerCount), - "worker.max_requests": fmt.Sprintf("%d", *flagFPMWorkerMaxRequests), - "timeout": fmt.Sprintf("%d", *flagFPMRequestTimeout), - }) - - if err := os.WriteFile(fpmConfigFilename, []byte(fpmConfTemplate), 0775); err != nil { - server.Logger.Fatal(err.Error()) - } -} diff --git a/internals/config/parser.go b/internals/config/parser.go new file mode 100644 index 0000000..53b30bd --- /dev/null +++ b/internals/config/parser.go @@ -0,0 +1,109 @@ +package config + +import ( + _ "embed" + "fmt" + "github.com/valyala/fasttemplate" + "gopkg.in/yaml.v3" + "os" + "os/exec" + "path/filepath" + "runtime" +) + +var ( + //go:embed php-fpm.conf + fpmConfContent string +) + +type Config struct { + DocumentRoot string `yaml:"document_root"` + DefaultScript string `yaml:"default_script"` + GZIPLevel int `yaml:"gzip_level"` + HTTPListenAddr string `yaml:"http_listen_addr"` + EnableAccessLogs bool `yaml:"enable_access_logs"` + DataDir string `yaml:"data_dir"` + + Env map[string]string `yaml:"env"` + + INI map[string]string `yaml:"ini"` + + FPM struct { + Bin string `yaml:"bin"` + WorkerCount int `yaml:"worker_count"` + WorkerMaxRequests int `yaml:"worker_max_requests"` + TerminationTimeout int `yaml:"termination_timeout"` + ConfigContent string `yaml:"-"` + ConfigFilename string `yaml:"-"` + PIDFilename string `yaml:"-"` + SocketFilename string `yaml:"-"` + Command *exec.Cmd `yaml:"-"` + } `yaml:"fpm"` +} + +func LoadFile(filename string) (*Config, error) { + content, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + + content = []byte(os.ExpandEnv(string(content))) + + var c Config + + if err := yaml.Unmarshal(content, &c); err != nil { + return nil, err + } + + if err := c.verify(); err != nil { + return nil, err + } + + return &c, nil +} + +func (c *Config) verify() error { + if _, err := os.Stat(c.DefaultScript); err != nil { + return err + } + + for _, p := range []*string{&(c.DefaultScript), &(c.DataDir)} { + if abs, err := filepath.Abs(*p); err != nil { + return err + } else { + *p = abs + } + } + + _ = os.RemoveAll(c.DataDir) + + fpmDir := filepath.Join(c.DataDir, "fpm") + + for _, p := range []string{c.DataDir, fpmDir} { + if err := os.MkdirAll(p, 0755); err != nil { + return err + } + } + + if c.FPM.WorkerCount < 1 { + c.FPM.WorkerCount = runtime.NumCPU() + } + + c.FPM.ConfigFilename = filepath.Join(fpmDir, "fpm.ini") + c.FPM.PIDFilename = filepath.Join(fpmDir, "fpm.pid") + c.FPM.SocketFilename = filepath.Join(fpmDir, "fpm.sock") + + fpmConfContent = fasttemplate.ExecuteString(fpmConfContent, "{{", "}}", map[string]any{ + "files.pid": c.FPM.PIDFilename, + "files.socket": c.FPM.SocketFilename, + "worker.count": fmt.Sprintf("%v", c.FPM.WorkerCount), + "worker.max_requests": fmt.Sprintf("%v", c.FPM.WorkerMaxRequests), + "termination_timeout": fmt.Sprintf("%v", c.FPM.TerminationTimeout), + }) + + if err := os.WriteFile(c.FPM.ConfigFilename, []byte(fpmConfContent), 0755); err != nil { + return err + } + + return nil +} diff --git a/php-fpm.conf b/internals/config/php-fpm.conf similarity index 54% rename from php-fpm.conf rename to internals/config/php-fpm.conf index 1350ba2..2f479db 100644 --- a/php-fpm.conf +++ b/internals/config/php-fpm.conf @@ -1,12 +1,14 @@ [global] pid = "{{files.pid}}" -error_log = /dev/null +log_level = "error" +error_log = "/dev/null" +daemonize = no +process_control_timeout = 5s [www] listen = "{{files.socket}}" - pm = static pm.max_children = {{worker.count}} pm.max_requests = {{worker.max_requests}} -request_terminate_timeout = {{timeout}} +request_terminate_timeout = {{termination_timeout}} clear_env = no diff --git a/main.go b/main.go deleted file mode 100644 index b9b6fc6..0000000 --- a/main.go +++ /dev/null @@ -1,30 +0,0 @@ -package main - -import ( - "github.com/labstack/echo/v4/middleware" - "log" -) - -func main() { - if *flagEnableLogging { - server.Use(middleware.Logger()) - } - - server.Use(middleware.GzipWithConfig(middleware.GzipConfig{ - Level: *flagGzipLevel, - })) - - server.Use(middleware.Recover()) - server.Use(serveStaticFilesOnlyMiddleware(*flagDocumentRoot)) - server.Use(serveFastCGIMiddleware( - *flagRouterFileName, - "unix", - fpmSocketFilename, - )) - - if err := startPHPFPM(); err != nil { - server.Logger.Fatal(err.Error()) - } - - log.Fatal(server.Start(*flagHttpListenAddr)) -} From c6c8c628ed4fd6e36fefa2ca5d131c5158d0bf2d Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Sun, 6 Aug 2023 14:48:34 +0300 Subject: [PATCH 04/14] updated phoo.yaml --- example/phoo.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/phoo.yaml b/example/phoo.yaml index cdaa4af..a3603c0 100644 --- a/example/phoo.yaml +++ b/example/phoo.yaml @@ -11,7 +11,7 @@ env: fpm: bin: "php-fpm8.2" - worker_count: 8 + worker_count: 4 worker_max_requests: 500 ini: From 1099e2cea5645431aeb7e660dcff980435e87e76 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Thu, 10 Aug 2023 21:53:53 +0300 Subject: [PATCH 05/14] continuing the revamp --- cmd/etc.go | 3 ++ cmd/server/flags.go | 55 +++++++++++++++++++++++ go.mod | 8 ++-- go.sum | 6 +++ internals/config/parser.go | 84 ++++++++++++++++------------------- internals/config/php-fpm.conf | 2 +- 6 files changed, 109 insertions(+), 49 deletions(-) create mode 100644 cmd/etc.go create mode 100644 cmd/server/flags.go diff --git a/cmd/etc.go b/cmd/etc.go new file mode 100644 index 0000000..15c97c2 --- /dev/null +++ b/cmd/etc.go @@ -0,0 +1,3 @@ +package main + +func defaultServeFlags diff --git a/cmd/server/flags.go b/cmd/server/flags.go new file mode 100644 index 0000000..7772c36 --- /dev/null +++ b/cmd/server/flags.go @@ -0,0 +1,55 @@ +package server + +import ( + "fmt" + "github.com/urfave/cli/v2" +) + +func DefaultFlags(envPrefix string, append ...[]cli.Flag) []cli.Flag { + prefixWrapper := func(k string) string { + return fmt.Sprintf("%s_%s", envPrefix, k) + } + + return []cli.Flag{ + &cli.StringFlag{ + Name: "metrics", + Usage: "the prometheus metrics endpoint, empty means disabled", + EnvVars: []string{prefixWrapper("METRICS_PATH")}, + }, + + &cli.StringFlag{ + Name: "root", + Usage: "the document root full path", + EnvVars: []string{prefixWrapper("DOCUMENT_ROOT")}, + Required: true, + }, + + &cli.StringFlag{ + Name: "entrypoint", + Usage: "the default php entrypoint script", + EnvVars: []string{"ENTRYPOINT"}, + Required: true, + }, + + &cli.StringFlag{ + Name: "http", + Usage: "the http listen address in the form of [address]:port", + EnvVars: []string{prefixWrapper("HTTP_LISTEN_ADDR")}, + Value: ":8000", + }, + + &cli.BoolFlag{ + Name: "logs", + Usage: "whether to enable access logs or not", + EnvVars: []string{prefixWrapper("ENABLE_ACCESS_LOGS")}, + Value: false, + }, + + &cli.StringFlag{ + Name: "fpm", + Usage: "the php-fpm binary filename", + EnvVars: []string{"PHP_FPM"}, + Value: "php-fpm", + }, + } +} diff --git a/go.mod b/go.mod index e8d05a2..fc3f846 100644 --- a/go.mod +++ b/go.mod @@ -1,21 +1,24 @@ module github.com/alash3al/phoo -go 1.20 +go 1.21 require ( github.com/labstack/echo/v4 v4.11.1 + github.com/urfave/cli/v2 v2.25.7 github.com/valyala/fasttemplate v1.2.2 github.com/yookoala/gofast v0.7.0 + gopkg.in/yaml.v3 v3.0.1 ) require ( + github.com/caarlos0/env/v9 v9.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/urfave/cli/v2 v2.25.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect golang.org/x/crypto v0.11.0 // indirect @@ -24,5 +27,4 @@ require ( golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index ab0a35c..09c2a44 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= +github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -8,6 +10,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= @@ -30,6 +34,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/urfave/cli/v2 v2.25.7 h1:VAzn5oq403l5pHjc4OhD54+XGO9cdKVL/7lDjF+iKUs= github.com/urfave/cli/v2 v2.25.7/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -79,6 +84,7 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internals/config/parser.go b/internals/config/parser.go index 53b30bd..bdc1de1 100644 --- a/internals/config/parser.go +++ b/internals/config/parser.go @@ -3,10 +3,10 @@ package config import ( _ "embed" "fmt" + "github.com/caarlos0/env/v9" + "github.com/joho/godotenv" "github.com/valyala/fasttemplate" - "gopkg.in/yaml.v3" "os" - "os/exec" "path/filepath" "runtime" ) @@ -17,52 +17,46 @@ var ( ) type Config struct { - DocumentRoot string `yaml:"document_root"` - DefaultScript string `yaml:"default_script"` - GZIPLevel int `yaml:"gzip_level"` - HTTPListenAddr string `yaml:"http_listen_addr"` - EnableAccessLogs bool `yaml:"enable_access_logs"` - DataDir string `yaml:"data_dir"` - - Env map[string]string `yaml:"env"` - - INI map[string]string `yaml:"ini"` - - FPM struct { - Bin string `yaml:"bin"` - WorkerCount int `yaml:"worker_count"` - WorkerMaxRequests int `yaml:"worker_max_requests"` - TerminationTimeout int `yaml:"termination_timeout"` - ConfigContent string `yaml:"-"` - ConfigFilename string `yaml:"-"` - PIDFilename string `yaml:"-"` - SocketFilename string `yaml:"-"` - Command *exec.Cmd `yaml:"-"` - } `yaml:"fpm"` + PrometheusMetricsEnabled bool `env:"PROMETHEUS_METRICS_ENABLED"` + PrometheusMetricsPath string `env:"PROMETHEUS_METRICS_PATH"` + DocumentRoot string `env:"DOCUMENT_ROOT"` + DefaultScript string `env:"DEFAULT_SCRIPT"` + GZIPEnabled bool `env:"GZIP_ENABLED"` + GZIPLevel int `env:"GZIP_LEVEL"` + HTTPListenAddr string `env:"HTTP_LISTEN_ADDR"` + EnableAccessLogs bool `env:"ENABLE_ACCESS_LOGS"` + DataDir string `env:"DATA_DIR"` + INI map[string]string `env:"PHP_INI" envSeparator:";"` + FPMBinFilename string `env:"FPM_BIN_PATH"` + WorkerCount int `env:"WORKER_COUNT"` + WorkerMaxRequests int `env:"WORKER_MAX_REQUEST_COUNT"` + WorkerTerminationTimeout int `env:"WORKER_MAX_REQUEST_TIMEOUT"` + + fpmConfigContent string + fpmConfigFilename string + fpmPIDFilename string + fpmSocketFilename string } func LoadFile(filename string) (*Config, error) { - content, err := os.ReadFile(filename) - if err != nil { + if err := godotenv.Overload(filename); err != nil { return nil, err } - content = []byte(os.ExpandEnv(string(content))) - var c Config - if err := yaml.Unmarshal(content, &c); err != nil { + if err := env.Parse(&c); err != nil { return nil, err } - if err := c.verify(); err != nil { + if err := c.ensure(); err != nil { return nil, err } return &c, nil } -func (c *Config) verify() error { +func (c *Config) ensure() error { if _, err := os.Stat(c.DefaultScript); err != nil { return err } @@ -75,6 +69,10 @@ func (c *Config) verify() error { } } + if c.WorkerCount < 1 { + c.WorkerCount = runtime.NumCPU() + } + _ = os.RemoveAll(c.DataDir) fpmDir := filepath.Join(c.DataDir, "fpm") @@ -85,23 +83,19 @@ func (c *Config) verify() error { } } - if c.FPM.WorkerCount < 1 { - c.FPM.WorkerCount = runtime.NumCPU() - } - - c.FPM.ConfigFilename = filepath.Join(fpmDir, "fpm.ini") - c.FPM.PIDFilename = filepath.Join(fpmDir, "fpm.pid") - c.FPM.SocketFilename = filepath.Join(fpmDir, "fpm.sock") + c.fpmConfigFilename = filepath.Join(fpmDir, "fpm.ini") + c.fpmSocketFilename = filepath.Join(fpmDir, "fpm.sock") + c.fpmPIDFilename = filepath.Join(fpmDir, "fpm.pid") - fpmConfContent = fasttemplate.ExecuteString(fpmConfContent, "{{", "}}", map[string]any{ - "files.pid": c.FPM.PIDFilename, - "files.socket": c.FPM.SocketFilename, - "worker.count": fmt.Sprintf("%v", c.FPM.WorkerCount), - "worker.max_requests": fmt.Sprintf("%v", c.FPM.WorkerMaxRequests), - "termination_timeout": fmt.Sprintf("%v", c.FPM.TerminationTimeout), + fpmConfigFileContents := fasttemplate.ExecuteString(fpmConfContent, "{{", "}}", map[string]any{ + "files.pid": c.fpmPIDFilename, + "files.socket": c.fpmSocketFilename, + "worker.count": fmt.Sprintf("%v", c.WorkerCount), + "worker.max_requests": fmt.Sprintf("%v", c.WorkerMaxRequests), + "worker.request_timeout": fmt.Sprintf("%v", c.WorkerTerminationTimeout), }) - if err := os.WriteFile(c.FPM.ConfigFilename, []byte(fpmConfContent), 0755); err != nil { + if err := os.WriteFile(fpmConfigFileContents, []byte(fpmConfigFileContents), 0755); err != nil { return err } diff --git a/internals/config/php-fpm.conf b/internals/config/php-fpm.conf index 2f479db..9e23cf0 100644 --- a/internals/config/php-fpm.conf +++ b/internals/config/php-fpm.conf @@ -10,5 +10,5 @@ listen = "{{files.socket}}" pm = static pm.max_children = {{worker.count}} pm.max_requests = {{worker.max_requests}} -request_terminate_timeout = {{termination_timeout}} +request_terminate_timeout = {{worker.request_timeout}} clear_env = no From 48615f73f2054c66db4eaa8d96284d5f5f256f9f Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 02:13:52 +0300 Subject: [PATCH 06/14] simi stable state --- cmd/etc.go | 3 - cmd/main.go | 33 ++------ cmd/serve/flags.go | 96 +++++++++++++++++++++++ cmd/{server => serve}/middlewares.go | 2 +- cmd/serve/serve.go | 90 +++++++++++++++++++++ cmd/server/flags.go | 55 ------------- cmd/server/server.go | 79 ------------------- internals/config/parser.go | 103 ------------------------- internals/fpm/fpm.go | 95 +++++++++++++++++++++++ internals/{config => fpm}/php-fpm.conf | 4 +- 10 files changed, 289 insertions(+), 271 deletions(-) delete mode 100644 cmd/etc.go create mode 100644 cmd/serve/flags.go rename cmd/{server => serve}/middlewares.go (98%) create mode 100644 cmd/serve/serve.go delete mode 100644 cmd/server/flags.go delete mode 100644 cmd/server/server.go delete mode 100644 internals/config/parser.go create mode 100644 internals/fpm/fpm.go rename internals/{config => fpm}/php-fpm.conf (67%) diff --git a/cmd/etc.go b/cmd/etc.go deleted file mode 100644 index 15c97c2..0000000 --- a/cmd/etc.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -func defaultServeFlags diff --git a/cmd/main.go b/cmd/main.go index 4885f07..41be213 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,45 +1,22 @@ package main import ( - "github.com/alash3al/phoo/cmd/server" - "github.com/alash3al/phoo/internals/config" + "github.com/alash3al/phoo/cmd/serve" "github.com/urfave/cli/v2" "log" "os" ) -var ( - globalConfig config.Config -) - func main() { app := &cli.App{ Name: "phoo", - Description: "php modern applications server that utilizes the bullet-proof php-fpm under-the-hood", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "config", - Aliases: []string{"c"}, - EnvVars: []string{"PHOO_CONFIG"}, - Value: "phoo.yaml", - }, - }, - Before: func(ctx *cli.Context) error { - c, err := config.LoadFile(ctx.String("config")) - if err != nil { - return err - } - - globalConfig = *c - - return nil - }, + Description: "php modern applications serve that utilizes the bullet-proof php-fpm under-the-hood", } app.Commands = append(app.Commands, &cli.Command{ - Name: "serve", - Aliases: []string{"s"}, - Action: server.Serve(&globalConfig), + Name: "serve", + Flags: serve.DefaultFlags("PHOO"), + Action: serve.Action(), }) if err := app.Run(os.Args); err != nil { diff --git a/cmd/serve/flags.go b/cmd/serve/flags.go new file mode 100644 index 0000000..780c1ee --- /dev/null +++ b/cmd/serve/flags.go @@ -0,0 +1,96 @@ +package serve + +import ( + "fmt" + "github.com/urfave/cli/v2" + "runtime" +) + +func DefaultFlags(envPrefix string) []cli.Flag { + prefixWrapper := func(k string) string { + return fmt.Sprintf("%s_%s", envPrefix, k) + } + + return []cli.Flag{ + &cli.StringFlag{ + Name: "root", + Usage: "the document root full path", + EnvVars: []string{prefixWrapper("DOCUMENT_ROOT")}, + Required: true, + }, + + &cli.StringFlag{ + Name: "entrypoint", + Usage: "the default php entrypoint script", + EnvVars: []string{"ENTRYPOINT"}, + }, + + &cli.StringFlag{ + Name: "http", + Usage: "the http listen address in the form of [address]:port", + EnvVars: []string{prefixWrapper("HTTP_LISTEN_ADDR")}, + Value: ":8000", + }, + + &cli.BoolFlag{ + Name: "logs", + Usage: "whether to enable access logs or not", + EnvVars: []string{prefixWrapper("ENABLE_ACCESS_LOGS")}, + Value: false, + }, + + &cli.StringFlag{ + Name: "fpm", + Usage: "the php-fpm binary filename", + EnvVars: []string{prefixWrapper("PHP_FPM")}, + Value: "php-fpm", + }, + + &cli.StringFlag{ + Name: "data", + Usage: "the directory to store phoo related files in", + EnvVars: []string{prefixWrapper("DATA_DIR")}, + Value: "./.phoo", + }, + + &cli.StringSliceFlag{ + Name: "ini", + Usage: "php ini settings in the form of key=value, this flag could be repeated for multiple ini settings", + EnvVars: []string{prefixWrapper("PHP_INI")}, + }, + + &cli.IntFlag{ + Name: "workers", + Usage: "php fpm workers, this is the maximum requests to be served at the same time", + EnvVars: []string{prefixWrapper("WORKER_COUNT")}, + Value: runtime.NumCPU(), + }, + + &cli.IntFlag{ + Name: "requests", + Usage: "php fpm max requests per worker, if a worker reached this number, it would be recycled", + EnvVars: []string{prefixWrapper("WORKER_MAX_REQUEST_COUNT")}, + Value: runtime.NumCPU() * 100, + }, + + &cli.IntFlag{ + Name: "timeout", + Usage: "php fpm max request time in seconds per worker, if a worker reached this number, it would be terminated, 0 means 'Disabled'", + EnvVars: []string{prefixWrapper("WORKER_MAX_REQUEST_TIME")}, + Value: 300, + }, + + &cli.StringFlag{ + Name: "metrics", + Usage: "the prometheus metrics endpoint, empty means disabled", + EnvVars: []string{prefixWrapper("METRICS_PATH")}, + }, + + &cli.IntFlag{ + Name: "gzip", + Usage: "gzip level, 0 means 'Disabled", + EnvVars: []string{prefixWrapper("GZIP_LEVEL")}, + Value: 5, + }, + } +} diff --git a/cmd/server/middlewares.go b/cmd/serve/middlewares.go similarity index 98% rename from cmd/server/middlewares.go rename to cmd/serve/middlewares.go index 09dc3f2..076590d 100644 --- a/cmd/server/middlewares.go +++ b/cmd/serve/middlewares.go @@ -1,4 +1,4 @@ -package server +package serve import ( "github.com/labstack/echo/v4" diff --git a/cmd/serve/serve.go b/cmd/serve/serve.go new file mode 100644 index 0000000..7b7976e --- /dev/null +++ b/cmd/serve/serve.go @@ -0,0 +1,90 @@ +package serve + +import ( + "errors" + "github.com/alash3al/phoo/internals/fpm" + "github.com/labstack/echo/v4" + "github.com/labstack/echo/v4/middleware" + "github.com/urfave/cli/v2" + "os" + "path/filepath" +) + +func Action() cli.ActionFunc { + return func(ctx *cli.Context) error { + if err := os.RemoveAll(ctx.String("data")); err != nil { + return err + } + + if err := os.MkdirAll(ctx.String("data"), 0755); err != nil { + return err + } + + if ctx.String("entrypoint") == "" { + entrypoints := []string{ + filepath.Join(ctx.String("root"), "index.php"), + filepath.Join(ctx.String("root"), "app.php"), + filepath.Join(ctx.String("root"), "server.php"), + } + + detectedEntrypoint := "" + + for _, entrypoint := range entrypoints { + stat, err := os.Stat(entrypoint) + if err != nil { + continue + } + + if stat.IsDir() { + continue + } + + detectedEntrypoint = entrypoint + } + + if detectedEntrypoint == "" { + return errors.New("unable to auto-detect the entrypoint script, try to put it yourself") + } + + if err := ctx.Set("entrypoint", detectedEntrypoint); err != nil { + return err + } + } + + fpmProcess := &fpm.Process{ + BinFilename: ctx.String("fpm"), + PIDFilename: filepath.Join(ctx.String("data"), "fpm.pid"), + ConfigFilename: filepath.Join(ctx.String("data"), "fpm.ini"), + SocketFilename: filepath.Join(ctx.String("data"), "fpm.sock"), + INI: ctx.StringSlice("ini"), + WorkerCount: ctx.Int("workers"), + WorkerMaxRequestCount: ctx.Int("requests"), + WorkerMaxRequestTime: ctx.Int("timeout"), + } + + if err := fpmProcess.Start(); err != nil { + return err + } + + e := echo.New() + e.HideBanner = true + + if ctx.Bool("logs") { + e.Use(middleware.Logger()) + } + + e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ + Level: ctx.Int("gzip"), + })) + + e.Use(middleware.Recover()) + e.Use(serveStaticFilesOnlyMiddleware(ctx.String("root"))) + e.Use(serveFastCGIMiddleware( + ctx.String("entrypoint"), + "unix", + fpmProcess.SocketFilename, + )) + + return e.Start(ctx.String("http")) + } +} diff --git a/cmd/server/flags.go b/cmd/server/flags.go deleted file mode 100644 index 7772c36..0000000 --- a/cmd/server/flags.go +++ /dev/null @@ -1,55 +0,0 @@ -package server - -import ( - "fmt" - "github.com/urfave/cli/v2" -) - -func DefaultFlags(envPrefix string, append ...[]cli.Flag) []cli.Flag { - prefixWrapper := func(k string) string { - return fmt.Sprintf("%s_%s", envPrefix, k) - } - - return []cli.Flag{ - &cli.StringFlag{ - Name: "metrics", - Usage: "the prometheus metrics endpoint, empty means disabled", - EnvVars: []string{prefixWrapper("METRICS_PATH")}, - }, - - &cli.StringFlag{ - Name: "root", - Usage: "the document root full path", - EnvVars: []string{prefixWrapper("DOCUMENT_ROOT")}, - Required: true, - }, - - &cli.StringFlag{ - Name: "entrypoint", - Usage: "the default php entrypoint script", - EnvVars: []string{"ENTRYPOINT"}, - Required: true, - }, - - &cli.StringFlag{ - Name: "http", - Usage: "the http listen address in the form of [address]:port", - EnvVars: []string{prefixWrapper("HTTP_LISTEN_ADDR")}, - Value: ":8000", - }, - - &cli.BoolFlag{ - Name: "logs", - Usage: "whether to enable access logs or not", - EnvVars: []string{prefixWrapper("ENABLE_ACCESS_LOGS")}, - Value: false, - }, - - &cli.StringFlag{ - Name: "fpm", - Usage: "the php-fpm binary filename", - EnvVars: []string{"PHP_FPM"}, - Value: "php-fpm", - }, - } -} diff --git a/cmd/server/server.go b/cmd/server/server.go deleted file mode 100644 index 3e3e929..0000000 --- a/cmd/server/server.go +++ /dev/null @@ -1,79 +0,0 @@ -package server - -import ( - "fmt" - "github.com/alash3al/phoo/internals/config" - "github.com/labstack/echo/v4" - "github.com/labstack/echo/v4/middleware" - "github.com/urfave/cli/v2" - "log" - "os" - "os/exec" - "time" -) - -func Serve(conf *config.Config) cli.ActionFunc { - return func(ctx *cli.Context) error { - e := echo.New() - e.HideBanner = true - - if conf.EnableAccessLogs { - e.Use(middleware.Logger()) - } - - e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ - Level: conf.GZIPLevel, - })) - - e.Use(middleware.Recover()) - e.Use(serveStaticFilesOnlyMiddleware(conf.DocumentRoot)) - e.Use(serveFastCGIMiddleware( - conf.DefaultScript, - "unix", - conf.FPM.SocketFilename, - )) - - if err := startPHPFPM(conf); err != nil { - e.Logger.Fatal(err.Error()) - } - - return e.Start(conf.HTTPListenAddr) - } -} - -func startPHPFPM(conf *config.Config) error { - cmd := exec.Command(conf.FPM.Bin, "-F", "-O", "-y", conf.FPM.ConfigFilename) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - for k, v := range conf.Env { - cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, v)) - } - - cmd.Env = append(cmd.Env, os.Environ()...) - - for k, v := range conf.INI { - cmd.Args = append(cmd.Args, "-d", fmt.Sprintf("%s=%s", k, v)) - } - - if err := cmd.Start(); err != nil { - return err - } - - for { - if _, err := os.Stat(conf.FPM.SocketFilename); err != nil { - time.Sleep(1 * time.Second) - continue - } - - break - } - - go (func() { - if err := cmd.Wait(); err != nil { - log.Fatal(err.Error()) - } - })() - - return nil -} diff --git a/internals/config/parser.go b/internals/config/parser.go deleted file mode 100644 index bdc1de1..0000000 --- a/internals/config/parser.go +++ /dev/null @@ -1,103 +0,0 @@ -package config - -import ( - _ "embed" - "fmt" - "github.com/caarlos0/env/v9" - "github.com/joho/godotenv" - "github.com/valyala/fasttemplate" - "os" - "path/filepath" - "runtime" -) - -var ( - //go:embed php-fpm.conf - fpmConfContent string -) - -type Config struct { - PrometheusMetricsEnabled bool `env:"PROMETHEUS_METRICS_ENABLED"` - PrometheusMetricsPath string `env:"PROMETHEUS_METRICS_PATH"` - DocumentRoot string `env:"DOCUMENT_ROOT"` - DefaultScript string `env:"DEFAULT_SCRIPT"` - GZIPEnabled bool `env:"GZIP_ENABLED"` - GZIPLevel int `env:"GZIP_LEVEL"` - HTTPListenAddr string `env:"HTTP_LISTEN_ADDR"` - EnableAccessLogs bool `env:"ENABLE_ACCESS_LOGS"` - DataDir string `env:"DATA_DIR"` - INI map[string]string `env:"PHP_INI" envSeparator:";"` - FPMBinFilename string `env:"FPM_BIN_PATH"` - WorkerCount int `env:"WORKER_COUNT"` - WorkerMaxRequests int `env:"WORKER_MAX_REQUEST_COUNT"` - WorkerTerminationTimeout int `env:"WORKER_MAX_REQUEST_TIMEOUT"` - - fpmConfigContent string - fpmConfigFilename string - fpmPIDFilename string - fpmSocketFilename string -} - -func LoadFile(filename string) (*Config, error) { - if err := godotenv.Overload(filename); err != nil { - return nil, err - } - - var c Config - - if err := env.Parse(&c); err != nil { - return nil, err - } - - if err := c.ensure(); err != nil { - return nil, err - } - - return &c, nil -} - -func (c *Config) ensure() error { - if _, err := os.Stat(c.DefaultScript); err != nil { - return err - } - - for _, p := range []*string{&(c.DefaultScript), &(c.DataDir)} { - if abs, err := filepath.Abs(*p); err != nil { - return err - } else { - *p = abs - } - } - - if c.WorkerCount < 1 { - c.WorkerCount = runtime.NumCPU() - } - - _ = os.RemoveAll(c.DataDir) - - fpmDir := filepath.Join(c.DataDir, "fpm") - - for _, p := range []string{c.DataDir, fpmDir} { - if err := os.MkdirAll(p, 0755); err != nil { - return err - } - } - - c.fpmConfigFilename = filepath.Join(fpmDir, "fpm.ini") - c.fpmSocketFilename = filepath.Join(fpmDir, "fpm.sock") - c.fpmPIDFilename = filepath.Join(fpmDir, "fpm.pid") - - fpmConfigFileContents := fasttemplate.ExecuteString(fpmConfContent, "{{", "}}", map[string]any{ - "files.pid": c.fpmPIDFilename, - "files.socket": c.fpmSocketFilename, - "worker.count": fmt.Sprintf("%v", c.WorkerCount), - "worker.max_requests": fmt.Sprintf("%v", c.WorkerMaxRequests), - "worker.request_timeout": fmt.Sprintf("%v", c.WorkerTerminationTimeout), - }) - - if err := os.WriteFile(fpmConfigFileContents, []byte(fpmConfigFileContents), 0755); err != nil { - return err - } - - return nil -} diff --git a/internals/fpm/fpm.go b/internals/fpm/fpm.go new file mode 100644 index 0000000..dff9700 --- /dev/null +++ b/internals/fpm/fpm.go @@ -0,0 +1,95 @@ +package fpm + +import ( + _ "embed" + "fmt" + "github.com/valyala/fasttemplate" + "os" + "os/exec" + "os/signal" + "path/filepath" + "syscall" + "time" +) + +//go:embed php-fpm.conf +var configTemplate string + +type Process struct { + BinFilename string + PIDFilename string + ConfigFilename string + SocketFilename string + INI []string + + WorkerCount int + WorkerMaxRequestCount int + WorkerMaxRequestTime int +} + +func (p *Process) Start() error { + paths := []*string{ + &p.ConfigFilename, + &p.SocketFilename, + &p.PIDFilename, + } + + for _, path := range paths { + abs, err := filepath.Abs(*path) + if err != nil { + return err + } + + *path = abs + } + + fpmConfigFileContents := fasttemplate.ExecuteString(configTemplate, "{{", "}}", map[string]any{ + "files.pid": p.PIDFilename, + "files.socket": p.SocketFilename, + "worker.count": fmt.Sprintf("%v", p.WorkerCount), + "worker.request.max_count": fmt.Sprintf("%v", p.WorkerMaxRequestCount), + "worker.request.max_time": fmt.Sprintf("%v", p.WorkerMaxRequestTime), + }) + + if err := os.WriteFile(p.ConfigFilename, []byte(fpmConfigFileContents), 0755); err != nil { + return err + } + + return p.execAndWait() +} + +func (p *Process) execAndWait() error { + cmd := exec.Command(p.BinFilename, "-F", "-O", "-y", p.ConfigFilename) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + for _, v := range p.INI { + cmd.Args = append(cmd.Args, "-d", v) + } + + if err := cmd.Start(); err != nil { + return err + } + + for { + if _, err := os.Stat(p.SocketFilename); err != nil { + time.Sleep(1 * time.Second) + continue + } + + break + } + + sig := make(chan os.Signal) + + signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) + + go func() { + for s := range sig { + _ = cmd.Process.Signal(s) + os.Exit(0) + } + }() + + return nil +} diff --git a/internals/config/php-fpm.conf b/internals/fpm/php-fpm.conf similarity index 67% rename from internals/config/php-fpm.conf rename to internals/fpm/php-fpm.conf index 9e23cf0..19751fc 100644 --- a/internals/config/php-fpm.conf +++ b/internals/fpm/php-fpm.conf @@ -9,6 +9,6 @@ process_control_timeout = 5s listen = "{{files.socket}}" pm = static pm.max_children = {{worker.count}} -pm.max_requests = {{worker.max_requests}} -request_terminate_timeout = {{worker.request_timeout}} +pm.max_requests = {{worker.request.max_count}} +request_terminate_timeout = {{worker.request.max_time}} clear_env = no From 26a38befb55f245d7cf0b586f4b7f4f4eaef57bd Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:07:05 +0300 Subject: [PATCH 07/14] finalized the core and added README file --- README.md | 55 ++++++++++++++++++++++++++++++++++++++++ cmd/main.go | 9 +++++-- cmd/serve/flags.go | 52 ++++++++++++++++++++++++++++++++++--- cmd/serve/middlewares.go | 20 +++++++++++++++ cmd/serve/serve.go | 33 +++++++++++++++++++----- go.mod | 13 ++++++++++ go.sum | 37 +++++++++++++++++++++++++++ 7 files changed, 206 insertions(+), 13 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..6a0b478 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +PHOO +==== +> modern php application server, it depends on the bullet-proof `php-fpm` but it controls how it is being run. + +Examples +======== +> Imagine you have a php application uses modern framework like laravel, symfony ... etc +> that app contains a public directory, and that public directory contains the main bootstrap file that +> serves the incoming requests named as `index.php`. +```shell +# this all what you need to serve a laravel application! +$ phoo serve -r ./public +⇨ http server started on [::]:8000 +``` + +#### But how about changing the address it is listening on to 0.0.0.0:80? +```shell +# no problem +$ phoo serve -r ./public --http 0.0.0.0:80 +⇨ http server started on [::]:80 +``` + +#### Sometimes I want to add custom `pnp.ini` settings, is it easy? +```shell +# is this ok for you? ;) +$ phoo serve -r ./public -i display_errors=Off -i another_key=another_value +⇨ http server started on [::]:8000 +``` +#### I have a high traffic web-app and I want to increase the php workers +```shell +# just increase the workers count +$ phoo serve -r ./public --workers=20 +⇨ http server started on [::]:8000 +``` + +#### Hmmmm, but I want to monitor my app via prometheus metrics, I don't want to do it manually +```shell +# no need to do it yourself, this will enable prometheus metrics at the specified `/metrics` path +$ phoo serve -r ./public --metrics "/metrics" +⇨ http server started on [::]:8000 +``` + +#### Wow!, seems `phoo` has a lot of simple flags/configs, is it documented anywhere? +> just run `phoo serve --help` and enjoy it :), you will find that you can also pass flags via `ENV` vars. + +Requirements +============ +- `php-fpm` +- a shell access to run `phoo` :D + +Installation +============ +- Binary installations could be done via the [releases](https://github.com/alash3al/phoo/releases). +- Docker image is available at [`ghcr.io/alash3al/phoo`](https://github.com/alash3al/phoo/pkgs/container/phoo) + - you can easily `COPY --from=ghcr.io/alash3al/phoo:2.1.8 /usr/bin/phoo /usr/bin/phoo` to run it into your own custom image! \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index 41be213..20beb7a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -9,13 +9,18 @@ import ( func main() { app := &cli.App{ - Name: "phoo", - Description: "php modern applications serve that utilizes the bullet-proof php-fpm under-the-hood", + Name: "phoo", + Description: "php modern applications serve that utilizes the bullet-proof php-fpm under-the-hood", + Suggest: true, + Version: "v3.x", + EnableBashCompletion: true, + SliceFlagSeparator: ";", } app.Commands = append(app.Commands, &cli.Command{ Name: "serve", Flags: serve.DefaultFlags("PHOO"), + Before: serve.Before(), Action: serve.Action(), }) diff --git a/cmd/serve/flags.go b/cmd/serve/flags.go index 780c1ee..2c2f0f8 100644 --- a/cmd/serve/flags.go +++ b/cmd/serve/flags.go @@ -2,6 +2,7 @@ package serve import ( "fmt" + "github.com/labstack/echo/v4/middleware" "github.com/urfave/cli/v2" "runtime" ) @@ -15,6 +16,7 @@ func DefaultFlags(envPrefix string) []cli.Flag { &cli.StringFlag{ Name: "root", Usage: "the document root full path", + Aliases: []string{"r"}, EnvVars: []string{prefixWrapper("DOCUMENT_ROOT")}, Required: true, }, @@ -22,6 +24,7 @@ func DefaultFlags(envPrefix string) []cli.Flag { &cli.StringFlag{ Name: "entrypoint", Usage: "the default php entrypoint script", + Aliases: []string{"e"}, EnvVars: []string{"ENTRYPOINT"}, }, @@ -56,6 +59,7 @@ func DefaultFlags(envPrefix string) []cli.Flag { &cli.StringSliceFlag{ Name: "ini", Usage: "php ini settings in the form of key=value, this flag could be repeated for multiple ini settings", + Aliases: []string{"i"}, EnvVars: []string{prefixWrapper("PHP_INI")}, }, @@ -86,11 +90,51 @@ func DefaultFlags(envPrefix string) []cli.Flag { EnvVars: []string{prefixWrapper("METRICS_PATH")}, }, + &cli.BoolFlag{ + Name: "cors", + Usage: "whether to enable/disable the cors-* features/flags", + EnvVars: []string{prefixWrapper("CORS_ENABLED")}, + Value: false, + }, + + &cli.StringSliceFlag{ + Name: "cors-origin", + Usage: "this flag adds the specified origin to the list of allowed cors origins, you can call it multiple times to add multiple origins", + EnvVars: []string{prefixWrapper("CORS_ORIGINS")}, + Value: cli.NewStringSlice("*"), + }, + + &cli.StringSliceFlag{ + Name: "cors-methods", + Usage: "this flag adds the specified methods to the list of allowed cors methods, you can call it multiple times to add multiple methods", + EnvVars: []string{prefixWrapper("CORS_METHODS")}, + Value: cli.NewStringSlice(middleware.DefaultCORSConfig.AllowMethods...), + }, + + &cli.StringSliceFlag{ + Name: "cors-headers", + Usage: "this flag adds the specified headers to the list of allowed cors headers the client can send, you can call it multiple times to add multiple headers", + EnvVars: []string{prefixWrapper("CORS_HEADERS")}, + }, + + &cli.StringSliceFlag{ + Name: "cors-expose", + Usage: "this flag adds the specified headers to the list of allowed headers the client can access, you can call it multiple times to add multiple headers", + EnvVars: []string{prefixWrapper("CORS_EXPOSE")}, + }, + + &cli.BoolFlag{ + Name: "cors-credentials", + Usage: "this flag indicates whether or not the actual request can be made using credentials", + EnvVars: []string{prefixWrapper("CORS_CREDENTIALS")}, + Value: false, + }, + &cli.IntFlag{ - Name: "gzip", - Usage: "gzip level, 0 means 'Disabled", - EnvVars: []string{prefixWrapper("GZIP_LEVEL")}, - Value: 5, + Name: "cors-age", + Usage: "the cors max_age in seconds", + EnvVars: []string{prefixWrapper("CORS_AGE")}, + Value: 0, }, } } diff --git a/cmd/serve/middlewares.go b/cmd/serve/middlewares.go index 076590d..9d99121 100644 --- a/cmd/serve/middlewares.go +++ b/cmd/serve/middlewares.go @@ -1,6 +1,7 @@ package serve import ( + "github.com/labstack/echo-contrib/echoprometheus" "github.com/labstack/echo/v4" "github.com/yookoala/gofast" "os" @@ -8,6 +9,25 @@ import ( "strings" ) +func servePrometheusMetricsMiddleware(metricsPath string) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + currentPath := strings.Trim(c.Request().URL.Path, "/") + metricsPath = strings.Trim(metricsPath, "/") + + if metricsPath == "" { + return next(c) + } + + if strings.EqualFold(currentPath, metricsPath) { + return echoprometheus.NewHandler()(c) + } + + return next(c) + } + } +} + func serveStaticFilesOnlyMiddleware(documentRoot string) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { diff --git a/cmd/serve/serve.go b/cmd/serve/serve.go index 7b7976e..ff822a1 100644 --- a/cmd/serve/serve.go +++ b/cmd/serve/serve.go @@ -3,14 +3,18 @@ package serve import ( "errors" "github.com/alash3al/phoo/internals/fpm" + "github.com/labstack/echo-contrib/echoprometheus" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/urfave/cli/v2" "os" "path/filepath" + "time" ) -func Action() cli.ActionFunc { +var fpmProcess *fpm.Process + +func Before() cli.BeforeFunc { return func(ctx *cli.Context) error { if err := os.RemoveAll(ctx.String("data")); err != nil { return err @@ -51,7 +55,7 @@ func Action() cli.ActionFunc { } } - fpmProcess := &fpm.Process{ + fpmProcess = &fpm.Process{ BinFilename: ctx.String("fpm"), PIDFilename: filepath.Join(ctx.String("data"), "fpm.pid"), ConfigFilename: filepath.Join(ctx.String("data"), "fpm.ini"), @@ -62,10 +66,12 @@ func Action() cli.ActionFunc { WorkerMaxRequestTime: ctx.Int("timeout"), } - if err := fpmProcess.Start(); err != nil { - return err - } + return fpmProcess.Start() + } +} +func Action() cli.ActionFunc { + return func(ctx *cli.Context) error { e := echo.New() e.HideBanner = true @@ -73,11 +79,24 @@ func Action() cli.ActionFunc { e.Use(middleware.Logger()) } - e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ - Level: ctx.Int("gzip"), + if ctx.Bool("cors") { + e.Use(middleware.CORSWithConfig(middleware.CORSConfig{ + AllowOrigins: ctx.StringSlice("cors-origins"), + AllowMethods: ctx.StringSlice("cors-methods"), + AllowHeaders: ctx.StringSlice("cors-headers"), + AllowCredentials: ctx.Bool("cors-credentials"), + ExposeHeaders: ctx.StringSlice("cors-expose"), + MaxAge: ctx.Int("cors-age"), + })) + } + + e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{ + Timeout: time.Duration(ctx.Int("timeout")) * time.Second, })) e.Use(middleware.Recover()) + e.Use(echoprometheus.NewMiddleware("PHOO")) + e.Use(servePrometheusMetricsMiddleware(ctx.String("metrics"))) e.Use(serveStaticFilesOnlyMiddleware(ctx.String("root"))) e.Use(serveFastCGIMiddleware( ctx.String("entrypoint"), diff --git a/go.mod b/go.mod index fc3f846..5708fdd 100644 --- a/go.mod +++ b/go.mod @@ -11,13 +11,25 @@ require ( ) require ( + github.com/beorn7/perks v1.0.1 // indirect github.com/caarlos0/env/v9 v9.0.0 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/joho/godotenv v1.5.1 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/labstack/echo-contrib v0.15.0 // indirect github.com/labstack/gommon v0.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.19 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/prometheus/client_golang v1.14.0 // indirect + github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/common v0.40.0 // indirect + github.com/prometheus/procfs v0.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect @@ -27,4 +39,5 @@ require ( golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect ) diff --git a/go.sum b/go.sum index 09c2a44..f4eea9a 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ +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/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc= github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -8,11 +12,22 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/go-restit/lzjson v0.0.0-20161206095556-efe3c53acc68/go.mod h1:7vXSKQt83WmbPeyVjCfNT9YDJ5BUFmcwFsEjI9SCvYM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/labstack/echo-contrib v0.15.0 h1:9K+oRU265y4Mu9zpRDv3X+DGTqUALY6oRHCSZZKCRVU= +github.com/labstack/echo-contrib v0.15.0/go.mod h1:lei+qt5CLB4oa7VHTE0yEfQSEB9XTJI1LUqko9UWvo4= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= @@ -24,14 +39,30 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 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.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw= +github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.40.0 h1:Afz7EVRqGg2Mqqf4JuF9vdvp1pi220m55Pi9T2JnO4Q= +github.com/prometheus/common v0.40.0/go.mod h1:L65ZJPSmfn/UBWLQIHV7dBrKFidB/wPlF1y5TlSt9OE= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= 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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= @@ -59,6 +90,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -83,7 +115,12 @@ golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= From fb2679d2ddd618f1542799995837f7b21b871f01 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:16:03 +0300 Subject: [PATCH 08/14] updated readme --- README.md | 2 +- cmd/main.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6a0b478..91e906b 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ $ phoo serve -r ./public --metrics "/metrics" ``` #### Wow!, seems `phoo` has a lot of simple flags/configs, is it documented anywhere? -> just run `phoo serve --help` and enjoy it :), you will find that you can also pass flags via `ENV` vars. +> just run `phoo serve --help` and enjoy it :), you will find that you can also pass flags via `ENV` vars, and it will automatically read `.env` file in the current working directory. Requirements ============ diff --git a/cmd/main.go b/cmd/main.go index 20beb7a..539ae4f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -6,6 +6,7 @@ import ( "log" "os" ) +import _ "github.com/joho/godotenv/autoload" func main() { app := &cli.App{ From 86906cd7621eb1c7f0b1b623296fc6306fafff5a Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:32:26 +0300 Subject: [PATCH 09/14] added github actions workflow --- .github/workflows/releaser.yaml | 63 +++++++++++++++++++++++++++++++++ .gitignore | 2 +- .idea/.gitignore | 8 +++++ .idea/modules.xml | 8 +++++ .idea/phoo.iml | 9 +++++ .idea/vcs.xml | 6 ++++ 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/releaser.yaml create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/phoo.iml create mode 100644 .idea/vcs.xml diff --git a/.github/workflows/releaser.yaml b/.github/workflows/releaser.yaml new file mode 100644 index 0000000..57a8259 --- /dev/null +++ b/.github/workflows/releaser.yaml @@ -0,0 +1,63 @@ +env: + CGO_ENABLED: "0" + REGISTRY: ghcr.io + IMAGE_NAME: alash3al/phoo + +on: + release: + types: [created] + +jobs: + binary-releaser: + name: Release Go Binary + runs-on: ubuntu-latest + strategy: + matrix: + goos: [linux, darwin] + goarch: [amd64, arm64] + steps: + - uses: actions/checkout@v3 + - uses: wangyoucao577/go-release-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + goos: ${{ matrix.goos }} + goarch: ${{ matrix.goarch }} + goversion: "https://dl.google.com/go/go1.21.0.linux-amd64.tar.gz" + project_path: "./cmd" + binary_name: "phoo" + ldflags: "-s -w" + + docker-releaser: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Get Latest Tag + id: var_tag + run: echo "name=$(git describe --tags --abbrev=0)" >> $GITHUB_OUTPUT + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to Github Container registry + uses: docker/login-action@v2 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v3 + with: + file: Dockerfile + context: . + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.var_tag.outputs.name }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore index 892ea5e..710fb5b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -.* +.phoo !.env.example \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d7859e4 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/phoo.iml b/.idea/phoo.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/phoo.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file From e4a1072c6549bf68b1d37cef95ae1a99bc564811 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:33:07 +0300 Subject: [PATCH 10/14] remove .idea --- .idea/.gitignore | 8 -------- .idea/modules.xml | 8 -------- .idea/phoo.iml | 9 --------- .idea/vcs.xml | 6 ------ 4 files changed, 31 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/modules.xml delete mode 100644 .idea/phoo.iml delete mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index d7859e4..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/phoo.iml b/.idea/phoo.iml deleted file mode 100644 index 5e764c4..0000000 --- a/.idea/phoo.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From 54cba863cc51c1694b611b7fe070e114535a4ba5 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:33:44 +0300 Subject: [PATCH 11/14] updated .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 710fb5b..b657cc0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .phoo -!.env.example \ No newline at end of file +!.env.example +.idea \ No newline at end of file From fd452549a45cb7dc5c2285ff9d94155d3825bc16 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:35:33 +0300 Subject: [PATCH 12/14] updated README --- .env.example | 0 README.md | 7 ++++++- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index 91e906b..5ca29ba 100644 --- a/README.md +++ b/README.md @@ -52,4 +52,9 @@ Installation ============ - Binary installations could be done via the [releases](https://github.com/alash3al/phoo/releases). - Docker image is available at [`ghcr.io/alash3al/phoo`](https://github.com/alash3al/phoo/pkgs/container/phoo) - - you can easily `COPY --from=ghcr.io/alash3al/phoo:2.1.8 /usr/bin/phoo /usr/bin/phoo` to run it into your own custom image! \ No newline at end of file + - you can easily `COPY --from=ghcr.io/alash3al/phoo:2.1.8 /usr/bin/phoo /usr/bin/phoo` to run it into your own custom image! + +TODOs +===== +- [ ] Add `.env.example` with comments to describe each var +- \ No newline at end of file From d3f7df4dc1b6c9128952dc00c0f437591d1368e3 Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 14:38:32 +0300 Subject: [PATCH 13/14] updated README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ca29ba..cac7d74 100644 --- a/README.md +++ b/README.md @@ -56,5 +56,5 @@ Installation TODOs ===== -- [ ] Add `.env.example` with comments to describe each var -- \ No newline at end of file +- [ ] Add `.env.example` with comments to describe each var. +- [ ] Add future plans/thoughts. \ No newline at end of file From 4cd1e4a222c1c4fa2a391557269a725663e9447b Mon Sep 17 00:00:00 2001 From: Mohamed Al Ashaal Date: Fri, 11 Aug 2023 15:09:46 +0300 Subject: [PATCH 14/14] updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cac7d74..8027270 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ $ phoo serve -r ./public --http 0.0.0.0:80 ⇨ http server started on [::]:80 ``` -#### Sometimes I want to add custom `pnp.ini` settings, is it easy? +#### Sometimes I want to add custom `php.ini` settings, is it easy? ```shell # is this ok for you? ;) $ phoo serve -r ./public -i display_errors=Off -i another_key=another_value