package server import ( "context" "log" "time" "github.com/writekitapp/writekit/internal/tenant" ) func (s *Server) StartAnalyticsSync() { if !s.cloudflare.IsConfigured() { return } go s.runAnalyticsSync() } func (s *Server) runAnalyticsSync() { ticker := time.NewTicker(24 * time.Hour) defer ticker.Stop() s.syncYesterdayAnalytics() for range ticker.C { s.syncYesterdayAnalytics() } } func (s *Server) syncYesterdayAnalytics() { ctx := context.Background() yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02") tenants, err := s.database.ListTenants(ctx) if err != nil { log.Printf("analytics sync: list tenants: %v", err) return } for _, t := range tenants { s.syncTenantAnalytics(ctx, t.ID, t.Subdomain, yesterday) } demos, err := s.database.ListActiveDemos(ctx) if err != nil { log.Printf("analytics sync: list demos: %v", err) return } for _, d := range demos { s.syncTenantAnalytics(ctx, d.ID, d.Subdomain, yesterday) } } func (s *Server) syncTenantAnalytics(ctx context.Context, tenantID, subdomain, date string) { hostname := subdomain + "." + s.domain tenantDB, err := s.tenantPool.Get(tenantID) if err != nil { log.Printf("analytics sync: get tenant db %s: %v", tenantID, err) return } q := tenant.NewQueries(tenantDB) has, err := q.HasArchivedDate(ctx, date) if err != nil { log.Printf("analytics sync: check archived %s: %v", tenantID, err) return } if has { return } cfData, err := s.cloudflare.GetAnalytics(ctx, 1, hostname) if err != nil { log.Printf("analytics sync: fetch cf data %s: %v", tenantID, err) return } if cfData == nil || len(cfData.Daily) == 0 { return } day := cfData.Daily[0] archived := &tenant.ArchivedDay{ Date: day.Date, Requests: day.Requests, PageViews: day.PageViews, UniqueVisitors: day.Visitors, Bandwidth: day.Bandwidth, } for _, b := range cfData.Browsers { archived.Browsers = append(archived.Browsers, tenant.NamedStat{Name: b.Name, Count: b.Count}) } for _, o := range cfData.OS { archived.OS = append(archived.OS, tenant.NamedStat{Name: o.Name, Count: o.Count}) } for _, d := range cfData.Devices { archived.Devices = append(archived.Devices, tenant.NamedStat{Name: d.Name, Count: d.Count}) } for _, c := range cfData.Countries { archived.Countries = append(archived.Countries, tenant.NamedStat{Name: c.Name, Count: c.Count}) } for _, p := range cfData.Paths { archived.Paths = append(archived.Paths, tenant.PageStats{Path: p.Path, Views: p.Requests}) } if err := q.SaveDailyAnalytics(ctx, archived); err != nil { log.Printf("analytics sync: save archived %s: %v", tenantID, err) } }