goatcounter-systemd/goatcounter/multi_site_client.go

70 lines
1.6 KiB
Go
Raw Permalink Normal View History

2024-09-28 16:20:24 -04:00
package goatcounter
import (
"context"
"log/slog"
"net/url"
)
type SiteClient interface {
URL() *url.URL
Count(context.Context, ...Hit) (uint64, error)
}
type MultiSiteClient struct {
siteToClient map[string]SiteClient
ignoreSites map[string]struct{}
}
func NewMultiSiteClient(siteToClient map[string]SiteClient, ignoreGoatSites bool) *MultiSiteClient {
ignoreSites := map[string]struct{}{}
if ignoreGoatSites {
for _, client := range siteToClient {
ignoreSite := client.URL().Host
slog.Debug("ignoring goat site", slog.String("site", ignoreSite))
ignoreSites[ignoreSite] = struct{}{}
}
}
return &MultiSiteClient{
siteToClient: siteToClient,
ignoreSites: ignoreSites,
}
}
func (m *MultiSiteClient) Count(ctx context.Context, hits ...Hit) (counted uint64, err error) {
siteHits := map[string][]Hit{}
for _, hit := range hits {
siteHits[hit.Host] = append(siteHits[hit.Host], hit)
}
for site, hits := range siteHits {
hitCount := len(hits)
logger := slog.With(slog.String("site", site), slog.Int("count", hitCount))
if _, ignore := m.ignoreSites[site]; ignore {
logger.DebugContext(ctx, "ignoring hits for site")
continue
}
client, ok := m.siteToClient[site]
if !ok {
logger.ErrorContext(ctx, "no client for site, skipping")
continue
}
subCount, err := client.Count(ctx, hits...)
if err != nil {
logger.ErrorContext(ctx, "failed to count hits", slog.String("err", err.Error()))
continue
}
logger.InfoContext(ctx, "counted hits", slog.Uint64("counted", subCount))
counted += subCount
}
return counted, nil
}