enki b3204ea07a
Some checks are pending
CI Pipeline / Run Tests (push) Waiting to run
CI Pipeline / Lint Code (push) Waiting to run
CI Pipeline / Security Scan (push) Waiting to run
CI Pipeline / Build Docker Images (push) Blocked by required conditions
CI Pipeline / E2E Tests (push) Blocked by required conditions
first commit
2025-08-18 00:40:15 -07:00

294 lines
9.1 KiB
Go

package config
import (
"fmt"
"os"
"time"
"gopkg.in/yaml.v2"
)
// Config represents the unified configuration for all services
type Config struct {
Mode string `yaml:"mode"`
Gateway GatewayConfig `yaml:"gateway"`
BlossomServer BlossomServerConfig `yaml:"blossom_server"`
DHT DHTConfig `yaml:"dht"`
Storage StorageConfig `yaml:"storage"`
Blossom BlossomConfig `yaml:"blossom"`
Torrent TorrentConfig `yaml:"torrent"`
Tracker TrackerConfig `yaml:"tracker"`
Nostr NostrConfig `yaml:"nostr"`
Proxy ProxyConfig `yaml:"proxy"`
Admin AdminConfig `yaml:"admin"`
RateLimiting RateLimitingConfig `yaml:"rate_limiting"`
}
// GatewayConfig configures the HTTP API gateway
type GatewayConfig struct {
Enabled bool `yaml:"enabled"`
Port int `yaml:"port"`
MaxUploadSize string `yaml:"max_upload_size"`
}
// BlossomServerConfig configures the embedded Blossom server
type BlossomServerConfig struct {
Enabled bool `yaml:"enabled"`
Port int `yaml:"port"`
StoragePath string `yaml:"storage_path"`
MaxBlobSize string `yaml:"max_blob_size"`
RateLimit RateLimit `yaml:"rate_limit"`
}
// RateLimit configures rate limiting for the Blossom server
type RateLimit struct {
RequestsPerMinute int `yaml:"requests_per_minute"`
BurstSize int `yaml:"burst_size"`
}
// DHTConfig configures the DHT node
type DHTConfig struct {
Enabled bool `yaml:"enabled"`
Port int `yaml:"port"`
NodeID string `yaml:"node_id"` // auto-generate if empty
BootstrapSelf bool `yaml:"bootstrap_self"` // add self as bootstrap node
BootstrapNodes []string `yaml:"bootstrap_nodes"`
AnnounceInterval time.Duration `yaml:"announce_interval"` // torrent announce interval
CleanupInterval time.Duration `yaml:"cleanup_interval"` // node cleanup interval
MaxTorrents int `yaml:"max_torrents"` // max torrents to track
MaxNodes int `yaml:"max_nodes"` // max nodes to store
MaxPeersPerTorrent int `yaml:"max_peers_per_torrent"`
}
// StorageConfig configures shared storage settings
type StorageConfig struct {
BlobThreshold int64 `yaml:"blob_threshold"`
ChunkSize int64 `yaml:"chunk_size"`
MetadataDB string `yaml:"metadata_db"`
BlobStorage string `yaml:"blob_storage"`
ChunkStorage string `yaml:"chunk_storage"`
Strategy StorageStrategy `yaml:"strategy"`
}
// StorageStrategy defines how files should be stored based on size
type StorageStrategy struct {
SmallFiles string `yaml:"small_files"` // "blob"
LargeFiles string `yaml:"large_files"` // "torrent"
}
// BlossomConfig configures external Blossom servers
type BlossomConfig struct {
Servers []string `yaml:"servers"`
}
// TorrentConfig configures BitTorrent settings
type TorrentConfig struct {
Trackers []string `yaml:"trackers"`
}
// TrackerConfig configures the built-in BitTorrent tracker
type TrackerConfig struct {
Enabled bool `yaml:"enabled"`
AnnounceInterval int `yaml:"announce_interval"` // seconds
MinInterval int `yaml:"min_interval"` // seconds
DefaultNumWant int `yaml:"default_numwant"` // peers to return
MaxNumWant int `yaml:"max_numwant"` // maximum peers
CleanupInterval time.Duration `yaml:"cleanup_interval"` // cleanup frequency
PeerTimeout time.Duration `yaml:"peer_timeout"` // peer expiration
}
// NostrConfig configures Nostr relay settings
type NostrConfig struct {
Relays []string `yaml:"relays"`
}
// ProxyConfig configures smart proxy settings
type ProxyConfig struct {
Enabled bool `yaml:"enabled"`
CacheSize int `yaml:"cache_size"`
CacheMaxAge time.Duration `yaml:"cache_max_age"`
}
// AdminConfig configures admin functionality
type AdminConfig struct {
Enabled bool `yaml:"enabled"`
Pubkeys []string `yaml:"pubkeys"`
AutoCleanup bool `yaml:"auto_cleanup"`
CleanupAge string `yaml:"cleanup_age"`
MaxFileAge string `yaml:"max_file_age"`
ReportThreshold int `yaml:"report_threshold"`
DefaultUserStorageLimit string `yaml:"default_user_storage_limit"`
}
// RateLimitingConfig configures rate limiting for different operations
type RateLimitingConfig struct {
Upload UploadRateConfig `yaml:"upload"`
Download DownloadRateConfig `yaml:"download"`
Stream StreamRateConfig `yaml:"stream"`
Auth AuthRateConfig `yaml:"auth"`
}
// UploadRateConfig configures upload rate limiting
type UploadRateConfig struct {
RequestsPerSecond float64 `yaml:"requests_per_second"`
BurstSize int `yaml:"burst_size"`
MaxFileSize string `yaml:"max_file_size"`
}
// DownloadRateConfig configures download rate limiting
type DownloadRateConfig struct {
RequestsPerSecond float64 `yaml:"requests_per_second"`
BurstSize int `yaml:"burst_size"`
}
// StreamRateConfig configures streaming rate limiting
type StreamRateConfig struct {
RequestsPerSecond float64 `yaml:"requests_per_second"`
BurstSize int `yaml:"burst_size"`
MaxConcurrent int `yaml:"max_concurrent"`
}
// AuthRateConfig configures authentication rate limiting
type AuthRateConfig struct {
LoginAttemptsPerMinute int `yaml:"login_attempts_per_minute"`
BurstSize int `yaml:"burst_size"`
}
// LoadConfig loads configuration from a YAML file
func LoadConfig(filename string) (*Config, error) {
data, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("failed to read config file %s: %w", filename, err)
}
var config Config
if err := yaml.Unmarshal(data, &config); err != nil {
return nil, fmt.Errorf("failed to parse config file %s: %w", filename, err)
}
// Set defaults
if config.Mode == "" {
config.Mode = "unified"
}
return &config, nil
}
// IsServiceEnabled checks if a specific service should be enabled based on mode
func (c *Config) IsServiceEnabled(service string) bool {
switch c.Mode {
case "unified":
switch service {
case "gateway":
return c.Gateway.Enabled
case "blossom":
return c.BlossomServer.Enabled
case "dht":
return c.DHT.Enabled
case "tracker":
return c.Tracker.Enabled
}
case "gateway-only":
return service == "gateway" && c.Gateway.Enabled
case "blossom-only":
return service == "blossom" && c.BlossomServer.Enabled
case "dht-only":
return service == "dht" && c.DHT.Enabled
}
return false
}
// GetBlobThreshold returns the blob threshold in bytes
func (c *Config) GetBlobThreshold() int64 {
return c.Storage.BlobThreshold
}
// GetChunkSize returns the chunk size in bytes
func (c *Config) GetChunkSize() int64 {
return c.Storage.ChunkSize
}
// GetMaxBlobSizeBytes converts the max blob size string to bytes
func (c *Config) GetMaxBlobSizeBytes() (int64, error) {
return parseSize(c.BlossomServer.MaxBlobSize)
}
// GetMaxUploadSizeBytes converts the max upload size string to bytes
func (c *Config) GetMaxUploadSizeBytes() (int64, error) {
return parseSize(c.Gateway.MaxUploadSize)
}
// GetDefaultUserStorageLimitBytes converts the default user storage limit to bytes
func (c *Config) GetDefaultUserStorageLimitBytes() (int64, error) {
if c.Admin.DefaultUserStorageLimit == "" {
return 10 * 1024 * 1024 * 1024, nil // 10GB default
}
return parseSize(c.Admin.DefaultUserStorageLimit)
}
// parseSize parses size strings like "2MB", "100MB", "10GB"
func parseSize(sizeStr string) (int64, error) {
if sizeStr == "" {
return 0, fmt.Errorf("empty size string")
}
var size int64
var unit string
n, err := fmt.Sscanf(sizeStr, "%d%s", &size, &unit)
if err != nil || n != 2 {
return 0, fmt.Errorf("invalid size format: %s", sizeStr)
}
switch unit {
case "B", "b":
return size, nil
case "KB", "kb", "K", "k":
return size * 1024, nil
case "MB", "mb", "M", "m":
return size * 1024 * 1024, nil
case "GB", "gb", "G", "g":
return size * 1024 * 1024 * 1024, nil
case "TB", "tb", "T", "t":
return size * 1024 * 1024 * 1024 * 1024, nil
default:
return 0, fmt.Errorf("unknown unit: %s", unit)
}
}
// GetRateLimitValues returns rate limiting values for middleware
func (c *Config) GetRateLimitValues() (float64, int, float64, int, float64, int) {
upload := c.RateLimiting.Upload
download := c.RateLimiting.Download
stream := c.RateLimiting.Stream
// Provide defaults if not configured
uploadRate := upload.RequestsPerSecond
if uploadRate <= 0 {
uploadRate = 1.0
}
uploadBurst := upload.BurstSize
if uploadBurst <= 0 {
uploadBurst = 5
}
downloadRate := download.RequestsPerSecond
if downloadRate <= 0 {
downloadRate = 50.0
}
downloadBurst := download.BurstSize
if downloadBurst <= 0 {
downloadBurst = 100
}
streamRate := stream.RequestsPerSecond
if streamRate <= 0 {
streamRate = 10.0
}
streamBurst := stream.BurstSize
if streamBurst <= 0 {
streamBurst = 20
}
return uploadRate, uploadBurst, downloadRate, downloadBurst, streamRate, streamBurst
}