refactor(api): restructured API for type safety, maintainability and docs generation

- These changes makes the API incombatible with previous versions
- Added new types for error handling, success responses, and health checks.
- Updated health check logic to utilize the new types for better clarity and structure.
- Refactored existing handlers to improve response consistency and error handling.
- Updated Makefile to include a new target for generating API types from Swagger.
- Updated "new agent" API to respond an encrypted cert pair
This commit is contained in:
yusing
2025-08-16 13:04:05 +08:00
parent fce9ce21c9
commit 35a3e3fef6
149 changed files with 13173 additions and 2173 deletions

View File

@@ -3,20 +3,21 @@ package route
import (
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/types"
)
func checkExists(r routes.Route) gperr.Error {
func checkExists(r types.Route) gperr.Error {
if r.UseLoadBalance() { // skip checking for load balanced routes
return nil
}
var (
existing routes.Route
existing types.Route
ok bool
)
switch r := r.(type) {
case routes.HTTPRoute:
case types.HTTPRoute:
existing, ok = routes.HTTP.Get(r.Key())
case routes.StreamRoute:
case types.StreamRoute:
existing, ok = routes.Stream.Get(r.Key())
}
if ok {

View File

@@ -14,7 +14,7 @@ type AgentProvider struct {
}
func (p *AgentProvider) ShortName() string {
return p.AgentConfig.Name()
return p.AgentConfig.Name
}
func (p *AgentProvider) NewWatcher() watcher.Watcher {

View File

@@ -13,6 +13,7 @@ import (
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/route"
"github.com/yusing/go-proxy/internal/serialization"
"github.com/yusing/go-proxy/internal/types"
"github.com/yusing/go-proxy/internal/utils/strutils"
"github.com/yusing/go-proxy/internal/watcher"
)
@@ -78,7 +79,7 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
}
if container.IsHostNetworkMode {
err := container.UpdatePorts()
err := docker.UpdatePorts(container)
if err != nil {
errs.Add(gperr.PrependSubject(container.ContainerName, err))
continue
@@ -111,7 +112,7 @@ func (p *DockerProvider) loadRoutesImpl() (route.Routes, gperr.Error) {
// Returns a list of proxy entries for a container.
// Always non-nil.
func (p *DockerProvider) routesFromContainerLabels(container *docker.Container) (route.Routes, gperr.Error) {
func (p *DockerProvider) routesFromContainerLabels(container *types.Container) (route.Routes, gperr.Error) {
if !container.IsExplicit && p.IsExplicitOnly() {
return make(route.Routes, 0), nil
}
@@ -138,10 +139,10 @@ func (p *DockerProvider) routesFromContainerLabels(container *docker.Container)
continue
}
entryMap, ok := entryMapAny.(docker.LabelMap)
entryMap, ok := entryMapAny.(types.LabelMap)
if !ok {
// try to deserialize to map
entryMap = make(docker.LabelMap)
entryMap = make(types.LabelMap)
yamlStr, ok := entryMapAny.(string)
if !ok {
// should not happen

View File

@@ -10,11 +10,12 @@ import (
"github.com/rs/zerolog"
"github.com/yusing/go-proxy/agent/pkg/agent"
"github.com/yusing/go-proxy/internal/docker"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/route"
provider "github.com/yusing/go-proxy/internal/route/provider/types"
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/types"
W "github.com/yusing/go-proxy/internal/watcher"
"github.com/yusing/go-proxy/internal/watcher/events"
)
@@ -45,7 +46,7 @@ const (
var ErrEmptyProviderName = errors.New("empty provider name")
var _ routes.Provider = (*Provider)(nil)
var _ types.RouteProvider = (*Provider)(nil)
func newProvider(t provider.Type) *Provider {
return &Provider{t: t}
@@ -76,7 +77,7 @@ func NewAgentProvider(cfg *agent.AgentConfig) *Provider {
p := newProvider(provider.ProviderTypeAgent)
agent := &AgentProvider{
AgentConfig: cfg,
docker: DockerProviderImpl(cfg.Name(), cfg.FakeDockerHost()),
docker: DockerProviderImpl(cfg.Name, cfg.FakeDockerHost()),
}
p.ProviderImpl = agent
p.watcher = p.NewWatcher()
@@ -145,7 +146,7 @@ func (p *Provider) NumRoutes() int {
return len(p.routes)
}
func (p *Provider) IterRoutes(yield func(string, routes.Route) bool) {
func (p *Provider) IterRoutes(yield func(string, types.Route) bool) {
routes := p.lockCloneRoutes()
for alias, r := range routes {
if !yield(alias, r.Impl()) {
@@ -154,7 +155,7 @@ func (p *Provider) IterRoutes(yield func(string, routes.Route) bool) {
}
}
func (p *Provider) FindService(project, service string) (routes.Route, bool) {
func (p *Provider) FindService(project, service string) (types.Route, bool) {
switch p.GetType() {
case provider.ProviderTypeDocker, provider.ProviderTypeAgent:
default:
@@ -166,17 +167,17 @@ func (p *Provider) FindService(project, service string) (routes.Route, bool) {
routes := p.lockCloneRoutes()
for _, r := range routes {
cont := r.ContainerInfo()
if cont.DockerComposeProject() != project {
if docker.DockerComposeProject(cont) != project {
continue
}
if cont.DockerComposeService() == service {
if docker.DockerComposeService(cont) == service {
return r.Impl(), true
}
}
return nil, false
}
func (p *Provider) GetRoute(alias string) (routes.Route, bool) {
func (p *Provider) GetRoute(alias string) (types.Route, bool) {
r, ok := p.lockGetRoute(alias)
if !ok {
return nil, false

View File

@@ -1,61 +1,12 @@
package provider
import (
R "github.com/yusing/go-proxy/internal/route"
provider "github.com/yusing/go-proxy/internal/route/provider/types"
route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/watcher/health"
"github.com/yusing/go-proxy/internal/types"
)
type (
RouteStats struct {
Total uint16 `json:"total"`
NumHealthy uint16 `json:"healthy"`
NumUnhealthy uint16 `json:"unhealthy"`
NumNapping uint16 `json:"napping"`
NumError uint16 `json:"error"`
NumUnknown uint16 `json:"unknown"`
}
ProviderStats struct {
Total uint16 `json:"total"`
RPs RouteStats `json:"reverse_proxies"`
Streams RouteStats `json:"streams"`
Type provider.Type `json:"type"`
}
)
func (stats *RouteStats) Add(r *R.Route) {
stats.Total++
mon := r.HealthMonitor()
if mon == nil {
stats.NumUnknown++
return
}
switch mon.Status() {
case health.StatusHealthy:
stats.NumHealthy++
case health.StatusUnhealthy:
stats.NumUnhealthy++
case health.StatusNapping:
stats.NumNapping++
case health.StatusError:
stats.NumError++
default:
stats.NumUnknown++
}
}
func (stats *RouteStats) AddOther(other RouteStats) {
stats.Total += other.Total
stats.NumHealthy += other.NumHealthy
stats.NumUnhealthy += other.NumUnhealthy
stats.NumNapping += other.NumNapping
stats.NumError += other.NumError
stats.NumUnknown += other.NumUnknown
}
func (p *Provider) Statistics() ProviderStats {
var rps, streams RouteStats
func (p *Provider) Statistics() types.ProviderStats {
var rps, streams types.RouteStats
for _, r := range p.routes {
switch r.Type() {
case route.RouteTypeHTTP:
@@ -64,7 +15,7 @@ func (p *Provider) Statistics() ProviderStats {
streams.Add(r)
}
}
return ProviderStats{
return types.ProviderStats{
Total: rps.Total + streams.Total,
RPs: rps,
Streams: streams,

View File

@@ -1,6 +1,6 @@
package provider
type Type string
type Type string // @name ProviderType
const (
ProviderTypeDocker Type = "docker"

View File

@@ -13,12 +13,12 @@ import (
"github.com/yusing/go-proxy/internal/logging/accesslog"
gphttp "github.com/yusing/go-proxy/internal/net/gphttp"
"github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer"
loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types"
"github.com/yusing/go-proxy/internal/net/gphttp/middleware"
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
nettypes "github.com/yusing/go-proxy/internal/net/types"
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/types"
"github.com/yusing/go-proxy/internal/watcher/health/monitor"
)
@@ -30,7 +30,7 @@ type ReveseProxyRoute struct {
rp *reverseproxy.ReverseProxy
}
var _ routes.ReverseProxyRoute = (*ReveseProxyRoute)(nil)
var _ types.ReverseProxyRoute = (*ReveseProxyRoute)(nil)
// var globalMux = http.NewServeMux() // TODO: support regex subdomain matching.
@@ -196,7 +196,7 @@ func (r *ReveseProxyRoute) addToLoadBalancer(parent task.Parent) {
}
r.loadBalancer = lb
server := loadbalance.NewServer(r.task.Name(), r.ProxyURL, r.LoadBalance.Weight, r.handler, r.HealthMon)
server := loadbalancer.NewServer(r.task.Name(), r.ProxyURL, r.LoadBalance.Weight, r.handler, r.HealthMon)
lb.AddServer(server)
r.task.OnCancel("lb_remove_server", func() {
lb.RemoveServer(server)

View File

@@ -14,18 +14,16 @@ import (
"github.com/yusing/go-proxy/internal/docker"
"github.com/yusing/go-proxy/internal/gperr"
"github.com/yusing/go-proxy/internal/homepage"
idlewatcher "github.com/yusing/go-proxy/internal/idlewatcher/types"
netutils "github.com/yusing/go-proxy/internal/net"
nettypes "github.com/yusing/go-proxy/internal/net/types"
"github.com/yusing/go-proxy/internal/proxmox"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/types"
"github.com/yusing/go-proxy/internal/utils/strutils"
"github.com/yusing/go-proxy/internal/watcher/health"
"github.com/yusing/go-proxy/internal/common"
config "github.com/yusing/go-proxy/internal/config/types"
"github.com/yusing/go-proxy/internal/logging/accesslog"
loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types"
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/route/rules"
route "github.com/yusing/go-proxy/internal/route/types"
@@ -43,39 +41,41 @@ type (
Root string `json:"root,omitempty"`
route.HTTPConfig
PathPatterns []string `json:"path_patterns,omitempty"`
Rules rules.Rules `json:"rules,omitempty" validate:"omitempty,unique=Name"`
HealthCheck *health.HealthCheckConfig `json:"healthcheck,omitempty"`
LoadBalance *loadbalance.Config `json:"load_balance,omitempty"`
Middlewares map[string]docker.LabelMap `json:"middlewares,omitempty"`
Homepage *homepage.ItemConfig `json:"homepage,omitempty"`
AccessLog *accesslog.RequestLoggerConfig `json:"access_log,omitempty"`
PathPatterns []string `json:"path_patterns,omitempty" extensions:"x-nullable"`
Rules rules.Rules `json:"rules,omitempty" validate:"omitempty,unique=Name" extension:"x-nullable"`
HealthCheck *types.HealthCheckConfig `json:"healthcheck"`
LoadBalance *types.LoadBalancerConfig `json:"load_balance,omitempty" extensions:"x-nullable"`
Middlewares map[string]types.LabelMap `json:"middlewares,omitempty" extensions:"x-nullable"`
Homepage *homepage.ItemConfig `json:"homepage"`
AccessLog *accesslog.RequestLoggerConfig `json:"access_log,omitempty" extensions:"x-nullable"`
Agent string `json:"agent,omitempty"`
Idlewatcher *idlewatcher.Config `json:"idlewatcher,omitempty"`
HealthMon health.HealthMonitor `json:"health,omitempty"`
Idlewatcher *types.IdlewatcherConfig `json:"idlewatcher,omitempty" extensions:"x-nullable"`
HealthMon types.HealthMonitor `json:"health,omitempty" swaggerignore:"true"`
// for swagger
HealthJSON *types.HealthJSON `form:"health"`
Metadata `deserialize:"-"`
}
Metadata struct {
/* Docker only */
Container *docker.Container `json:"container,omitempty"`
Container *types.Container `json:"container,omitempty" extensions:"x-nullable"`
Provider string `json:"provider,omitempty"` // for backward compatibility
Provider string `json:"provider,omitempty" extensions:"x-nullable"` // for backward compatibility
// private fields
LisURL *nettypes.URL `json:"lurl,omitempty"`
ProxyURL *nettypes.URL `json:"purl,omitempty"`
LisURL *nettypes.URL `json:"lurl,omitempty" swaggertype:"string" extensions:"x-nullable"`
ProxyURL *nettypes.URL `json:"purl,omitempty" swaggertype:"string"`
Excluded *bool `json:"excluded"`
impl routes.Route
impl types.Route
task *task.Task
isValidated bool
lastError gperr.Error
provider routes.Provider
provider types.RouteProvider
agent *agent.AgentConfig
@@ -212,7 +212,7 @@ func (r *Route) Validate() gperr.Error {
errs := gperr.NewBuilder("entry validation failed")
var impl routes.Route
var impl types.Route
var err gperr.Error
switch r.Scheme {
@@ -263,7 +263,7 @@ func (r *Route) Validate() gperr.Error {
return nil
}
func (r *Route) Impl() routes.Route {
func (r *Route) Impl() types.Route {
return r.impl
}
@@ -318,11 +318,11 @@ func (r *Route) Started() <-chan struct{} {
return r.started
}
func (r *Route) GetProvider() routes.Provider {
func (r *Route) GetProvider() types.RouteProvider {
return r.provider
}
func (r *Route) SetProvider(p routes.Provider) {
func (r *Route) SetProvider(p types.RouteProvider) {
r.provider = p
r.Provider = p.ShortName()
}
@@ -384,26 +384,26 @@ func (r *Route) IsAgent() bool {
return r.GetAgent() != nil
}
func (r *Route) HealthMonitor() health.HealthMonitor {
func (r *Route) HealthMonitor() types.HealthMonitor {
return r.HealthMon
}
func (r *Route) SetHealthMonitor(m health.HealthMonitor) {
func (r *Route) SetHealthMonitor(m types.HealthMonitor) {
if r.HealthMon != nil && r.HealthMon != m {
r.HealthMon.Finish("health monitor replaced")
}
r.HealthMon = m
}
func (r *Route) IdlewatcherConfig() *idlewatcher.Config {
func (r *Route) IdlewatcherConfig() *types.IdlewatcherConfig {
return r.Idlewatcher
}
func (r *Route) HealthCheckConfig() *health.HealthCheckConfig {
func (r *Route) HealthCheckConfig() *types.HealthCheckConfig {
return r.HealthCheck
}
func (r *Route) LoadBalanceConfig() *loadbalance.Config {
func (r *Route) LoadBalanceConfig() *types.LoadBalancerConfig {
return r.LoadBalance
}
@@ -419,7 +419,7 @@ func (r *Route) HomepageItem() *homepage.Item {
}
}
func (r *Route) ContainerInfo() *docker.Container {
func (r *Route) ContainerInfo() *types.Container {
return r.Container
}
@@ -447,7 +447,7 @@ func (r *Route) ShouldExclude() bool {
return true
case r.IsZeroPort() && !r.UseIdleWatcher():
return true
case !r.Container.IsExplicit && r.Container.IsBlacklisted():
case !r.Container.IsExplicit && docker.IsBlacklisted(r.Container):
return true
case strings.HasPrefix(r.Container.ContainerName, "buildx_"):
return true
@@ -579,7 +579,7 @@ func (r *Route) Finalize() {
r.Port.Listening, r.Port.Proxy = lp, pp
if r.HealthCheck == nil {
r.HealthCheck = health.DefaultHealthConfig()
r.HealthCheck = types.DefaultHealthConfig()
}
if !r.HealthCheck.Disable {

View File

@@ -5,11 +5,9 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/docker"
loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types"
route "github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/types"
expect "github.com/yusing/go-proxy/internal/utils/testing"
"github.com/yusing/go-proxy/internal/watcher/health"
)
func TestRouteValidate(t *testing.T) {
@@ -43,10 +41,10 @@ func TestRouteValidate(t *testing.T) {
Scheme: route.SchemeHTTP,
Host: "example.com",
Port: route.Port{Proxy: 80},
HealthCheck: &health.HealthCheckConfig{
HealthCheck: &types.HealthCheckConfig{
Disable: true,
},
LoadBalance: &loadbalance.Config{
LoadBalance: &types.LoadBalancerConfig{
Link: "test-link",
}, // Minimal LoadBalance config with non-empty Link will be checked by UseLoadBalance
}
@@ -99,9 +97,9 @@ func TestRouteValidate(t *testing.T) {
Host: "example.com",
Port: route.Port{Proxy: 80},
Metadata: Metadata{
Container: &docker.Container{
Container: &types.Container{
ContainerID: "test-id",
Image: &docker.ContainerImage{
Image: &types.ContainerImage{
Name: "test-image",
},
},
@@ -157,9 +155,9 @@ func TestDockerRouteDisallowAgent(t *testing.T) {
Port: route.Port{Proxy: 80},
Agent: "test-agent",
Metadata: Metadata{
Container: &docker.Container{
Container: &types.Container{
ContainerID: "test-id",
Image: &docker.ContainerImage{
Image: &types.ContainerImage{
Name: "test-image",
},
},

View File

@@ -4,18 +4,20 @@ import (
"context"
"net/http"
"net/url"
"github.com/yusing/go-proxy/internal/types"
)
type RouteContext struct{}
var routeContextKey = RouteContext{}
func WithRouteContext(r *http.Request, route HTTPRoute) *http.Request {
func WithRouteContext(r *http.Request, route types.HTTPRoute) *http.Request {
return r.WithContext(context.WithValue(r.Context(), routeContextKey, route))
}
func TryGetRoute(r *http.Request) HTTPRoute {
if route, ok := r.Context().Value(routeContextKey).(HTTPRoute); ok {
func TryGetRoute(r *http.Request) types.HTTPRoute {
if route, ok := r.Context().Value(routeContextKey).(types.HTTPRoute); ok {
return route
}
return nil

View File

@@ -2,84 +2,80 @@ package routes
import (
"encoding/json"
"fmt"
"math"
"net/url"
"strings"
"time"
"github.com/yusing/go-proxy/internal/homepage"
"github.com/yusing/go-proxy/internal/watcher/health"
"github.com/yusing/go-proxy/internal/types"
)
func getHealthInfo(r Route) map[string]string {
mon := r.HealthMonitor()
if mon == nil {
return map[string]string{
"status": "unknown",
"uptime": "n/a",
"latency": "n/a",
"detail": "n/a",
}
}
return map[string]string{
"status": mon.Status().String(),
"uptime": mon.Uptime().Round(time.Second).String(),
"latency": mon.Latency().Round(time.Microsecond).String(),
"detail": mon.Detail(),
}
type HealthInfo struct {
Status types.HealthStatus `json:"status" swaggertype:"string" enums:"healthy,unhealthy,napping,starting,error,unknown"`
Uptime time.Duration `json:"uptime" swaggertype:"number"` // uptime in milliseconds
Latency time.Duration `json:"latency" swaggertype:"number"` // latency in microseconds
Detail string `json:"detail"`
}
type HealthInfoRaw struct {
Status health.Status `json:"status"`
Latency time.Duration `json:"latency"`
}
func (info *HealthInfoRaw) MarshalJSON() ([]byte, error) {
func (info *HealthInfo) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]any{
"status": info.Status.String(),
"latency": info.Latency.Milliseconds(),
"latency": info.Latency.Microseconds(),
"uptime": info.Uptime.Milliseconds(),
"detail": info.Detail,
})
}
func (info *HealthInfoRaw) UnmarshalJSON(data []byte) error {
var v map[string]any
func (info *HealthInfo) UnmarshalJSON(data []byte) error {
var v struct {
Status string `json:"status"`
Latency int64 `json:"latency"`
Uptime int64 `json:"uptime"`
Detail string `json:"detail"`
}
if err := json.Unmarshal(data, &v); err != nil {
return err
}
if status, ok := v["status"].(string); ok {
info.Status = health.NewStatus(status)
// overflow check
if math.MaxInt64/time.Microsecond < time.Duration(v.Latency) {
return fmt.Errorf("latency overflow: %d", v.Latency)
}
if latency, ok := v["latency"].(float64); ok {
info.Latency = time.Duration(latency)
if math.MaxInt64/time.Millisecond < time.Duration(v.Uptime) {
return fmt.Errorf("uptime overflow: %d", v.Uptime)
}
info.Status = types.NewHealthStatusFromString(v.Status)
info.Latency = time.Duration(v.Latency) * time.Microsecond
info.Uptime = time.Duration(v.Uptime) * time.Millisecond
info.Detail = v.Detail
return nil
}
func getHealthInfoRaw(r Route) *HealthInfoRaw {
mon := r.HealthMonitor()
if mon == nil {
return &HealthInfoRaw{
Status: health.StatusUnknown,
Latency: time.Duration(0),
}
}
return &HealthInfoRaw{
Status: mon.Status(),
Latency: mon.Latency(),
}
}
func HealthMap() map[string]map[string]string {
healthMap := make(map[string]map[string]string, NumRoutes())
func GetHealthInfo() map[string]HealthInfo {
healthMap := make(map[string]HealthInfo, NumRoutes())
for r := range Iter {
healthMap[r.Name()] = getHealthInfo(r)
}
return healthMap
}
func HealthInfo() map[string]*HealthInfoRaw {
healthMap := make(map[string]*HealthInfoRaw, NumRoutes())
for r := range Iter {
healthMap[r.Name()] = getHealthInfoRaw(r)
func getHealthInfo(r types.Route) HealthInfo {
mon := r.HealthMonitor()
if mon == nil {
return HealthInfo{
Status: types.StatusUnknown,
Detail: "n/a",
}
}
return HealthInfo{
Status: mon.Status(),
Uptime: mon.Uptime(),
Latency: mon.Latency(),
Detail: mon.Detail(),
}
return healthMap
}
func HomepageCategories() []string {
@@ -99,7 +95,13 @@ func HomepageCategories() []string {
return categories
}
func HomepageConfig(categoryFilter, providerFilter string) homepage.Homepage {
func HomepageItems(proto, hostname, categoryFilter, providerFilter string) homepage.Homepage {
switch proto {
case "http", "https":
default:
proto = "http"
}
hp := make(homepage.Homepage)
for _, r := range HTTP.Iter {
@@ -110,13 +112,32 @@ func HomepageConfig(categoryFilter, providerFilter string) homepage.Homepage {
if categoryFilter != "" && item.Category != categoryFilter {
continue
}
// clear url if invalid
_, err := url.Parse(item.URL)
if err != nil {
item.URL = ""
}
// append hostname if provided and only if alias is not FQDN
if hostname != "" && item.URL == "" {
if !strings.Contains(item.Alias, ".") {
item.URL = fmt.Sprintf("%s://%s.%s", proto, item.Alias, hostname)
}
}
// prepend protocol if not exists
if !strings.HasPrefix(item.URL, "http://") && !strings.HasPrefix(item.URL, "https://") {
item.URL = fmt.Sprintf("%s://%s", proto, item.URL)
}
hp.Add(item)
}
return hp
}
func ByProvider() map[string][]Route {
rts := make(map[string][]Route)
func ByProvider() map[string][]types.Route {
rts := make(map[string][]types.Route)
for r := range Iter {
rts[r.ProviderName()] = append(rts[r.ProviderName()], r)
}

View File

@@ -1,69 +0,0 @@
package routes
import (
"net/http"
"github.com/yusing/go-proxy/agent/pkg/agent"
"github.com/yusing/go-proxy/internal/docker"
"github.com/yusing/go-proxy/internal/homepage"
idlewatcher "github.com/yusing/go-proxy/internal/idlewatcher/types"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/utils/pool"
"github.com/yusing/go-proxy/internal/watcher/health"
loadbalance "github.com/yusing/go-proxy/internal/net/gphttp/loadbalancer/types"
"github.com/yusing/go-proxy/internal/net/gphttp/reverseproxy"
nettypes "github.com/yusing/go-proxy/internal/net/types"
)
type (
//nolint:interfacebloat // this is for avoiding circular imports
Route interface {
task.TaskStarter
task.TaskFinisher
pool.Object
ProviderName() string
GetProvider() Provider
TargetURL() *nettypes.URL
HealthMonitor() health.HealthMonitor
SetHealthMonitor(m health.HealthMonitor)
References() []string
Started() <-chan struct{}
IdlewatcherConfig() *idlewatcher.Config
HealthCheckConfig() *health.HealthCheckConfig
LoadBalanceConfig() *loadbalance.Config
HomepageConfig() *homepage.ItemConfig
HomepageItem() *homepage.Item
ContainerInfo() *docker.Container
GetAgent() *agent.AgentConfig
IsDocker() bool
IsAgent() bool
UseLoadBalance() bool
UseIdleWatcher() bool
UseHealthCheck() bool
UseAccessLog() bool
}
HTTPRoute interface {
Route
http.Handler
}
ReverseProxyRoute interface {
HTTPRoute
ReverseProxy() *reverseproxy.ReverseProxy
}
StreamRoute interface {
Route
nettypes.Stream
Stream() nettypes.Stream
}
Provider interface {
GetRoute(alias string) (r Route, ok bool)
IterRoutes(yield func(alias string, r Route) bool)
FindService(project, service string) (r Route, ok bool)
ShortName() string
}
)

View File

@@ -1,21 +1,22 @@
package routes
import (
"github.com/yusing/go-proxy/internal/types"
"github.com/yusing/go-proxy/internal/utils/pool"
)
var (
HTTP = pool.New[HTTPRoute]("http_routes")
Stream = pool.New[StreamRoute]("stream_routes")
HTTP = pool.New[types.HTTPRoute]("http_routes")
Stream = pool.New[types.StreamRoute]("stream_routes")
// All is a pool of all routes, including HTTP, Stream routes and also excluded routes.
All = pool.New[Route]("all_routes")
All = pool.New[types.Route]("all_routes")
)
func init() {
All.DisableLog()
}
func Iter(yield func(r Route) bool) {
func Iter(yield func(r types.Route) bool) {
for _, r := range All.Iter {
if !yield(r) {
break
@@ -23,7 +24,7 @@ func Iter(yield func(r Route) bool) {
}
}
func IterKV(yield func(alias string, r Route) bool) {
func IterKV(yield func(alias string, r types.Route) bool) {
for k, r := range All.Iter {
if !yield(k, r) {
break
@@ -41,7 +42,7 @@ func Clear() {
All.Clear()
}
func GetHTTPRouteOrExact(alias, host string) (HTTPRoute, bool) {
func GetHTTPRouteOrExact(alias, host string) (types.HTTPRoute, bool) {
r, ok := HTTP.Get(alias)
if ok {
return r, true
@@ -50,6 +51,6 @@ func GetHTTPRouteOrExact(alias, host string) (HTTPRoute, bool) {
return HTTP.Get(host)
}
func Get(alias string) (Route, bool) {
func Get(alias string) (types.Route, bool) {
return All.Get(alias)
}

View File

@@ -13,6 +13,7 @@ import (
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/route/stream"
"github.com/yusing/go-proxy/internal/task"
"github.com/yusing/go-proxy/internal/types"
"github.com/yusing/go-proxy/internal/watcher/health/monitor"
)
@@ -24,7 +25,7 @@ type StreamRoute struct {
l zerolog.Logger
}
func NewStreamRoute(base *Route) (routes.Route, gperr.Error) {
func NewStreamRoute(base *Route) (types.Route, gperr.Error) {
// TODO: support non-coherent scheme
return &StreamRoute{
Route: base,

View File

@@ -6,6 +6,6 @@ import (
type HTTPConfig struct {
NoTLSVerify bool `json:"no_tls_verify,omitempty"`
ResponseHeaderTimeout time.Duration `json:"response_header_timeout,omitempty"`
ResponseHeaderTimeout time.Duration `json:"response_header_timeout,omitempty" swaggertype:"primitive,integer"`
DisableCompression bool `json:"disable_compression,omitempty"`
}