change to route based approach

This commit is contained in:
2025-05-10 00:01:02 +00:00
parent 552f4c246b
commit 28022ebe87
13 changed files with 3594 additions and 1167 deletions

View File

@ -1,4 +1,4 @@
# SmartProxy Fully Unified Configuration Plan
# SmartProxy Fully Unified Configuration Plan (Updated)
## Project Goal
Redesign SmartProxy's configuration for a more elegant, unified, and comprehensible approach by:
@ -6,6 +6,7 @@ Redesign SmartProxy's configuration for a more elegant, unified, and comprehensi
2. Eliminating the confusion between domain configs and port forwarding
3. Providing a clear, declarative API that makes the intent obvious
4. Enhancing maintainability and extensibility for future features
5. Completely removing legacy code to eliminate technical debt
## Current Issues
@ -132,177 +133,14 @@ interface ISmartProxyOptions {
}
```
### Example Configuration
```typescript
const proxy = new SmartProxy({
// All routing is configured in a single array
routes: [
// Basic HTTPS server with automatic certificates
{
match: {
ports: 443,
domains: ['example.com', '*.example.com']
},
action: {
type: 'forward',
target: {
host: 'localhost',
port: 8080
},
tls: {
mode: 'terminate',
certificate: 'auto' // Use ACME
}
},
name: 'Main HTTPS Server'
},
// HTTP to HTTPS redirect
{
match: {
ports: 80,
domains: ['example.com', '*.example.com']
},
action: {
type: 'redirect',
redirect: {
to: 'https://{domain}{path}',
status: 301
}
},
name: 'HTTP to HTTPS Redirect'
},
// Admin portal with IP restriction
{
match: {
ports: 8443,
domains: 'admin.example.com'
},
action: {
type: 'forward',
target: {
host: 'admin-backend',
port: 3000
},
tls: {
mode: 'terminate',
certificate: 'auto'
},
security: {
allowedIps: ['192.168.1.*', '10.0.0.*'],
maxConnections: 10
}
},
priority: 100, // Higher priority than default rules
name: 'Admin Portal'
},
// Port range for direct forwarding
{
match: {
ports: [{ from: 10000, to: 10010 }],
// No domains = all domains or direct IP
},
action: {
type: 'forward',
target: {
host: 'backend-server',
port: 10000,
preservePort: true // Use same port number as incoming
},
tls: {
mode: 'passthrough' // Direct TCP forwarding
}
},
name: 'Dynamic Port Range'
},
// Path-based routing
{
match: {
ports: 443,
domains: 'api.example.com',
path: '/v1/*'
},
action: {
type: 'forward',
target: {
host: 'api-v1-service',
port: 8001
},
tls: {
mode: 'terminate'
}
},
name: 'API v1 Endpoints'
},
// Load balanced backend
{
match: {
ports: 443,
domains: 'app.example.com'
},
action: {
type: 'forward',
target: {
// Round-robin load balancing
host: [
'app-server-1',
'app-server-2',
'app-server-3'
],
port: 8080
},
tls: {
mode: 'terminate'
},
advanced: {
headers: {
'X-Served-By': '{server}',
'X-Client-IP': '{clientIp}'
}
}
},
name: 'Load Balanced App Servers'
}
],
// Global defaults
defaults: {
target: {
host: 'localhost',
port: 8080
},
security: {
maxConnections: 1000,
// Global security defaults
}
},
// ACME configuration for auto certificates
acme: {
enabled: true,
email: 'admin@example.com',
production: true,
renewThresholdDays: 30
},
// Other global settings
// ...
});
```
## Implementation Plan
## Revised Implementation Plan
### Phase 1: Core Design & Interface Definition
1. **Define New Core Interfaces**:
- Create `IRouteConfig` interface with `match` and `action` branches
- Define all sub-interfaces for matching and actions
- Update `ISmartProxyOptions` to use `routes` array
- Create new `ISmartProxyOptions` to use `routes` array exclusively
- Define template variable system for dynamic values
2. **Create Helper Functions**:
@ -319,78 +157,56 @@ const proxy = new SmartProxy({
### Phase 2: Core Implementation
1. **Create RouteManager**:
- Replaces both PortRangeManager and DomainConfigManager
- Handles all routing decisions in one place
- Provides fast lookup from port+domain+path to action
- Manages server instances for different ports
- Build a new RouteManager to replace both PortRangeManager and DomainConfigManager
- Implement port and domain matching in one unified system
- Create efficient route lookup algorithms
2. **Update ConnectionHandler**:
- Simplify to work with the unified route system
- Implement templating system for dynamic values
- Support more sophisticated routing rules
2. **Implement New ConnectionHandler**:
- Create a new ConnectionHandler built from scratch for routes
- Implement the routing logic with the new match/action pattern
- Support template processing for headers and other dynamic values
3. **Implement New SmartProxy Core**:
- Rewrite initialization to use route-based configuration
- Create network servers based on port specifications
- Create new SmartProxy implementation using routes exclusively
- Build network servers based on port specifications
- Manage TLS contexts and certificates
### Phase 3: Feature Implementation
### Phase 3: Legacy Code Removal
1. **Path-Based Routing**:
- Implement HTTP path matching
- Add wildcard and regex support for paths
- Create route differentiation based on HTTP method
1. **Identify Legacy Components**:
- Create an inventory of all files and components to be removed
- Document dependencies between legacy components
- Create a removal plan that minimizes disruption
2. **Enhanced Security**:
- Implement per-route security rules
- Add authentication methods (basic, digest, etc.)
- Support for IP-based access control
2. **Remove Legacy Components**:
- Remove PortRangeManager and related code
- Remove DomainConfigManager and related code
- Remove old ConnectionHandler implementation
- Remove other legacy components
3. **TLS Management**:
- Support multiple certificate types (auto, manual, wildcard)
- Implement certificate selection based on SNI
- Support different TLS modes per route
3. **Clean Interface Adaptations**:
- Remove all legacy interfaces and types
- Update type exports to only expose route-based interfaces
- Remove any adapter or backward compatibility code
4. **Metrics & Monitoring**:
- Per-route statistics
- Named route tracking for better visibility
- Tag-based grouping of metrics
### Phase 4: Backward Compatibility
1. **Legacy Adapter Layer**:
- Convert old configuration format to route-based format
- Map fromPort/toPort/domainConfigs to unified routes
- Preserve all functionality during migration
2. **API Compatibility**:
- Support both old and new configuration methods
- Add deprecation warnings when using legacy properties
- Provide migration utilities
3. **Documentation**:
- Clear migration guide for existing users
- Examples mapping old config to new config
- Timeline for deprecation
### Phase 5: Documentation & Examples
### Phase 4: Updated Documentation & Examples
1. **Update Core Documentation**:
- Rewrite README.md with a focus on route-based configuration
- Rewrite README.md with a focus on route-based configuration exclusively
- Create interface reference documentation
- Document all template variables
2. **Create Example Library**:
- Common configuration patterns
- Common configuration patterns using the new API
- Complex use cases for advanced features
- Infrastructure-as-code examples
3. **Add Validation Tooling**:
3. **Add Validation Tools**:
- Configuration validator to check for issues
- Schema definitions for IDE autocomplete
- Runtime validation helpers
### Phase 6: Testing
### Phase 5: Testing
1. **Unit Tests**:
- Test route matching logic
@ -398,378 +214,103 @@ const proxy = new SmartProxy({
- Test template processing
2. **Integration Tests**:
- Verify full proxy flows
- Verify full proxy flows with the new system
- Test complex routing scenarios
- Check backward compatibility
- Ensure all features work as expected
3. **Performance Testing**:
- Benchmark routing performance
- Evaluate memory usage
- Test with large numbers of routes
## Benefits of the New Approach
1. **Truly Unified Configuration**:
- One "source of truth" for all routing
- Entire routing flow visible in a single configuration
- No overlapping or conflicting configuration systems
2. **Declarative Intent**:
- Configuration clearly states what to match and what action to take
- Metadata provides context and documentation inline
- Easy to understand the purpose of each route
3. **Advanced Routing Capabilities**:
- Path-based routing with pattern matching
- Client IP-based conditional routing
- Fine-grained security controls
4. **Composable and Extensible**:
- Each route is a self-contained unit of configuration
- Routes can be grouped by tags or priority
- New match criteria or actions can be added without breaking changes
5. **Better Developer Experience**:
- Clear, consistent configuration pattern
- Helper functions for common scenarios
- Better error messages and validation
## Example Use Cases
### 1. Complete Reverse Proxy with Auto SSL
```typescript
const proxy = new SmartProxy({
routes: [
// HTTPS server for all domains
{
match: { ports: 443 },
action: {
type: 'forward',
target: { host: 'localhost', port: 8080 },
tls: { mode: 'terminate', certificate: 'auto' }
}
},
// HTTP to HTTPS redirect
{
match: { ports: 80 },
action: {
type: 'redirect',
redirect: { to: 'https://{domain}{path}', status: 301 }
}
}
],
acme: {
enabled: true,
email: 'admin@example.com',
production: true
}
});
```
### 2. Microservices API Gateway
```typescript
const apiGateway = new SmartProxy({
routes: [
// Users API
{
match: {
ports: 443,
domains: 'api.example.com',
path: '/users/*'
},
action: {
type: 'forward',
target: { host: 'users-service', port: 8001 },
tls: { mode: 'terminate', certificate: 'auto' }
},
name: 'Users Service'
},
// Products API
{
match: {
ports: 443,
domains: 'api.example.com',
path: '/products/*'
},
action: {
type: 'forward',
target: { host: 'products-service', port: 8002 },
tls: { mode: 'terminate', certificate: 'auto' }
},
name: 'Products Service'
},
// Orders API with authentication
{
match: {
ports: 443,
domains: 'api.example.com',
path: '/orders/*'
},
action: {
type: 'forward',
target: { host: 'orders-service', port: 8003 },
tls: { mode: 'terminate', certificate: 'auto' },
security: {
authentication: {
type: 'basic',
users: { 'admin': 'password' }
}
}
},
name: 'Orders Service (Protected)'
}
],
acme: {
enabled: true,
email: 'admin@example.com'
}
});
```
### 3. Multi-Environment Setup
```typescript
const environments = {
production: {
target: { host: 'prod-backend', port: 8080 },
security: { maxConnections: 1000 }
},
staging: {
target: { host: 'staging-backend', port: 8080 },
security: {
allowedIps: ['10.0.0.*', '192.168.1.*'],
maxConnections: 100
}
},
development: {
target: { host: 'localhost', port: 3000 },
security: {
allowedIps: ['127.0.0.1'],
maxConnections: 10
}
}
};
// Select environment based on hostname
const proxy = new SmartProxy({
routes: [
// Production environment
{
match: {
ports: [80, 443],
domains: ['app.example.com', 'www.example.com']
},
action: {
type: 'forward',
target: environments.production.target,
tls: { mode: 'terminate', certificate: 'auto' },
security: environments.production.security
},
name: 'Production Environment'
},
// Staging environment
{
match: {
ports: [80, 443],
domains: 'staging.example.com'
},
action: {
type: 'forward',
target: environments.staging.target,
tls: { mode: 'terminate', certificate: 'auto' },
security: environments.staging.security
},
name: 'Staging Environment'
},
// Development environment
{
match: {
ports: [80, 443],
domains: 'dev.example.com'
},
action: {
type: 'forward',
target: environments.development.target,
tls: { mode: 'terminate', certificate: 'auto' },
security: environments.development.security
},
name: 'Development Environment'
}
],
acme: { enabled: true, email: 'admin@example.com' }
});
```
## Implementation Strategy
### Code Organization
1. **New Files**:
- `route-manager.ts` (core routing engine)
- `route-types.ts` (interface definitions)
- `route-helpers.ts` (helper functions)
- `route-matcher.ts` (matching logic)
- `template-engine.ts` (for variable substitution)
- `route-config.ts` - Core route interfaces
- `route-manager.ts` - Route matching and management
- `route-connection-handler.ts` - Connection handling with routes
- `route-smart-proxy.ts` - Main SmartProxy implementation
- `template-engine.ts` - For variable substitution
2. **Modified Files**:
- `smart-proxy.ts` (update to use route-based configuration)
- `connection-handler.ts` (simplify using route-based approach)
- Replace `port-range-manager.ts` and `domain-config-manager.ts`
2. **File Removal**:
- Remove `port-range-manager.ts`
- Remove `domain-config-manager.ts`
- Remove legacy interfaces and adapter code
- Remove backward compatibility shims
### Backward Compatibility
### Transition Strategy
The backward compatibility layer will convert the legacy configuration to the new format:
1. **Breaking Change Approach**:
- This will be a major version update with breaking changes
- No backward compatibility will be maintained
- Clear migration documentation will guide users to the new API
```typescript
function convertLegacyConfig(legacy: ILegacySmartProxyOptions): ISmartProxyOptions {
const routes: IRouteConfig[] = [];
// Convert main port configuration
if (legacy.fromPort) {
// Add main listener for fromPort
routes.push({
match: { ports: legacy.fromPort },
action: {
type: 'forward',
target: { host: legacy.targetIP || 'localhost', port: legacy.toPort },
tls: { mode: legacy.sniEnabled ? 'passthrough' : 'terminate' }
},
name: 'Main Listener (Legacy)'
});
// If ACME is enabled, add HTTP listener for challenges
if (legacy.acme?.enabled) {
routes.push({
match: { ports: 80 },
action: {
type: 'forward',
target: { host: 'localhost', port: 80 },
// Special flag for ACME handler
acmeEnabled: true
},
name: 'ACME Challenge Handler (Legacy)'
});
}
}
// Convert domain configs
if (legacy.domainConfigs) {
for (const domainConfig of legacy.domainConfigs) {
const { domains, forwarding } = domainConfig;
// Determine action based on forwarding type
let action: Partial<IRouteAction> = {
type: 'forward',
target: {
host: forwarding.target.host,
port: forwarding.target.port
}
};
// Set TLS mode based on forwarding type
switch (forwarding.type) {
case 'http-only':
// No TLS
break;
case 'https-passthrough':
action.tls = { mode: 'passthrough' };
break;
case 'https-terminate-to-http':
action.tls = {
mode: 'terminate',
certificate: forwarding.https?.customCert || 'auto'
};
break;
case 'https-terminate-to-https':
action.tls = {
mode: 'terminate-and-reencrypt',
certificate: forwarding.https?.customCert || 'auto'
};
break;
}
// Security settings
if (forwarding.security) {
action.security = forwarding.security;
}
// Add HTTP redirect if needed
if (forwarding.http?.redirectToHttps) {
routes.push({
match: { ports: 80, domains },
action: {
type: 'redirect',
redirect: { to: 'https://{domain}{path}', status: 301 }
},
name: `HTTP Redirect for ${domains.join(', ')} (Legacy)`
});
}
// Add main route
routes.push({
match: {
ports: forwarding.type.startsWith('https') ? 443 : 80,
domains
},
action: action as IRouteAction,
name: `Route for ${domains.join(', ')} (Legacy)`
});
// Add port ranges if specified
if (forwarding.advanced?.portRanges) {
for (const range of forwarding.advanced.portRanges) {
routes.push({
match: {
ports: { from: range.from, to: range.to },
domains
},
action: action as IRouteAction,
name: `Port Range ${range.from}-${range.to} for ${domains.join(', ')} (Legacy)`
});
}
}
}
}
// Global port ranges
if (legacy.globalPortRanges) {
for (const range of legacy.globalPortRanges) {
routes.push({
match: { ports: { from: range.from, to: range.to } },
action: {
type: 'forward',
target: {
host: legacy.targetIP || 'localhost',
port: legacy.forwardAllGlobalRanges ? 0 : legacy.toPort,
preservePort: !!legacy.forwardAllGlobalRanges
},
tls: { mode: 'passthrough' }
},
name: `Global Port Range ${range.from}-${range.to} (Legacy)`
});
}
}
return {
routes,
defaults: {
target: {
host: legacy.targetIP || 'localhost',
port: legacy.toPort
}
},
acme: legacy.acme
};
}
```
2. **Package Structure**:
- `@push.rocks/smartproxy` package will be updated to v14.0.0
- Legacy code fully removed, only route-based API exposed
- Support documentation provided for migration
## Success Criteria
3. **Migration Documentation**:
- Provide a migration guide with examples
- Show equivalent route configurations for common legacy patterns
- Offer code transformation helpers for complex setups
- All existing functionality works with the new route-based configuration
- Performance is equal or better than the current implementation
- Configuration is more intuitive and easier to understand
- New features can be added without breaking existing code
- Code is more maintainable with clear separation of concerns
- Migration from old configuration to new is straightforward
## Benefits of the Clean Approach
1. **Reduced Complexity**:
- No overlapping or conflicting configuration systems
- No dual maintenance of backward compatibility code
- Simplified internal architecture
2. **Cleaner Code Base**:
- Removal of technical debt
- Better separation of concerns
- More maintainable codebase
3. **Better User Experience**:
- Consistent, predictable API
- No confusing overlapping options
- Clear documentation of one approach, not two
4. **Future-Proof Design**:
- Easier to extend with new features
- Better performance without legacy overhead
- Cleaner foundation for future enhancements
## Migration Support
While we're removing backward compatibility from the codebase, we'll provide extensive migration support:
1. **Migration Guide**:
- Detailed documentation on moving from legacy to route-based config
- Pattern-matching examples for all common use cases
- Troubleshooting guide for common migration issues
2. **Conversion Tool**:
- Provide a standalone one-time conversion tool
- Takes legacy configuration and outputs route-based equivalents
- Will not be included in the main package to avoid bloat
3. **Version Policy**:
- Maintain the legacy version (13.x) for security updates
- Make the route-based version a clear major version change (14.0.0)
- Clearly communicate the breaking changes
## Timeline and Versioning
1. **Development**:
- Develop route-based implementation in a separate branch
- Complete full test coverage of new implementation
- Ensure documentation is complete
2. **Release**:
- Release as version 14.0.0
- Clearly mark as breaking change
- Provide migration guide at release time
3. **Support**:
- Offer extended support for migration questions
- Consider maintaining security updates for v13.x for 6 months
- Focus active development on route-based version only