refactor: reorganize struct fields, add new handlers and storage backends

- [x] Reorder struct fields across codebase for consistency
- [x] Add analytics event handlers and tests
- [x] Add authentication API key management handlers and tests
- [x] Add pre-warming control handlers and tests
- [x] Implement S3 storage backend with tests
- [x] Implement SMB/CIFS storage backend with tests
- [x] Add CDN middleware tests
- [x] Integrate analytics tracking into cache manager
- [x] Add S3 and SMB storage initialization in app setup
- [x] Add CDN caching to proxy handlers
- [x] Remove distributed locking (Redis lock manager)
- [x] Remove proxy common package and utilities
- [x] Remove standalone HTTP server package
- [x] Remove logger middleware
- [x] Simplify error handling utilities
- [x] Update config with S3 and SMB options
- [x] Update cache manager signature to include analytics
This commit is contained in:
2026-01-03 00:18:58 +00:00
parent 48b834a62a
commit 6b037a92b4
57 changed files with 2789 additions and 2276 deletions
+47 -14
View File
@@ -11,6 +11,7 @@ import (
"sync"
"time"
"github.com/lukaszraczylo/gohoarder/pkg/analytics"
"github.com/lukaszraczylo/gohoarder/pkg/errors"
"github.com/lukaszraczylo/gohoarder/pkg/metadata"
"github.com/lukaszraczylo/gohoarder/pkg/metrics"
@@ -27,15 +28,21 @@ type ScannerInterface interface {
CheckVulnerabilities(ctx context.Context, registry, packageName, version string) (blocked bool, reason string, err error)
}
// AnalyticsInterface defines the interface for analytics tracking
type AnalyticsInterface interface {
TrackDownload(download analytics.PackageDownload)
}
// Manager coordinates caching operations between storage and metadata
type Manager struct {
storage storage.StorageBackend
metadata metadata.MetadataStore
scanner ScannerInterface
config Config
sf singleflight.Group
mu sync.RWMutex
evicting bool
storage storage.StorageBackend
metadata metadata.MetadataStore
scanner ScannerInterface
analytics AnalyticsInterface
sf singleflight.Group
config Config
mu sync.RWMutex
evicting bool
}
// Config holds cache manager configuration
@@ -48,15 +55,15 @@ type Config struct {
// CacheEntry represents a cached package
type CacheEntry struct {
Package *metadata.Package
Data io.ReadCloser
FromCache bool
Package *metadata.Package
UpstreamURL string
CacheControl string
FromCache bool
}
// New creates a new cache manager
func New(storage storage.StorageBackend, metadata metadata.MetadataStore, scanner ScannerInterface, config Config) (*Manager, error) {
func New(storage storage.StorageBackend, metadata metadata.MetadataStore, scanner ScannerInterface, analytics AnalyticsInterface, config Config) (*Manager, error) {
if storage == nil {
return nil, errors.New(errors.ErrCodeInvalidConfig, "storage backend is required")
}
@@ -70,6 +77,11 @@ func New(storage storage.StorageBackend, metadata metadata.MetadataStore, scanne
log.Info().Msg("Cache manager initialized with security scanning enabled")
}
// Analytics is optional - can be nil if analytics tracking is disabled
if analytics != nil {
log.Info().Msg("Cache manager initialized with analytics tracking enabled")
}
if config.DefaultTTL == 0 {
config.DefaultTTL = 7 * 24 * time.Hour // 7 days default
}
@@ -87,10 +99,11 @@ func New(storage storage.StorageBackend, metadata metadata.MetadataStore, scanne
}
manager := &Manager{
storage: storage,
metadata: metadata,
scanner: scanner,
config: config,
storage: storage,
metadata: metadata,
scanner: scanner,
analytics: analytics,
config: config,
}
// Start background cleanup worker
@@ -134,6 +147,11 @@ func (m *Manager) getOrFetch(ctx context.Context, registry, name, version string
metrics.RecordCacheHit(registry)
_ = m.metadata.UpdateDownloadCount(ctx, registry, name, version) // #nosec G104 -- Async update, error logged
// Track download in analytics if enabled
if m.analytics != nil {
m.trackDownload(registry, name, version, pkg.Size)
}
// Check for vulnerabilities if scanner is enabled
if m.scanner != nil {
blocked, reason, err := m.scanner.CheckVulnerabilities(ctx, registry, name, version)
@@ -552,6 +570,21 @@ func (m *Manager) Health(ctx context.Context) error {
return nil
}
// trackDownload tracks a package download event in analytics
func (m *Manager) trackDownload(registry, name, version string, size int64) {
download := analytics.PackageDownload{
Registry: registry,
Name: name,
Version: version,
Timestamp: time.Now(),
BytesSize: size,
ClientIP: "", // TODO: Extract from context if available
UserAgent: "", // TODO: Extract from context if available
}
m.analytics.TrackDownload(download)
}
// Close closes the cache manager
func (m *Manager) Close() error {
var err error