new 1
This commit is contained in:
parent
9d86fd33c6
commit
da94a4b7b0
7 changed files with 133 additions and 246 deletions
246
caddyfile.go
246
caddyfile.go
|
@ -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)
|
|
||||||
)
|
|
1
main.go
Normal file
1
main.go
Normal file
|
@ -0,0 +1 @@
|
||||||
|
package main
|
79
pages/config.go
Normal file
79
pages/config.go
Normal file
|
@ -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)
|
||||||
|
}
|
7
pages/config.yaml
Normal file
7
pages/config.yaml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
gitea:
|
||||||
|
server: "https://gitea.com"
|
||||||
|
token: "1234"
|
||||||
|
branch: "public"
|
||||||
|
|
||||||
|
page:
|
||||||
|
domain: "example.com"
|
19
pages/const.go
Normal file
19
pages/const.go
Normal file
|
@ -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"
|
||||||
|
)
|
2
pages/env.go
Normal file
2
pages/env.go
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
package pages
|
||||||
|
|
25
pages/utils.go
Normal file
25
pages/utils.go
Normal file
|
@ -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
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue