WitNote / internal /strategy /strategy.go
AUXteam's picture
Upload folder using huggingface_hub
6a7089a verified
// Package strategy defines the interface for pluggable allocation strategies.
// Strategies control how the dashboard routes requests to browser instances.
package strategy
import (
"context"
"fmt"
"net/http"
"sync"
"github.com/pinchtab/pinchtab/internal/config"
"github.com/pinchtab/pinchtab/internal/orchestrator"
)
// Orchestrator is the interface strategies need from the orchestrator.
// Avoids import cycles by depending on the interface, not the concrete type.
type Orchestrator interface {
RegisterHandlers(mux *http.ServeMux)
FirstRunningURL() string
}
// OrchestratorAware is implemented by strategies that need a reference to
// the concrete orchestrator. The dashboard checks for this interface after
// constructing a strategy and injects the orchestrator before Start().
type OrchestratorAware interface {
SetOrchestrator(o *orchestrator.Orchestrator)
}
// RuntimeConfigAware is implemented by strategies that need access to
// runtime configuration at construction time.
type RuntimeConfigAware interface {
SetRuntimeConfig(cfg *config.RuntimeConfig)
}
// Strategy defines a browser allocation approach.
type Strategy interface {
// Name returns the strategy identifier.
Name() string
// RegisterRoutes adds strategy-specific HTTP endpoints to the mux.
RegisterRoutes(mux *http.ServeMux)
// Start begins any background tasks.
Start(ctx context.Context) error
// Stop gracefully shuts down.
Stop() error
}
// Factory creates a new Strategy instance.
type Factory func() Strategy
var (
registry = make(map[string]Factory)
mu sync.RWMutex
)
// Register adds a strategy factory to the registry.
func Register(name string, factory Factory) error {
mu.Lock()
defer mu.Unlock()
if _, exists := registry[name]; exists {
return fmt.Errorf("strategy %q already registered", name)
}
registry[name] = factory
return nil
}
// MustRegister is like Register but panics on duplicate name.
func MustRegister(name string, factory Factory) {
if err := Register(name, factory); err != nil {
panic(err)
}
}
// New creates a strategy by name from the registry.
func New(name string) (Strategy, error) {
mu.RLock()
factory, ok := registry[name]
mu.RUnlock()
if !ok {
return nil, fmt.Errorf("unknown strategy: %s (available: %v)", name, Names())
}
return factory(), nil
}
// Names returns all registered strategy names.
func Names() []string {
mu.RLock()
defer mu.RUnlock()
names := make([]string, 0, len(registry))
for name := range registry {
names = append(names, name)
}
return names
}