You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

144 lines
4.1 KiB

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 media cache
mediaCache, err := cache.NewMediaCache("cache/media")
if err != nil {
logger.Fatalf("Failed to initialize media cache: %v", err)
}
// Initialize Nostr client
profileRelays := cfg.GetProfilesRelays()
contactRelays := cfg.GetContactFormRelays()
nostrClient := nostr.NewClient(cfg.Relays.Feeds, profileRelays, contactRelays)
ctx := context.Background()
if err := nostrClient.Connect(ctx); err != nil {
logger.Warnf("Failed to connect to relays: %v", err)
}
// Initialize services
// Use standard Nostr kind constants
articleKinds := nostr.SupportedArticleKinds()
// Use first profile relay for wiki service (fallback)
wikiRelay := cfg.Relays.Feeds
if len(profileRelays) > 0 {
wikiRelay = profileRelays[0]
}
wikiService := nostr.NewWikiService(nostrClient, articleKinds, nostr.KindWiki, wikiRelay, nostr.KindIndex, nostr.KindBlog, nostr.KindLongform)
feedService := nostr.NewFeedService(nostrClient, nostr.KindNote)
issueService := nostr.NewIssueService(nostrClient, nostr.KindIssue, nostr.KindRepoAnnouncement)
ebooksService := nostr.NewEBooksService(nostrClient, nostr.KindIndex, cfg.Relays.Feeds)
// 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,
)
// Generate minimal landing page immediately so server can start serving
logger.Info("Generating initial landing page...")
initialLandingHTML, err := htmlGenerator.GenerateLandingPage(
[]generator.WikiPageInfo{},
nil, // newestBlogItem
nil, // newestArticleItem
[]generator.ArticleItemInfo{}, // allArticleItems
[]generator.EBookInfo{}, // allEBooks
)
if err == nil {
if err := pageCache.Set("/", initialLandingHTML); err != nil {
logger.Warnf("Failed to cache initial landing page: %v", err)
} else {
logger.Info("Initial landing page cached")
}
} else {
logger.Warnf("Failed to generate initial landing page: %v", err)
}
// Start cache rewarming (runs in background)
rewarmer.Start(ctx)
// Initialize HTTP server
httpServer := server.NewServer(cfg.Server.Port, pageCache, feedCache, mediaCache, issueService, cfg.RepoAnnouncement, htmlGenerator, nostrClient, cfg.SEO.SiteURL)
// 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("Cache rewarming in progress... (pages will update as they become available)")
// Wait for shutdown signal
httpServer.WaitForShutdown()
// Close Nostr client
nostrClient.Close()
}