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"` Branding BrandingConfig `yaml:"branding"` } // 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"` } // BrandingConfig configures site branding and appearance type BrandingConfig struct { SiteName string `yaml:"site_name"` LogoURL string `yaml:"logo_url"` LogoWidth string `yaml:"logo_width"` LogoHeight string `yaml:"logo_height"` FaviconURL string `yaml:"favicon_url"` Description string `yaml:"description"` FooterText string `yaml:"footer_text"` SupportURL string `yaml:"support_url"` } // 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" } // Set branding defaults if config.Branding.SiteName == "" { config.Branding.SiteName = "BitTorrent Gateway" } if config.Branding.Description == "" { config.Branding.Description = "Decentralized file sharing gateway" } 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 }