mirror of
https://github.com/yusing/godoxy.git
synced 2026-02-22 10:27:46 +01:00
Decouple the types package from the internal/proxmox package by defining a standalone ProxmoxConfig struct. This reduces circular dependencies and allows the types package to define its own configuration structures without importing the proxmox package. The route validation logic now converts between types.ProxmoxConfig and proxmox.NodeConfig where needed for internal operations.
Route
Provides HTTP routing, reverse proxy, file serving, and TCP/UDP stream proxying for GoDoxy.
Overview
The internal/route package implements the core routing system for GoDoxy. It handles reverse proxying HTTP requests, serving static files, and proxying TCP/UDP streams. Routes can be discovered from Docker containers, YAML files, or remote agents.
Primary Consumers
- Route providers: Create and manage route instances
- HTTP server: Dispatches requests to route handlers
- Configuration layer: Validates and loads route configs
Non-goals
- Does not implement container runtime operations (delegates to providers)
- Does not handle authentication (delegates to middleware/rules)
- Does not manage health checks (delegates to
internal/health/monitor)
Stability
Internal package with stable core types. Route configuration schema is versioned.
Public API
Exported Types
type Route struct {
Alias string // Unique route identifier
Scheme Scheme // http, https, h2c, tcp, udp, fileserver
Host string // Virtual host
Port Port // Listen and target ports
// File serving
Root string // Document root
SPA bool // Single-page app mode
Index string // Index file
// Route rules and middleware
HTTPConfig
PathPatterns []string
Rules rules.Rules
RuleFile string
// Health and load balancing
HealthCheck types.HealthCheckConfig
LoadBalance *types.LoadBalancerConfig
// Additional features
Middlewares map[string]types.LabelMap
Homepage *homepage.ItemConfig
AccessLog *accesslog.RequestLoggerConfig
Agent string
Idlewatcher *types.IdlewatcherConfig
Metadata
}
type Scheme string
const (
SchemeHTTP Scheme = "http"
SchemeHTTPS Scheme = "https"
SchemeH2C Scheme = "h2c"
SchemeTCP Scheme = "tcp"
SchemeUDP Scheme = "udp"
SchemeFileServer Scheme = "fileserver"
)
type ExcludedReason int
const (
ExcludedReasonNone ExcludedReason = iota
ExcludedReasonError
ExcludedReasonManual
ExcludedReasonNoPortContainer
ExcludedReasonNoPortSpecified
ExcludedReasonBlacklisted
ExcludedReasonBuildx
ExcludedReasonOld
)
Exported Functions/Methods
// Validation and lifecycle
func (r *Route) Validate() gperr.Error
func (r *Route) Start(parent task.Parent) gperr.Error
func (r *Route) Finish(reason any)
func (r *Route) Started() <-chan struct{}
// Route queries
func (r *Route) Impl() types.Route
func (r *Route) Task() *task.Task
func (r *Route) ProviderName() string
func (r *Route) TargetURL() *nettypes.URL
func (r *Route) References() []string
// Status queries
func (r *Route) ShouldExclude() bool
func (r *Route) UseLoadBalance() bool
func (r *Route) UseIdleWatcher() bool
func (r *Route) UseHealthCheck() bool
Architecture
Core Components
classDiagram
class Route {
+Validate() gperr.Error
+Start(parent) gperr.Error
+Finish(reason)
+Started() <-chan struct#123;#125;
}
class Metadata {
+impl types.Route
+task *task.Task
+started chan struct#123;#125;
}
class HealthMonitor {
+Start(parent) error
+Healthy() bool
+URL() string
}
Route --> Metadata : contains
Route --> HealthMonitor : optional
Route Types
graph TD
Route --> HTTPRoute
Route --> StreamRoute
HTTPRoute --> ReverseProxyRoute
HTTPRoute --> FileServer
StreamRoute --> TCPStream
StreamRoute --> UDPStream
Request Processing Pipeline
flowchart LR
A[Request] --> B[Route Matching]
B --> C{Route Type}
C -->|HTTP| D[Middleware]
C -->|FileServer| E[File System]
C -->|Stream| F[TCP/UDP Proxy]
D --> G[Rules Engine]
G --> H[Upstream]
H --> I[Response]
E --> I
F --> I
Reverse Proxy Flow
sequenceDiagram
participant C as Client
participant P as Proxy
participant L as Load Balancer
participant B as Backend
C->>P: GET /
P->>L: Select Backend
L-->>P: Backend1
P->>B: Forward Request
B-->>P: 200 OK
P-->>C: Response
Configuration Surface
Route Configuration
type Route struct {
Alias string `json:"alias"`
Scheme Scheme `json:"scheme"`
Host string `json:"host,omitempty"`
Port Port `json:"port"`
Root string `json:"root,omitempty"`
SPA bool `json:"spa,omitempty"`
Index string `json:"index,omitempty"`
// ... additional fields
}
Docker Labels
labels:
proxy.aliases: myapp
proxy.myapp.port: 3000
YAML Configuration
routes:
myapp:
scheme: http
root: /var/www/myapp
spa: true
Dependency and Integration Map
| Dependency | Purpose |
|---|---|
internal/route/routes |
Route registry and lookup |
internal/route/rules |
Request/response rule processing |
internal/route/stream |
TCP/UDP stream proxying |
internal/route/provider |
Route discovery and loading |
internal/health/monitor |
Health checking |
internal/idlewatcher |
Idle container management |
internal/logging/accesslog |
Request logging |
internal/homepage |
Dashboard integration |
github.com/yusing/goutils/errs |
Error handling |
Observability
Logs
- INFO: Route start/stop, validation results
- DEBUG: Request processing details
- ERROR: Proxy failures, health check failures
Log context includes: alias, host, method, path, status
Metrics
Health check metrics via internal/health/monitor:
health_check_totalhealth_check_failure_totalhealth_check_duration_seconds
Security Considerations
- Route matching validates host and path patterns
- Upstream URL validation prevents SSRF attacks
- Rules engine can enforce authentication/authorization
- ACL integration available for IP-based access control
Failure Modes and Recovery
| Failure | Behavior | Recovery |
|---|---|---|
| Backend unavailable | Returns 502 error | Fix backend service |
| Health check fails | Route marked unhealthy | Fix backend health endpoint |
| Route validation fails | Route excluded with reason | Fix configuration |
| TLS handshake fails | Connection error | Fix certificates |
| Load balancer no backends | Returns 503 error | Add healthy backends |
Usage Examples
Creating a Basic HTTP Route
route := &route.Route{
Alias: "myapp",
Scheme: route.SchemeHTTP,
Host: "myapp.local",
Port: route.Port{Proxy: 8080, Target: 3000},
}
if err := route.Validate(); err != nil {
return err
}
if err := route.Start(parent); err != nil {
return err
}
Route with Health Check
route := &route.Route{
Alias: "myservice",
HealthCheck: types.HealthCheckConfig{
Path: "/health",
Interval: 30 * time.Second,
Timeout: 5 * time.Second,
},
}
File Server Route
route := &route.Route{
Alias: "files",
Scheme: route.SchemeFileServer,
Root: "/var/www/files",
SPA: false,
Index: "index.html",
}
Testing Notes
- Unit tests for validation logic
- Integration tests with real backends
- Mock health monitors for testing
- Route exclusion tests cover all reason codes