diff --git a/caddyfile.go b/caddyfile.go deleted file mode 100644 index 54acea0..0000000 --- a/caddyfile.go +++ /dev/null @@ -1,246 +0,0 @@ -package pages - -import ( - "fmt" - "github.com/alecthomas/units" - "github.com/caddyserver/caddy/v2" - "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile" - "github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile" - "github.com/caddyserver/caddy/v2/modules/caddyhttp" - "github.com/d7z-project/caddy-gitea-pages/pages" - "github.com/pkg/errors" - "go.uber.org/zap" - "io" - "net/http" - "os" - "strconv" - "strings" - "time" -) - -func init() { - middle := &Middleware{ - Config: &pages.MiddlewareConfig{}, - } - caddy.RegisterModule(middle) - httpcaddyfile.RegisterHandlerDirective("gitea", parseCaddyfile(middle)) -} - -func (m *Middleware) UnmarshalCaddyfile(d *caddyfile.Dispenser) error { - for d.Next() { - for n := d.Nesting(); d.NextBlock(n); { - switch d.Val() { - case "server": - d.Args(&m.Config.Server) - case "token": - d.Args(&m.Config.Token) - case "cache": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) != 3 { - return d.Errf("expected 3 argument for 'cache'; got %v", remainingArgs) - } - var err error - m.Config.CacheTimeout, err = time.ParseDuration(remainingArgs[0]) - if err != nil { - return d.Errf("invalid duration: %v", err) - } - m.Config.CacheRefresh, err = time.ParseDuration(remainingArgs[1]) - if err != nil { - return d.Errf("invalid duration: %v", err) - } - size, err := units.ParseBase2Bytes(remainingArgs[2]) - if err != nil { - return d.Errf("invalid CacheSize: %v", err) - } - m.Config.CacheMaxSize = int(size) - case "domain": - d.Args(&m.Config.Domain) - case "alias": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) == 0 { - return d.Errf("expected 2 argument for 'alias'; got %v", remainingArgs) - } - if len(remainingArgs) == 1 { - m.Config.Alias = remainingArgs[0] - } - if len(remainingArgs) == 2 && remainingArgs[1] == "shared" { - m.Config.Alias = remainingArgs[0] - m.Config.SharedAlias = true - } - case "headers": - if d.NextArg() { - return d.ArgErr() - } - for nesting := d.Nesting(); d.NextBlock(nesting); { - args := []string{d.Val()} - args = append(args, d.RemainingArgs()...) - if len(args) != 2 { - return d.Errf("expected 2 arguments, got %d", len(args)) - } - if m.Config.CustomHeaders == nil { - m.Config.CustomHeaders = make(map[string]string) - } - m.Config.CustomHeaders[args[0]] = args[1] - } - case "errors": - if d.NextArg() { - return d.ArgErr() - } - for nesting := d.Nesting(); d.NextBlock(nesting); { - args := []string{d.Val()} - args = append(args, d.RemainingArgs()...) - if len(args) != 2 { - return d.Errf("expected 2 arguments, got %d", len(args)) - } - body, err := parseBody(args[1]) - if err != nil { - return d.Errf("failed to parse %s: %v", args[0], err) - } - if m.Config.ErrorPages == nil { - m.Config.ErrorPages = make(map[string]string) - } - m.Config.ErrorPages[strings.ToLower(args[0])] = body - } - case "redirect": - remainingArgs := d.RemainingArgs() - if len(remainingArgs) != 2 { - return d.Errf("expected 2 arguments, got %d", len(remainingArgs)) - } - code, err := strconv.Atoi(remainingArgs[1]) - if err != nil { - return d.WrapErr(err) - } - m.Config.AutoRedirect = &pages.AutoRedirect{ - Enabled: true, - Scheme: remainingArgs[0], - Code: code, - } - default: - return d.Errf("unrecognized subdirective '%s'", d.Val()) - } - } - } - return nil -} - -func parseBody(path string) (string, error) { - fileData, err := os.ReadFile(path) - if err == nil { - return string(fileData), nil - } else if strings.HasPrefix(path, "http://") || - strings.HasPrefix(path, "https://") { - resp, err := http.Get(path) - if err != nil { - return "", err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return "", errors.New(resp.Status) - } - all, err := io.ReadAll(resp.Body) - if err != nil { - return "", err - } - return string(all), nil - } - return "", err -} - -func parseCaddyfile(middleware *Middleware) func(httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { - return func(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) { - err := middleware.UnmarshalCaddyfile(h.Dispenser) - if err != nil { - return nil, err - } - if middleware.Config.ErrorPages == nil { - middleware.Config.ErrorPages = make(map[string]string) - } - if middleware.Config.CustomHeaders == nil { - middleware.Config.CustomHeaders = make(map[string]string) - } - if middleware.Config.AutoRedirect == nil { - middleware.Config.AutoRedirect = &pages.AutoRedirect{ - Enabled: false, - } - } - if middleware.Config.CacheRefresh <= 0 { - middleware.Config.CacheRefresh = 1 * time.Minute - } - if middleware.Config.CacheTimeout <= 0 { - middleware.Config.CacheTimeout = 3 * time.Minute - } - if middleware.Config.CacheMaxSize <= 0 { - middleware.Config.CacheMaxSize = 3 * 1024 * 1024 - } - return middleware, nil - } -} - -type Middleware struct { - Config *pages.MiddlewareConfig `json:"config"` - Logger *zap.Logger `json:"-"` - Client *pages.PageClient `json:"-"` -} - -func (m *Middleware) ServeHTTP( - writer http.ResponseWriter, - request *http.Request, - handler caddyhttp.Handler, -) error { - - type stackTracer interface { - StackTrace() errors.StackTrace - } - err := m.Client.Route(writer, request) - if errors.Is(err, pages.ErrorNotMatches) { - return handler.ServeHTTP(writer, request) - } else { - if err != nil { - if err, ok := err.(stackTracer); ok { - for _, f := range err.StackTrace() { - fmt.Printf("%+s:%d\n", f, f) - } - } - } - return err - } -} - -func (m *Middleware) CaddyModule() caddy.ModuleInfo { - return caddy.ModuleInfo{ - ID: "http.handlers.gitea", - New: func() caddy.Module { - return new(Middleware) - }, - } -} - -func (m *Middleware) Validate() error { - return m.Client.Validate() -} - -func (m *Middleware) Cleanup() error { - m.Logger.Info("cleaning up gitea middleware.") - return m.Client.Close() -} - -func (m *Middleware) Provision(ctx caddy.Context) error { - var err error - m.Logger = ctx.Logger() // g.Logger is a *zap.Logger - m.Client, err = pages.NewPageClient( - m.Config, - m.Logger, - ) - if err != nil { - return err - } - return nil -} - -var ( - _ caddy.Provisioner = (*Middleware)(nil) - _ caddy.CleanerUpper = (*Middleware)(nil) - _ caddy.Validator = (*Middleware)(nil) - _ caddyhttp.MiddlewareHandler = (*Middleware)(nil) - _ caddyfile.Unmarshaler = (*Middleware)(nil) -) diff --git a/main.go b/main.go new file mode 100644 index 0000000..85f0393 --- /dev/null +++ b/main.go @@ -0,0 +1 @@ +package main \ No newline at end of file diff --git a/pages/config.go b/pages/config.go new file mode 100644 index 0000000..9a1a0b1 --- /dev/null +++ b/pages/config.go @@ -0,0 +1,79 @@ +package pages + +import ( + "flag" + "fmt" + "os" + + "gopkg.in/yaml.v3" +) + +type Config struct { + GiteaServer string `yaml:"server" json:"server"` + GiteaToken string `yaml:"token" json:"token"` + GiteaBranch string `yaml:"branch" json:"branch"` + PageBaseDomain string `yaml:"domain" json:"domain"` + ConfigPath string `yaml:"config" json:"config"` +} + +var DefauleConfig = Config{ + GiteaServer: DefaultGiteaServer, + GiteaToken: DefaultGiteaToken, + GiteaBranch: DefaultGiteaBranch, + PageBaseDomain: DefaultPageBaseDomain, + ConfigPath: DefauleConfigPath, +} + +func ParseEnvs() *Config { + config := &Config{} + config.GiteaServer = GetEnvStr(ENV_PAGE_GiteaServer, DefaultGiteaServer) + config.GiteaToken = GetEnvStr(ENV_PAGE_GiteaToken, DefaultGiteaToken) + config.GiteaBranch = GetEnvStr(ENV_PAGE_GiteaBranch, DefaultGiteaBranch) + config.PageBaseDomain = GetEnvStr(ENV_PAGE_PageBaseDomain, DefaultPageBaseDomain) + + config.ConfigPath = GetEnvStr(ENV_PAGE_ConfigPath, DefauleConfigPath) + return config +} + +func ParseFile(config *Config) error { + c, err := os.ReadFile(config.ConfigPath) + if err != nil { + return err + } + return yaml.Unmarshal(c, &config) +} + +func mergeConfig(cli, file, envs, defaultKey Config) Config { + config := defaultKey + + config.GiteaServer = GetStr(cli.GiteaServer, file.GiteaServer, envs.GiteaServer, defaultKey.GiteaServer) + config.GiteaToken = GetStr(cli.GiteaToken, file.GiteaToken, envs.GiteaToken, defaultKey.GiteaToken) + config.GiteaBranch = GetStr(cli.GiteaBranch, file.GiteaBranch, envs.GiteaBranch, defaultKey.GiteaBranch) + config.PageBaseDomain = GetStr(cli.PageBaseDomain, file.PageBaseDomain, envs.PageBaseDomain, defaultKey.PageBaseDomain) + config.ConfigPath = GetStr(cli.ConfigPath, file.ConfigPath, envs.ConfigPath, defaultKey.ConfigPath) + + return config +} + +func ParseCli(config *Config) { + flag.StringVar(&config.GiteaServer, "server", config.GiteaServer, "gitea server") + flag.StringVar(&config.GiteaToken, "token", config.GiteaToken, "gitea token") + flag.StringVar(&config.GiteaBranch, "branch", config.GiteaBranch, "gitea branch") + flag.StringVar(&config.PageBaseDomain, "domain", config.PageBaseDomain, "page base domain") + flag.StringVar(&config.ConfigPath, "config", config.ConfigPath, "config path") + flag.Parse() +} + +func Parse() Config { + var config Config = DefauleConfig + + envs := ParseEnvs() + err := ParseFile(&config) + if err != nil { + fmt.Printf("Faild to parse config file: %v\n", err) + } + cli := Config{} + ParseCli(&cli) + + return mergeConfig(cli, config, *envs, DefauleConfig) +} diff --git a/pages/config.yaml b/pages/config.yaml new file mode 100644 index 0000000..7294003 --- /dev/null +++ b/pages/config.yaml @@ -0,0 +1,7 @@ +gitea: + server: "https://gitea.com" + token: "1234" + branch: "public" + +page: + domain: "example.com" \ No newline at end of file diff --git a/pages/const.go b/pages/const.go new file mode 100644 index 0000000..1be5057 --- /dev/null +++ b/pages/const.go @@ -0,0 +1,19 @@ +package pages + +const ( + DefaultGiteaServer = "https://gitea.com" + DefaultGiteaToken = "" + DefaultGiteaBranch = "public" + + DefaultPageBaseDomain = "example.com" + + DefauleConfigPath = "./config.yaml" + + ENV_PAGE_GiteaServer = "GiteaServer" + ENV_PAGE_GiteaToken = "GiteaToken" + ENV_PAGE_GiteaBranch = "GiteaBranch" + + ENV_PAGE_PageBaseDomain = "PageBaseDomain" + + ENV_PAGE_ConfigPath = "PageConfigPath" +) diff --git a/pages/env.go b/pages/env.go new file mode 100644 index 0000000..80c6966 --- /dev/null +++ b/pages/env.go @@ -0,0 +1,2 @@ +package pages + diff --git a/pages/utils.go b/pages/utils.go new file mode 100644 index 0000000..e265be3 --- /dev/null +++ b/pages/utils.go @@ -0,0 +1,25 @@ +package pages + +import ( + "os" + "strings" +) + +func GetStr(key ...string) string { + for _, k := range key { + value := strings.TrimSpace(k) + if value != "" { + return value + } + } + return "" +} + +func GetEnvStr(key, defaultKey string) string { + v, ok := os.LookupEnv(key) + if !ok { + return defaultKey + } + value := strings.TrimSpace(v) + return value +}