package main import ( "context" "log/slog" "net/http" "os" "os/signal" "time" "github.com/bugsnag/bugsnag-go/v2" "github.com/joho/godotenv" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" "github.com/robfig/cron" ) type service struct { pdsHost string did string blobDir string bucketName string httpClient *http.Client minioClient *minio.Client } func main() { ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill) defer stop() envLocation := os.Getenv("ENV_LOCATION") if envLocation == "" { envLocation = ".env" } err := godotenv.Load(envLocation) if err != nil { if !os.IsNotExist(err) { slog.Error("load env", "error", err) return } } configureBugsnag() minioClient, err := createMinioClient() if err != nil { slog.Error("create minio client", "error", err) bugsnag.Notify(err) return } bucketName := os.Getenv("S3_BUCKET_NAME") err = minioClient.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{}) if err != nil { slog.Error("create bucket", "error", err) bugsnag.Notify(err) return } pdsHost := os.Getenv("PDS_HOST") did := os.Getenv("DID") blobDir := os.Getenv("BLOB_DIR") service := service{ pdsHost: pdsHost, did: did, blobDir: blobDir, bucketName: bucketName, minioClient: minioClient, httpClient: &http.Client{ Timeout: time.Second * 5, Transport: &http.Transport{ IdleConnTimeout: time.Second * 90, }, }, } service.backupPDS(ctx) service.backupTangledKnot(ctx) c := cron.New() c.AddFunc("@hourly", func() { service.backupPDS(ctx) }) c.AddFunc("@hourly", func() { service.backupTangledKnot(ctx) }) c.Start() defer c.Stop() <-ctx.Done() } func createMinioClient() (*minio.Client, error) { endpoint := os.Getenv("S3_ENDPOINT") accessKeyID := os.Getenv("S3_ACCESS_ID") secretAccessKey := os.Getenv("S3_SECRET_ACCESS_KEY") useSSL := true return minio.New(endpoint, &minio.Options{ Creds: credentials.NewStaticV4(accessKeyID, secretAccessKey, ""), Secure: useSSL, }) } func configureBugsnag() { apiKey := os.Getenv("BUGSNAG_API_KEY") if apiKey == "" { slog.Info("bugsnag not configured") return } bugsnag.Configure(bugsnag.Configuration{ APIKey: apiKey, ReleaseStage: "production", }) }