mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-25 01:38:30 +02:00
Merge branch 'main' into dev
This commit is contained in:
39
.github/workflows/merge-main-into-compat.yml
vendored
Normal file
39
.github/workflows/merge-main-into-compat.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Cherry-pick into Compat
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v*
|
||||||
|
paths:
|
||||||
|
- ".github/workflows/merge-main-into-compat.yml"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cherry-pick:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Configure git user
|
||||||
|
run: |
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
- name: Cherry-pick commits from last tag
|
||||||
|
run: |
|
||||||
|
git fetch origin compat
|
||||||
|
git checkout compat
|
||||||
|
CURRENT_TAG=${{ github.ref_name }}
|
||||||
|
PREV_TAG=$(git describe --tags --abbrev=0 $CURRENT_TAG^ 2>/dev/null || echo "")
|
||||||
|
|
||||||
|
if [ -z "$PREV_TAG" ]; then
|
||||||
|
echo "No previous tag found. Cherry-picking all commits up to $CURRENT_TAG"
|
||||||
|
git rev-list --reverse --no-merges $CURRENT_TAG | xargs -r git cherry-pick
|
||||||
|
else
|
||||||
|
echo "Cherry-picking commits from $PREV_TAG to $CURRENT_TAG"
|
||||||
|
git rev-list --reverse --no-merges $PREV_TAG..$CURRENT_TAG | xargs -r git cherry-pick
|
||||||
|
fi
|
||||||
|
- name: Push compat
|
||||||
|
run: |
|
||||||
|
git push origin compat
|
||||||
2
goutils
2
goutils
Submodule goutils updated: 6c698b1d55...cb0f79b51c
@@ -31,6 +31,9 @@ func (c containerHelper) getAliases() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c containerHelper) getName() string {
|
func (c containerHelper) getName() string {
|
||||||
|
if len(c.Names) == 0 { // Why did it happen? Every container must have a name.
|
||||||
|
return ""
|
||||||
|
}
|
||||||
return strings.TrimPrefix(c.Names[0], "/")
|
return strings.TrimPrefix(c.Names[0], "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ func NewWatcher(parent task.Parent, r types.Route, cfg *types.IdlewatcherConfig)
|
|||||||
depCfg = new(types.IdlewatcherConfig)
|
depCfg = new(types.IdlewatcherConfig)
|
||||||
depCfg.IdlewatcherConfigBase = cfg.IdlewatcherConfigBase
|
depCfg.IdlewatcherConfigBase = cfg.IdlewatcherConfigBase
|
||||||
depCfg.IdleTimeout = neverTick // disable auto sleep for dependencies
|
depCfg.IdleTimeout = neverTick // disable auto sleep for dependencies
|
||||||
} else if depCfg.IdleTimeout > 0 {
|
} else if depCfg.IdleTimeout > 0 && depCfg.IdleTimeout != neverTick {
|
||||||
depErrors.Addf("dependency %q has positive idle timeout %s", dep, depCfg.IdleTimeout)
|
depErrors.Addf("dependency %q has positive idle timeout %s", dep, depCfg.IdleTimeout)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package route
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -27,8 +28,25 @@ type (
|
|||||||
|
|
||||||
var _ types.FileServerRoute = (*FileServer)(nil)
|
var _ types.FileServerRoute = (*FileServer)(nil)
|
||||||
|
|
||||||
func handler(root string) http.Handler {
|
func handler(root string, spa bool, index string) http.Handler {
|
||||||
return http.FileServer(http.Dir(root))
|
if !spa {
|
||||||
|
return http.FileServer(http.Dir(root))
|
||||||
|
}
|
||||||
|
indexPath := filepath.Join(root, index)
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
urlPath := path.Clean(r.URL.Path)
|
||||||
|
if urlPath == "/" {
|
||||||
|
http.ServeFile(w, r, indexPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fullPath := filepath.Join(root, filepath.FromSlash(urlPath))
|
||||||
|
stat, err := os.Stat(fullPath)
|
||||||
|
if err == nil && !stat.IsDir() {
|
||||||
|
http.ServeFile(w, r, fullPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.ServeFile(w, r, indexPath)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewFileServer(base *Route) (*FileServer, gperr.Error) {
|
func NewFileServer(base *Route) (*FileServer, gperr.Error) {
|
||||||
@@ -39,7 +57,12 @@ func NewFileServer(base *Route) (*FileServer, gperr.Error) {
|
|||||||
return nil, gperr.New("`root` must be an absolute path")
|
return nil, gperr.New("`root` must be an absolute path")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.handler = handler(s.Root)
|
if s.Index == "" {
|
||||||
|
s.Index = "/index.html"
|
||||||
|
} else if s.Index[0] != '/' {
|
||||||
|
s.Index = "/" + s.Index
|
||||||
|
}
|
||||||
|
s.handler = handler(s.Root, s.SPA, s.Index)
|
||||||
|
|
||||||
if len(s.Middlewares) > 0 {
|
if len(s.Middlewares) > 0 {
|
||||||
mid, err := middleware.BuildMiddlewareFromMap(s.Alias, s.Middlewares)
|
mid, err := middleware.BuildMiddlewareFromMap(s.Alias, s.Middlewares)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/yusing/godoxy/internal/net/gphttp/middleware"
|
"github.com/yusing/godoxy/internal/net/gphttp/middleware"
|
||||||
nettypes "github.com/yusing/godoxy/internal/net/types"
|
nettypes "github.com/yusing/godoxy/internal/net/types"
|
||||||
"github.com/yusing/godoxy/internal/route/routes"
|
"github.com/yusing/godoxy/internal/route/routes"
|
||||||
|
route "github.com/yusing/godoxy/internal/route/types"
|
||||||
"github.com/yusing/godoxy/internal/types"
|
"github.com/yusing/godoxy/internal/types"
|
||||||
"github.com/yusing/godoxy/internal/watcher/health/monitor"
|
"github.com/yusing/godoxy/internal/watcher/health/monitor"
|
||||||
gperr "github.com/yusing/goutils/errs"
|
gperr "github.com/yusing/goutils/errs"
|
||||||
@@ -60,6 +61,28 @@ func NewReverseProxyRoute(base *Route) (*ReveseProxyRoute, gperr.Error) {
|
|||||||
service := base.Name()
|
service := base.Name()
|
||||||
rp := reverseproxy.NewReverseProxy(service, &proxyURL.URL, trans)
|
rp := reverseproxy.NewReverseProxy(service, &proxyURL.URL, trans)
|
||||||
|
|
||||||
|
scheme := base.Scheme
|
||||||
|
retried := false
|
||||||
|
retryLock := sync.Mutex{}
|
||||||
|
rp.OnSchemeMisMatch = func() (retry bool) { // switch scheme and retry
|
||||||
|
retryLock.Lock()
|
||||||
|
defer retryLock.Unlock()
|
||||||
|
|
||||||
|
if retried {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
retried = true
|
||||||
|
|
||||||
|
if scheme == route.SchemeHTTP {
|
||||||
|
rp.TargetURL.Scheme = "https"
|
||||||
|
} else {
|
||||||
|
rp.TargetURL.Scheme = "http"
|
||||||
|
}
|
||||||
|
rp.Info().Msgf("scheme mismatch detected, retrying with %s", rp.TargetURL.Scheme)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
if len(base.Middlewares) > 0 {
|
if len(base.Middlewares) > 0 {
|
||||||
err := middleware.PatchReverseProxy(rp, base.Middlewares)
|
err := middleware.PatchReverseProxy(rp, base.Middlewares)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -44,7 +44,10 @@ type (
|
|||||||
Scheme route.Scheme `json:"scheme,omitempty" swaggertype:"string" enums:"http,https,tcp,udp,fileserver"`
|
Scheme route.Scheme `json:"scheme,omitempty" swaggertype:"string" enums:"http,https,tcp,udp,fileserver"`
|
||||||
Host string `json:"host,omitempty"`
|
Host string `json:"host,omitempty"`
|
||||||
Port route.Port `json:"port"`
|
Port route.Port `json:"port"`
|
||||||
Root string `json:"root,omitempty"`
|
|
||||||
|
Root string `json:"root,omitempty"`
|
||||||
|
SPA bool `json:"spa,omitempty"` // Single-page app mode: serves index for non-existent paths
|
||||||
|
Index string `json:"index,omitempty"` // Index file to serve for single-page app mode
|
||||||
|
|
||||||
route.HTTPConfig
|
route.HTTPConfig
|
||||||
PathPatterns []string `json:"path_patterns,omitempty" extensions:"x-nullable"`
|
PathPatterns []string `json:"path_patterns,omitempty" extensions:"x-nullable"`
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ func NewHTTPHealthMonitor(url *url.URL, config types.HealthCheckConfig) *HTTPHea
|
|||||||
return mon
|
return mon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var userAgent = "GoDoxy/" + version.Get().String()
|
||||||
|
|
||||||
func (mon *HTTPHealthMonitor) CheckHealth() (types.HealthCheckResult, error) {
|
func (mon *HTTPHealthMonitor) CheckHealth() (types.HealthCheckResult, error) {
|
||||||
req := fasthttp.AcquireRequest()
|
req := fasthttp.AcquireRequest()
|
||||||
defer fasthttp.ReleaseRequest(req)
|
defer fasthttp.ReleaseRequest(req)
|
||||||
@@ -49,7 +51,7 @@ func (mon *HTTPHealthMonitor) CheckHealth() (types.HealthCheckResult, error) {
|
|||||||
|
|
||||||
req.SetRequestURI(mon.url.Load().JoinPath(mon.config.Path).String())
|
req.SetRequestURI(mon.url.Load().JoinPath(mon.config.Path).String())
|
||||||
req.Header.SetMethod(mon.method)
|
req.Header.SetMethod(mon.method)
|
||||||
req.Header.Set("User-Agent", "GoDoxy/"+version.Get().String())
|
req.Header.Set("User-Agent", userAgent)
|
||||||
req.Header.Set("Accept", "text/plain,text/html,*/*;q=0.8")
|
req.Header.Set("Accept", "text/plain,text/html,*/*;q=0.8")
|
||||||
req.Header.Set("Accept-Encoding", "identity")
|
req.Header.Set("Accept-Encoding", "identity")
|
||||||
req.Header.Set("Cache-Control", "no-cache")
|
req.Header.Set("Cache-Control", "no-cache")
|
||||||
|
|||||||
@@ -74,7 +74,11 @@ func NewMonitor(r types.Route) types.HealthMonCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newMonitor(u *url.URL, cfg types.HealthCheckConfig, healthCheckFunc HealthCheckFunc) *monitor {
|
func newMonitor(u *url.URL, cfg types.HealthCheckConfig, healthCheckFunc HealthCheckFunc) *monitor {
|
||||||
cfg.ApplyDefaults(config.WorkingState.Load().Value().Defaults.HealthCheck)
|
if state := config.WorkingState.Load(); state != nil {
|
||||||
|
cfg.ApplyDefaults(state.Value().Defaults.HealthCheck)
|
||||||
|
} else {
|
||||||
|
cfg.ApplyDefaults(types.HealthCheckConfig{}) // use defaults from constants
|
||||||
|
}
|
||||||
mon := &monitor{
|
mon := &monitor{
|
||||||
config: cfg,
|
config: cfg,
|
||||||
checkHealth: healthCheckFunc,
|
checkHealth: healthCheckFunc,
|
||||||
|
|||||||
Reference in New Issue
Block a user