package main import ( "context" "flag" "time" "gitcitadel-online/internal/cache" "gitcitadel-online/internal/config" "gitcitadel-online/internal/generator" "gitcitadel-online/internal/logger" "gitcitadel-online/internal/nostr" "gitcitadel-online/internal/server" ) func main() { configPath := flag.String("config", "config.yaml", "Path to configuration file") devMode := flag.Bool("dev", false, "Enable development mode") logLevel := flag.String("log-level", "info", "Log level (debug, info, warn, error)") flag.Parse() // Initialize logger if *devMode { logger.Init("debug", true) } else { logger.Init(*logLevel, false) } // Load configuration cfg, err := config.LoadConfig(*configPath) if err != nil { logger.Fatalf("Failed to load config: %v", err) } if err := cfg.Validate(); err != nil { logger.Fatalf("Invalid config: %v", err) } if *devMode { logger.Info("Development mode enabled") } // Initialize caches pageCache := cache.NewCache() feedCache := cache.NewFeedCache() // Initialize Nostr client nostrClient := nostr.NewClient(cfg.Relays.Primary, cfg.Relays.Fallback, cfg.Relays.AdditionalFallback) ctx := context.Background() if err := nostrClient.Connect(ctx); err != nil { logger.Warnf("Failed to connect to relays: %v", err) } // Initialize services // Get the primary wiki kind (first from config) wikiKind := cfg.WikiKinds[0] // Get the primary blog kind (first from config) blogKind := cfg.BlogKinds[0] // Combine wiki and blog kinds for articleKinds (for backward compatibility) articleKinds := append(cfg.WikiKinds, cfg.BlogKinds...) wikiService := nostr.NewWikiService(nostrClient, articleKinds, wikiKind, cfg.Relays.AdditionalFallback, cfg.IndexKind, blogKind) feedService := nostr.NewFeedService(nostrClient, cfg.FeedKind) issueService := nostr.NewIssueService(nostrClient, cfg.IssueKind, cfg.RepoAnnouncementKind) ebooksService := nostr.NewEBooksService(nostrClient, cfg.IndexKind, "wss://theforest.nostr1.com") // Initialize HTML generator htmlGenerator, err := generator.NewHTMLGenerator( "templates", cfg.LinkBaseURL, cfg.SEO.SiteName, cfg.SEO.SiteURL, cfg.SEO.DefaultImage, nostrClient, ) if err != nil { logger.Fatalf("Failed to initialize HTML generator: %v", err) } // Initialize cache rewarming rewarmer := cache.NewRewarmer( pageCache, feedCache, wikiService, feedService, ebooksService, htmlGenerator, cfg.WikiIndex, cfg.BlogIndex, cfg.Feed.Relay, cfg.Feed.MaxEvents, time.Duration(cfg.Cache.RefreshIntervalMinutes)*time.Minute, time.Duration(cfg.Feed.PollIntervalMinutes)*time.Minute, ) // Start cache rewarming rewarmer.Start(ctx) // Initialize HTTP server httpServer := server.NewServer(cfg.Server.Port, pageCache, feedCache, issueService, cfg.RepoAnnouncement, htmlGenerator, nostrClient) // Start server in goroutine go func() { if err := httpServer.Start(); err != nil { logger.Fatalf("Server failed: %v", err) } }() logger.Infof("Server started on port %d", cfg.Server.Port) logger.Info("Waiting for initial cache population...") // Wait a bit for initial cache time.Sleep(5 * time.Second) // Wait for shutdown signal httpServer.WaitForShutdown() // Close Nostr client nostrClient.Close() }