From 4fe07e636ae34f52bce83412ed8f90975aaa5ca7 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 16 Feb 2026 15:52:38 +0100 Subject: [PATCH] removed dead and redundant code implemented sitemap and expanded healthcheck --- cmd/server/main.go | 2 +- internal/generator/html.go | 9 ----- internal/generator/seo.go | 70 ------------------------------------- internal/nostr/client.go | 27 ++------------ internal/server/handlers.go | 61 +++++++++++++++++++++++++++++--- internal/server/server.go | 20 ++--------- 6 files changed, 64 insertions(+), 125 deletions(-) delete mode 100644 internal/generator/seo.go diff --git a/cmd/server/main.go b/cmd/server/main.go index 5ccadd6..d542f4c 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -124,7 +124,7 @@ func main() { rewarmer.Start(ctx) // Initialize HTTP server - httpServer := server.NewServer(cfg.Server.Port, pageCache, feedCache, mediaCache, issueService, cfg.RepoAnnouncement, htmlGenerator, nostrClient) + httpServer := server.NewServer(cfg.Server.Port, pageCache, feedCache, mediaCache, issueService, cfg.RepoAnnouncement, htmlGenerator, nostrClient, cfg.SEO.SiteURL) // Start server in goroutine go func() { diff --git a/internal/generator/html.go b/internal/generator/html.go index 6282bd5..d2b4e94 100644 --- a/internal/generator/html.go +++ b/internal/generator/html.go @@ -179,15 +179,6 @@ type EBookInfo struct { TimeISO string // ISO time } -// UserBadgeInfo represents user badge data for display -type UserBadgeInfo struct { - Pubkey string - Picture string - DisplayName string - Name string - ShortNpub string -} - // NewHTMLGenerator creates a new HTML generator func NewHTMLGenerator(templateDir string, linkBaseURL, siteName, siteURL, defaultImage string, nostrClient *nostr.Client) (*HTMLGenerator, error) { tmpl := template.New("base").Funcs(getTemplateFuncs()) diff --git a/internal/generator/seo.go b/internal/generator/seo.go deleted file mode 100644 index edc871c..0000000 --- a/internal/generator/seo.go +++ /dev/null @@ -1,70 +0,0 @@ -package generator - -import ( - "encoding/json" -) - -// GenerateStructuredData generates JSON-LD structured data -func GenerateStructuredData(siteName, siteURL, pageType, title, description, url string) string { - var data map[string]interface{} - - switch pageType { - case "article": - data = map[string]interface{}{ - "@context": "https://schema.org", - "@type": "Article", - "headline": title, - "description": description, - "url": url, - "publisher": map[string]interface{}{ - "@type": "Organization", - "name": siteName, - }, - } - case "website": - data = map[string]interface{}{ - "@context": "https://schema.org", - "@type": "WebSite", - "name": siteName, - "url": siteURL, - } - default: - data = map[string]interface{}{ - "@context": "https://schema.org", - "@type": "WebPage", - "name": title, - "url": url, - } - } - - jsonData, _ := json.Marshal(data) - return string(jsonData) -} - -// GenerateBreadcrumbStructuredData generates breadcrumb structured data -func GenerateBreadcrumbStructuredData(items []BreadcrumbItem, siteURL string) string { - breadcrumbList := make([]map[string]interface{}, len(items)) - for i, item := range items { - breadcrumbList[i] = map[string]interface{}{ - "@type": "ListItem", - "position": i + 1, - "name": item.Name, - "item": siteURL + item.URL, - } - } - - data := map[string]interface{}{ - "@context": "https://schema.org", - "@type": "BreadcrumbList", - "itemListElement": breadcrumbList, - } - - jsonData, _ := json.Marshal(data) - return string(jsonData) -} - -// BreadcrumbItem represents a breadcrumb item -type BreadcrumbItem struct { - Name string - URL string -} diff --git a/internal/nostr/client.go b/internal/nostr/client.go index 05a4d39..bec4a83 100644 --- a/internal/nostr/client.go +++ b/internal/nostr/client.go @@ -3,7 +3,6 @@ package nostr import ( "context" "fmt" - "sync" "time" "gitcitadel-online/internal/logger" @@ -15,11 +14,9 @@ import ( type Client struct { pool *nostr.SimplePool relays []string - feedsRelay string // Relay for feeds - profileRelays []string // Relays for profiles - contactRelays []string // Relays for contact form - mu sync.RWMutex - ctx context.Context + feedsRelay string // Relay for feeds + profileRelays []string // Relays for profiles + contactRelays []string // Relays for contact form requestSem chan struct{} // Semaphore to limit concurrent requests maxConcurrent int // Maximum concurrent requests } @@ -45,7 +42,6 @@ func NewClient(feedsRelay string, profileRelays []string, contactRelays []string feedsRelay: feedsRelay, profileRelays: profileRelays, contactRelays: contactRelays, - ctx: ctx, requestSem: make(chan struct{}, maxConcurrent), maxConcurrent: maxConcurrent, } @@ -197,23 +193,6 @@ func (c *Client) FetchEventsBatchFromRelays(ctx context.Context, filters []nostr return events, nil } -// FetchEventByID fetches an event by its ID -func (c *Client) FetchEventByID(ctx context.Context, eventID string) (*nostr.Event, error) { - filter := nostr.Filter{ - IDs: []string{eventID}, - } - return c.FetchEvent(ctx, filter) -} - -// FetchEventsByKind fetches events of a specific kind -func (c *Client) FetchEventsByKind(ctx context.Context, kind int, limit int) ([]*nostr.Event, error) { - filter := nostr.Filter{ - Kinds: []int{kind}, - Limit: limit, - } - return c.FetchEvents(ctx, filter) -} - // Close closes all relay connections in the pool func (c *Client) Close() { // SimplePool manages connections, but we can close individual relays if needed diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 8fa253c..3b70a7a 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -408,11 +408,24 @@ func (s *Server) handleMediaCache(w http.ResponseWriter, r *http.Request) { // handleHealth handles health check requests func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { + // Check if cache has pages if s.cache.Size() == 0 { w.WriteHeader(http.StatusServiceUnavailable) - w.Write([]byte("Not ready")) + w.Write([]byte("Not ready - cache empty")) return } + + // Check relay connectivity with timeout + ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) + defer cancel() + + if err := s.nostrClient.HealthCheck(ctx, 5*time.Second); err != nil { + logger.WithField("error", err).Warn("Health check: relay connectivity check failed") + w.WriteHeader(http.StatusServiceUnavailable) + w.Write([]byte("Not ready - relay connectivity check failed")) + return + } + w.WriteHeader(http.StatusOK) w.Write([]byte("OK")) } @@ -426,11 +439,51 @@ func (s *Server) handleMetrics(w http.ResponseWriter, r *http.Request) { // handleSitemap handles sitemap requests func (s *Server) handleSitemap(w http.ResponseWriter, r *http.Request) { - // TODO: Generate sitemap from cache - w.Header().Set("Content-Type", "application/xml") - w.Write([]byte(` + // Get all cached page paths + paths := s.cache.GetAllPaths() + if len(paths) == 0 { + w.Header().Set("Content-Type", "application/xml") + w.Write([]byte(` `)) + return + } + + // Convert cached pages to sitemap URLs + sitemapURLs := make([]generator.SitemapURL, 0, len(paths)) + for _, path := range paths { + page, exists := s.cache.Get(path) + if !exists { + continue + } + + // Determine priority and change frequency based on path + priority := 0.5 + changeFreq := "daily" + if path == "/" { + priority = 1.0 + changeFreq = "hourly" + } else if path == "/wiki" || path == "/blog" || path == "/articles" || path == "/ebooks" { + priority = 0.8 + changeFreq = "daily" + } else if strings.HasPrefix(path, "/wiki/") { + priority = 0.7 + changeFreq = "weekly" + } + + sitemapURLs = append(sitemapURLs, generator.SitemapURL{ + Path: path, + LastMod: page.LastUpdated, + ChangeFreq: changeFreq, + Priority: priority, + }) + } + + // Generate sitemap XML + sitemapXML := generator.GenerateSitemap(sitemapURLs, s.siteURL) + + w.Header().Set("Content-Type", "application/xml") + w.Write([]byte(sitemapXML)) } // handleRobots handles robots.txt requests diff --git a/internal/server/server.go b/internal/server/server.go index d626b0a..a43f2cb 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -28,6 +28,7 @@ type Server struct { repoAnnouncement string htmlGenerator HTMLGeneratorInterface nostrClient *nostr.Client + siteURL string } // IssueServiceInterface defines the interface for issue service @@ -44,7 +45,7 @@ type HTMLGeneratorInterface interface { } // NewServer creates a new HTTP server -func NewServer(port int, pageCache *cache.Cache, feedCache *cache.FeedCache, mediaCache *cache.MediaCache, issueService IssueServiceInterface, repoAnnouncement string, htmlGenerator HTMLGeneratorInterface, nostrClient *nostr.Client) *Server { +func NewServer(port int, pageCache *cache.Cache, feedCache *cache.FeedCache, mediaCache *cache.MediaCache, issueService IssueServiceInterface, repoAnnouncement string, htmlGenerator HTMLGeneratorInterface, nostrClient *nostr.Client, siteURL string) *Server { s := &Server{ cache: pageCache, feedCache: feedCache, @@ -54,6 +55,7 @@ func NewServer(port int, pageCache *cache.Cache, feedCache *cache.FeedCache, med repoAnnouncement: repoAnnouncement, htmlGenerator: htmlGenerator, nostrClient: nostrClient, + siteURL: siteURL, } mux := http.NewServeMux() @@ -99,19 +101,3 @@ func (s *Server) WaitForShutdown() { logger.Info("Server exited") } - -// convertFeedItemsToInfo converts cache.FeedItem to generator.FeedItemInfo -func (s *Server) convertFeedItemsToInfo(items []cache.FeedItem) []generator.FeedItemInfo { - feedItems := make([]generator.FeedItemInfo, 0, len(items)) - for _, item := range items { - feedItems = append(feedItems, generator.FeedItemInfo{ - EventID: item.EventID, - Author: item.Author, - Content: item.Content, - Time: item.Time.Format("2006-01-02 15:04:05"), - TimeISO: item.Time.Format(time.RFC3339), - Link: item.Link, - }) - } - return feedItems -}