Files
godoxy-yusing/internal/route/README.md

326 lines
7.8 KiB
Markdown

# 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
```go
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
}
```
```go
type Scheme string
const (
SchemeHTTP Scheme = "http"
SchemeHTTPS Scheme = "https"
SchemeH2C Scheme = "h2c"
SchemeTCP Scheme = "tcp"
SchemeUDP Scheme = "udp"
SchemeFileServer Scheme = "fileserver"
)
```
```go
type ExcludedReason int
const (
ExcludedReasonNone ExcludedReason = iota
ExcludedReasonError
ExcludedReasonManual
ExcludedReasonNoPortContainer
ExcludedReasonNoPortSpecified
ExcludedReasonBlacklisted
ExcludedReasonBuildx
ExcludedReasonOld
)
```
### Exported Functions/Methods
```go
// 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
```mermaid
classDiagram
class Route {
+Validate() gperr.Error
+Start(parent) gperr.Error
+Finish(reason)
+Started() &lt;-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
```mermaid
graph TD
Route --> HTTPRoute
Route --> StreamRoute
HTTPRoute --> ReverseProxyRoute
HTTPRoute --> FileServer
StreamRoute --> TCPStream
StreamRoute --> UDPStream
```
### Request Processing Pipeline
```mermaid
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
```mermaid
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
```go
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
```yaml
labels:
proxy.aliases: myapp
proxy.myapp.port: 3000
```
### YAML Configuration
```yaml
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_total`
- `health_check_failure_total`
- `health_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
```go
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
```go
route := &route.Route{
Alias: "myservice",
HealthCheck: types.HealthCheckConfig{
Path: "/health",
Interval: 30 * time.Second,
Timeout: 5 * time.Second,
},
}
```
### File Server Route
```go
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