mirror of
https://github.com/yusing/godoxy.git
synced 2026-03-31 14:13:09 +02:00
fix: add nil guard before entrypoint retrieval; move config from types/
This commit is contained in:
@@ -74,6 +74,9 @@ func FavIcon(c *gin.Context) {
|
||||
func GetFavIconFromAlias(ctx context.Context, alias string, variant icons.Variant) (iconfetch.Result, error) {
|
||||
// try with route.Icon
|
||||
ep := entrypoint.FromCtx(ctx)
|
||||
if ep == nil { // impossible, but just in case
|
||||
return iconfetch.FetchResultWithErrorf(http.StatusInternalServerError, "entrypoint not initialized")
|
||||
}
|
||||
r, ok := ep.HTTPRoutes().Get(alias)
|
||||
if !ok {
|
||||
return iconfetch.FetchResultWithErrorf(http.StatusNotFound, "route not found")
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
||||
apitypes "github.com/yusing/goutils/apitypes"
|
||||
"github.com/yusing/goutils/http/httpheaders"
|
||||
"github.com/yusing/goutils/http/websocket"
|
||||
|
||||
@@ -25,6 +26,10 @@ import (
|
||||
// @Router /health [get]
|
||||
func Health(c *gin.Context) {
|
||||
ep := entrypoint.FromCtx(c.Request.Context())
|
||||
if ep == nil { // impossible, but just in case
|
||||
c.JSON(http.StatusInternalServerError, apitypes.Error("entrypoint not initialized"))
|
||||
return
|
||||
}
|
||||
if httpheaders.IsWebsocket(c.Request.Header) {
|
||||
websocket.PeriodicWrite(c, 1*time.Second, func() (any, error) {
|
||||
return ep.GetHealthInfoSimple(), nil
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/yusing/godoxy/internal/homepage"
|
||||
|
||||
_ "github.com/yusing/goutils/apitypes"
|
||||
apitypes "github.com/yusing/goutils/apitypes"
|
||||
)
|
||||
|
||||
// @x-id "categories"
|
||||
@@ -22,6 +23,10 @@ import (
|
||||
// @Router /homepage/categories [get]
|
||||
func Categories(c *gin.Context) {
|
||||
ep := entrypoint.FromCtx(c.Request.Context())
|
||||
if ep == nil { // impossible, but just in case
|
||||
c.JSON(http.StatusInternalServerError, apitypes.Error("entrypoint not initialized"))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, HomepageCategories(ep))
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/yusing/godoxy/internal/route"
|
||||
|
||||
_ "github.com/yusing/goutils/apitypes"
|
||||
apitypes "github.com/yusing/goutils/apitypes"
|
||||
)
|
||||
|
||||
type RoutesByProvider map[string][]route.Route
|
||||
@@ -25,5 +26,9 @@ type RoutesByProvider map[string][]route.Route
|
||||
// @Router /route/by_provider [get]
|
||||
func ByProvider(c *gin.Context) {
|
||||
ep := entrypoint.FromCtx(c.Request.Context())
|
||||
if ep == nil { // impossible, but just in case
|
||||
c.JSON(http.StatusInternalServerError, apitypes.Error("entrypoint not initialized"))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, ep.RoutesByProvider())
|
||||
}
|
||||
|
||||
@@ -33,6 +33,11 @@ func Route(c *gin.Context) {
|
||||
}
|
||||
|
||||
ep := entrypoint.FromCtx(c.Request.Context())
|
||||
if ep == nil { // impossible, but just in case
|
||||
c.JSON(http.StatusInternalServerError, apitypes.Error("entrypoint not initialized"))
|
||||
return
|
||||
}
|
||||
|
||||
route, ok := ep.GetRoute(request.Which)
|
||||
if ok {
|
||||
c.JSON(http.StatusOK, route)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/yusing/godoxy/agent/pkg/agent"
|
||||
"github.com/yusing/godoxy/internal/acl"
|
||||
"github.com/yusing/godoxy/internal/autocert"
|
||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint"
|
||||
homepage "github.com/yusing/godoxy/internal/homepage/types"
|
||||
maxmind "github.com/yusing/godoxy/internal/maxmind/types"
|
||||
"github.com/yusing/godoxy/internal/notif"
|
||||
|
||||
@@ -27,7 +27,7 @@ type findRouteFunc func(HTTPRoutes, string) types.HTTPRoute
|
||||
type Entrypoint struct {
|
||||
task *task.Task
|
||||
|
||||
cfg *entrypoint.Config
|
||||
cfg *Config
|
||||
|
||||
middleware *middleware.Middleware
|
||||
notFoundHandler http.Handler
|
||||
@@ -48,9 +48,9 @@ type Entrypoint struct {
|
||||
|
||||
var _ entrypoint.Entrypoint = &Entrypoint{}
|
||||
|
||||
var emptyCfg entrypoint.Config
|
||||
var emptyCfg Config
|
||||
|
||||
func NewEntrypoint(parent task.Parent, cfg *entrypoint.Config) *Entrypoint {
|
||||
func NewEntrypoint(parent task.Parent, cfg *Config) *Entrypoint {
|
||||
if cfg == nil {
|
||||
cfg = &emptyCfg
|
||||
}
|
||||
@@ -91,12 +91,23 @@ func NewEntrypoint(parent task.Parent, cfg *entrypoint.Config) *Entrypoint {
|
||||
return ep
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) ShortLinkMatcher() *ShortLinkMatcher {
|
||||
return ep.shortLinkMatcher
|
||||
func (ep *Entrypoint) SupportProxyProtocol() bool {
|
||||
return ep.cfg.SupportProxyProtocol
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) Config() *entrypoint.Config {
|
||||
return ep.cfg
|
||||
func (ep *Entrypoint) DisablePoolsLog(v bool) {
|
||||
ep.httpPoolDisableLog.Store(v)
|
||||
// apply to all running http servers
|
||||
for _, srv := range ep.servers.Range {
|
||||
srv.routes.DisableLog(v)
|
||||
}
|
||||
// apply to other pools
|
||||
ep.streamRoutes.DisableLog(v)
|
||||
ep.excludedRoutes.DisableLog(v)
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) ShortLinkMatcher() *ShortLinkMatcher {
|
||||
return ep.shortLinkMatcher
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) HTTPRoutes() entrypoint.PoolLike[types.HTTPRoute] {
|
||||
@@ -111,19 +122,12 @@ func (ep *Entrypoint) ExcludedRoutes() entrypoint.RWPoolLike[types.Route] {
|
||||
return ep.excludedRoutes
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) GetServer(addr string) (*httpServer, bool) {
|
||||
func (ep *Entrypoint) GetServer(addr string) (http.Handler, bool) {
|
||||
return ep.servers.Load(addr)
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) DisablePoolsLog(v bool) {
|
||||
ep.httpPoolDisableLog.Store(v)
|
||||
// apply to all running http servers
|
||||
for _, srv := range ep.servers.Range {
|
||||
srv.routes.DisableLog(v)
|
||||
}
|
||||
// apply to other pools
|
||||
ep.streamRoutes.DisableLog(v)
|
||||
ep.excludedRoutes.DisableLog(v)
|
||||
func (ep *Entrypoint) PrintServers() {
|
||||
log.Info().Msgf("servers: %v", xsync.ToPlainMap(ep.servers))
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) SetFindRouteDomains(domains []string) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
. "github.com/yusing/godoxy/internal/entrypoint"
|
||||
entrypoint "github.com/yusing/godoxy/internal/entrypoint/types"
|
||||
"github.com/yusing/godoxy/internal/route"
|
||||
routeTypes "github.com/yusing/godoxy/internal/route/types"
|
||||
"github.com/yusing/godoxy/internal/types"
|
||||
@@ -47,13 +48,15 @@ func (t noopTransport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
}
|
||||
|
||||
func BenchmarkEntrypointReal(b *testing.B) {
|
||||
var ep Entrypoint
|
||||
task := task.NewTestTask(b)
|
||||
ep := NewEntrypoint(task, nil)
|
||||
req := http.Request{
|
||||
Method: "GET",
|
||||
URL: &url.URL{Path: "/", RawPath: "/"},
|
||||
Host: "test.domain.tld",
|
||||
}
|
||||
ep.SetFindRouteDomains([]string{})
|
||||
entrypoint.SetCtx(task, ep)
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Length", "1")
|
||||
@@ -89,7 +92,7 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.Start(task.NewTestTask(b))
|
||||
err = r.Start(task)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@@ -114,13 +117,15 @@ func BenchmarkEntrypointReal(b *testing.B) {
|
||||
}
|
||||
|
||||
func BenchmarkEntrypoint(b *testing.B) {
|
||||
var ep Entrypoint
|
||||
task := task.NewTestTask(b)
|
||||
ep := NewEntrypoint(task, nil)
|
||||
req := http.Request{
|
||||
Method: "GET",
|
||||
URL: &url.URL{Path: "/", RawPath: "/"},
|
||||
Host: "test.domain.tld",
|
||||
}
|
||||
ep.SetFindRouteDomains([]string{})
|
||||
entrypoint.SetCtx(task, ep)
|
||||
|
||||
r := &route.Route{
|
||||
Alias: "test",
|
||||
@@ -139,7 +144,7 @@ func BenchmarkEntrypoint(b *testing.B) {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
err = r.Start(task.RootTask("test", false))
|
||||
err = r.Start(task)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -74,11 +74,14 @@ func (ep *Entrypoint) AddRoute(r types.Route) {
|
||||
func (ep *Entrypoint) AddHTTPRoute(route types.HTTPRoute) error {
|
||||
if port := route.ListenURL().Port(); port == "" || port == "0" {
|
||||
host := route.ListenURL().Hostname()
|
||||
var httpAddr, httpsAddr string
|
||||
if host == "" {
|
||||
host = common.ProxyHTTPHost
|
||||
httpAddr = common.ProxyHTTPAddr
|
||||
httpsAddr = common.ProxyHTTPSAddr
|
||||
} else {
|
||||
httpAddr = net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPPort))
|
||||
httpsAddr = net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPSPort))
|
||||
}
|
||||
httpAddr := net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPPort))
|
||||
httpsAddr := net.JoinHostPort(host, strconv.Itoa(common.ProxyHTTPSPort))
|
||||
return errors.Join(ep.addHTTPRoute(route, httpAddr, HTTPProtoHTTP), ep.addHTTPRoute(route, httpsAddr, HTTPProtoHTTPS))
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ func TestEntrypoint_ShortLinkDispatch(t *testing.T) {
|
||||
ep.ShortLinkMatcher().AddRoute("app")
|
||||
|
||||
server := NewHTTPServer(ep)
|
||||
err := server.Listen("localhost:8080", HTTPProtoHTTP)
|
||||
err := server.Listen("localhost:0", HTTPProtoHTTP)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("shortlink host", func(t *testing.T) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
type Entrypoint interface {
|
||||
Config() *Config
|
||||
SupportProxyProtocol() bool
|
||||
|
||||
DisablePoolsLog(v bool)
|
||||
|
||||
|
||||
@@ -126,7 +126,11 @@ func (s *FileServer) Start(parent task.Parent) gperr.Error {
|
||||
}
|
||||
}
|
||||
|
||||
entrypoint.FromCtx(parent.Context()).AddRoute(s)
|
||||
ep := entrypoint.FromCtx(parent.Context())
|
||||
if ep == nil {
|
||||
return gperr.New("entrypoint not initialized")
|
||||
}
|
||||
ep.AddRoute(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -163,10 +163,15 @@ func (r *ReveseProxyRoute) Start(parent task.Parent) gperr.Error {
|
||||
}
|
||||
}
|
||||
|
||||
ep := entrypoint.FromCtx(parent.Context())
|
||||
if ep == nil {
|
||||
return gperr.New("entrypoint not initialized")
|
||||
}
|
||||
|
||||
if r.UseLoadBalance() {
|
||||
r.addToLoadBalancer(parent)
|
||||
r.addToLoadBalancer(parent, ep)
|
||||
} else {
|
||||
entrypoint.FromCtx(parent.Context()).AddRoute(r)
|
||||
ep.AddRoute(r)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -178,12 +183,11 @@ func (r *ReveseProxyRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
var lbLock sync.Mutex
|
||||
|
||||
func (r *ReveseProxyRoute) addToLoadBalancer(parent task.Parent) {
|
||||
func (r *ReveseProxyRoute) addToLoadBalancer(parent task.Parent, ep entrypoint.Entrypoint) {
|
||||
var lb *loadbalancer.LoadBalancer
|
||||
cfg := r.LoadBalance
|
||||
lbLock.Lock()
|
||||
|
||||
ep := entrypoint.FromCtx(r.task.Context())
|
||||
l, ok := ep.HTTPRoutes().Get(cfg.Link)
|
||||
var linked *ReveseProxyRoute
|
||||
if ok {
|
||||
|
||||
@@ -46,7 +46,7 @@ type (
|
||||
Host string `json:"host,omitempty"`
|
||||
Port route.Port `json:"port"`
|
||||
|
||||
Bind string `json:"bind,omitempty" validate:"omitempty,dive,ip_addr" extensions:"x-nullable"`
|
||||
Bind string `json:"bind,omitempty" validate:"omitempty,ip_addr" extensions:"x-nullable"`
|
||||
|
||||
Root string `json:"root,omitempty"`
|
||||
SPA bool `json:"spa,omitempty"` // Single-page app mode: serves index for non-existent paths
|
||||
@@ -199,7 +199,11 @@ func (r *Route) validate() gperr.Error {
|
||||
|
||||
if (r.Proxmox == nil || r.Proxmox.Node == "" || r.Proxmox.VMID == nil) && r.Container == nil {
|
||||
wasNotNil := r.Proxmox != nil
|
||||
proxmoxProviders := config.WorkingState.Load().Value().Providers.Proxmox
|
||||
workingState := config.WorkingState.Load()
|
||||
var proxmoxProviders []*proxmox.Config
|
||||
if workingState != nil { // nil in tests
|
||||
proxmoxProviders = workingState.Value().Providers.Proxmox
|
||||
}
|
||||
if len(proxmoxProviders) > 0 {
|
||||
// it's fine if ip is nil
|
||||
hostname := r.Host
|
||||
|
||||
@@ -82,7 +82,11 @@ func (r *StreamRoute) Start(parent task.Parent) gperr.Error {
|
||||
r.l.Info().Msg("stream closed")
|
||||
})
|
||||
|
||||
entrypoint.FromCtx(parent.Context()).AddRoute(r)
|
||||
ep := entrypoint.FromCtx(parent.Context())
|
||||
if ep == nil {
|
||||
return gperr.New("entrypoint not initialized")
|
||||
}
|
||||
ep.AddRoute(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,10 @@ func (s *TCPTCPStream) ListenAndServe(ctx context.Context, preDial, onRead netty
|
||||
s.listener = acl.WrapTCP(s.listener)
|
||||
}
|
||||
|
||||
if proxyProto := entrypoint.FromCtx(ctx).Config().SupportProxyProtocol; proxyProto {
|
||||
s.listener = &proxyproto.Listener{Listener: s.listener}
|
||||
if ep := entrypoint.FromCtx(ctx); ep != nil {
|
||||
if proxyProto := entrypoint.FromCtx(ctx).SupportProxyProtocol(); proxyProto {
|
||||
s.listener = &proxyproto.Listener{Listener: s.listener}
|
||||
}
|
||||
}
|
||||
|
||||
s.preDial = preDial
|
||||
|
||||
Reference in New Issue
Block a user