Initial commit: Open sourcing all of the Maple Open Technologies code.

This commit is contained in:
Bartlomiej Mika 2025-12-02 14:33:08 -05:00
commit 755d54a99d
2010 changed files with 448675 additions and 0 deletions

View file

@ -0,0 +1,116 @@
package scheduler
import (
"context"
"time"
"github.com/robfig/cron/v3"
"go.uber.org/zap"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/leaderelection"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/service/ipcleanup"
)
// IPCleanupScheduler handles scheduled IP address cleanup for GDPR compliance
// CWE-359: IP addresses must be deleted after 90 days
type IPCleanupScheduler struct {
cron *cron.Cron
cleanupService *ipcleanup.CleanupService
leaderElection leaderelection.LeaderElection
logger *zap.Logger
enabled bool
schedulePattern string
}
// ProvideIPCleanupScheduler creates a new IPCleanupScheduler from config
func ProvideIPCleanupScheduler(
cfg *config.Config,
cleanupService *ipcleanup.CleanupService,
leaderElection leaderelection.LeaderElection,
logger *zap.Logger,
) *IPCleanupScheduler {
// IP cleanup enabled if configured (defaults to true for GDPR compliance)
enabled := cfg.Scheduler.IPCleanupEnabled
// Default: run daily at 2 AM
schedulePattern := cfg.Scheduler.IPCleanupSchedule
// Create cron with logger
cronLog := &cronLogger{logger: logger.Named("cron")}
c := cron.New(
cron.WithLogger(cronLog),
cron.WithChain(
cron.Recover(cronLog),
),
)
return &IPCleanupScheduler{
cron: c,
cleanupService: cleanupService,
leaderElection: leaderElection,
logger: logger.Named("ip-cleanup-scheduler"),
enabled: enabled,
schedulePattern: schedulePattern,
}
}
// Start starts the IP cleanup scheduler
func (s *IPCleanupScheduler) Start() error {
if !s.enabled {
s.logger.Info("IP cleanup scheduler is disabled")
return nil
}
s.logger.Info("starting IP cleanup scheduler for GDPR compliance",
zap.String("schedule", s.schedulePattern),
zap.String("retention_period", "90 days"))
// Schedule the IP cleanup job
_, err := s.cron.AddFunc(s.schedulePattern, s.cleanupIPs)
if err != nil {
s.logger.Error("failed to schedule IP cleanup job", zap.Error(err))
return err
}
// Start the cron scheduler
s.cron.Start()
s.logger.Info("IP cleanup scheduler started successfully")
return nil
}
// Stop stops the IP cleanup scheduler
func (s *IPCleanupScheduler) Stop() {
if !s.enabled {
return
}
s.logger.Info("stopping IP cleanup scheduler")
ctx := s.cron.Stop()
<-ctx.Done()
s.logger.Info("IP cleanup scheduler stopped")
}
// cleanupIPs is the cron job function that cleans up expired IP addresses
func (s *IPCleanupScheduler) cleanupIPs() {
// Only execute if this instance is the leader
if !s.leaderElection.IsLeader() {
s.logger.Debug("skipping IP cleanup - not the leader instance",
zap.String("instance_id", s.leaderElection.GetInstanceID()))
return
}
s.logger.Info("executing scheduled IP cleanup for GDPR compliance as leader instance",
zap.String("instance_id", s.leaderElection.GetInstanceID()))
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
err := s.cleanupService.CleanupExpiredIPs(ctx)
if err != nil {
s.logger.Error("IP cleanup failed", zap.Error(err))
return
}
s.logger.Info("IP cleanup completed successfully")
}

View file

@ -0,0 +1,129 @@
package scheduler
import (
"context"
"time"
"github.com/robfig/cron/v3"
"go.uber.org/zap"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/config"
"codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/pkg/leaderelection"
siteusecase "codeberg.org/mapleopentech/monorepo/cloud/maplepress-backend/internal/usecase/site"
)
// QuotaResetScheduler handles scheduled usage resets for billing cycles
type QuotaResetScheduler struct {
cron *cron.Cron
resetUsageUC *siteusecase.ResetMonthlyUsageUseCase
leaderElection leaderelection.LeaderElection
logger *zap.Logger
enabled bool
schedulePattern string
}
// cronLogger is a simple adapter for cron to use zap logger
type cronLogger struct {
logger *zap.Logger
}
func (l *cronLogger) Info(msg string, keysAndValues ...interface{}) {
l.logger.Sugar().Infow(msg, keysAndValues...)
}
func (l *cronLogger) Error(err error, msg string, keysAndValues ...interface{}) {
l.logger.Sugar().Errorw(msg, append(keysAndValues, "error", err)...)
}
// ProvideQuotaResetScheduler creates a new QuotaResetScheduler from config
func ProvideQuotaResetScheduler(
cfg *config.Config,
resetUsageUC *siteusecase.ResetMonthlyUsageUseCase,
leaderElection leaderelection.LeaderElection,
logger *zap.Logger,
) *QuotaResetScheduler {
enabled := cfg.Scheduler.QuotaResetEnabled
schedulePattern := cfg.Scheduler.QuotaResetSchedule
// Create cron with logger
cronLog := &cronLogger{logger: logger.Named("cron")}
c := cron.New(
cron.WithLogger(cronLog),
cron.WithChain(
cron.Recover(cronLog),
),
)
return &QuotaResetScheduler{
cron: c,
resetUsageUC: resetUsageUC,
leaderElection: leaderElection,
logger: logger.Named("usage-reset-scheduler"),
enabled: enabled,
schedulePattern: schedulePattern,
}
}
// Start starts the quota reset scheduler
func (s *QuotaResetScheduler) Start() error {
if !s.enabled {
s.logger.Info("quota reset scheduler is disabled")
return nil
}
s.logger.Info("starting quota reset scheduler",
zap.String("schedule", s.schedulePattern))
// Schedule the quota reset job
_, err := s.cron.AddFunc(s.schedulePattern, s.resetQuotas)
if err != nil {
s.logger.Error("failed to schedule quota reset job", zap.Error(err))
return err
}
// Start the cron scheduler
s.cron.Start()
s.logger.Info("quota reset scheduler started successfully")
return nil
}
// Stop stops the quota reset scheduler
func (s *QuotaResetScheduler) Stop() {
if !s.enabled {
return
}
s.logger.Info("stopping quota reset scheduler")
ctx := s.cron.Stop()
<-ctx.Done()
s.logger.Info("quota reset scheduler stopped")
}
// resetQuotas is the cron job function that resets monthly usage counters
func (s *QuotaResetScheduler) resetQuotas() {
// Only execute if this instance is the leader
if !s.leaderElection.IsLeader() {
s.logger.Debug("skipping quota reset - not the leader instance",
zap.String("instance_id", s.leaderElection.GetInstanceID()))
return
}
s.logger.Info("executing scheduled usage reset as leader instance",
zap.String("instance_id", s.leaderElection.GetInstanceID()))
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
output, err := s.resetUsageUC.Execute(ctx)
if err != nil {
s.logger.Error("usage reset failed", zap.Error(err))
return
}
s.logger.Info("usage reset completed",
zap.Int("processed_sites", output.ProcessedSites),
zap.Int("reset_count", output.ResetCount),
zap.Int("failed_count", output.FailedCount),
zap.Time("processed_at", output.ProcessedAt))
}