saasfeed

package
v1.0.134 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2026 License: MIT Imports: 10 Imported by: 0

Documentation

Overview

Package saasfeed is the SaaS category feed syncer: it periodically fetches a curated JSON file of SaaS URL categories (AI, Marketing, Messaging, …) from a remote URL and hands the parsed categories to an injected merge callback. Extracted from package main per ADR-0002 (five-seam design recorded there): the category store lives in main's policy engine, so the MERGE is main's closure over catStore; the LIFECYCLE context provider is injected (the sync loop must die with the process, P6.1 UC-3); the CLIENT is injected (main builds it on ssrf.SafeDialContext); the sync-failure COUNTER is package-owned (SyncFailures, read by urlcat_metrics.go); and test construction goes through New/SeedStats/SetFeedURLForTest instead of struct-literal field pokes.

Sync interval defaults to 24h. Admin can change the URL via the GUI to point at a private fork or internal mirror. Merge strategy is additive only (implemented by the injected callback).

Index

Constants

View Source
const DefaultFeedURL = "https://raw.githubusercontent.com/KidCarmi/Culvert/main/internal/urlcat/default_categories.json"

DefaultFeedURL is the built-in feed location (the Culvert GitHub repo); package main's urlcategories startup slice uses it as the config default. The path tracks the file's in-repo home (internal/urlcat since the ADR-0002 urlcat extraction — a stale root path here would 404 every default-URL deployment).

Variables

This section is empty.

Functions

func SyncFailures

func SyncFailures() int64

SyncFailures returns the cumulative SaaS feed sync failure count.

Types

type Category

type Category struct {
	Name  string   `json:"name"`
	Hosts []string `json:"hosts"`
}

Category is the feed's wire type: one named URL category with its host list. JSON-compatible with main's CategoryEntry (whose builtIn field the feed does not carry).

type Deps

type Deps struct {
	// Client performs the feed fetches. nil → a 30s-timeout default client
	// WITHOUT the SSRF-safe dialer; production (package main) always passes
	// a client built on ssrf.SafeDialContext.
	Client *http.Client
	// Merge folds parsed categories into the category store and returns the
	// number of hosts added (it owns persistence of the store). nil → the
	// fetch/parse result is dropped with added=0 (test convenience).
	Merge func(categories []Category) (added int)
	// Lifecycle returns the context the sync loop is parented to, resolved
	// at Configure time (P6.1 UC-3: process shutdown must cancel the loop).
	// nil → context.Background().
	Lifecycle func() context.Context
}

Deps carries the injectable collaborators for New.

type Syncer

type Syncer struct {
	// contains filtered or unexported fields
}

Syncer periodically fetches the feed and merges it via the injected callback.

func New

func New(deps Deps) *Syncer

New builds a Syncer from injected collaborators. The syncer starts idle (Configure enables it); interval defaults to 24h.

func (*Syncer) Configure

func (s *Syncer) Configure(feedURL string, interval time.Duration)

Configure sets the feed URL and starts the periodic sync loop.

func (*Syncer) Done

func (s *Syncer) Done() <-chan struct{}

Done returns the channel that closes when the current syncLoop goroutine exits, or nil when the syncer is not running. Provided as a test seam so the P6.1 UC-3 regression can wait deterministically for the goroutine to actually finish after the lifecycle context is cancelled; production code does not call this today.

func (*Syncer) Enabled

func (s *Syncer) Enabled() bool

Enabled returns whether the feed is active.

func (*Syncer) FeedURL

func (s *Syncer) FeedURL() string

FeedURL returns the configured URL.

func (*Syncer) SeedStats

func (s *Syncer) SeedStats(lastSync time.Time, count int64)

SeedStats sets the last-sync timestamp and added-count directly. Test support for the metrics surface (production values are set by Sync).

func (*Syncer) SetFeedURLForTest

func (s *Syncer) SetFeedURLForTest(feedURL string)

SetFeedURLForTest sets the feed URL without starting the sync loop, so a test can drive Sync synchronously (e.g. the invalid-URL failure-counter regression). Production code configures via Configure.

func (*Syncer) Stats

func (s *Syncer) Stats() (url string, lastSync time.Time, count int64, interval time.Duration)

Stats returns the current feed URL, last sync time, and domain count.

func (*Syncer) Stop

func (s *Syncer) Stop()

Stop halts the sync loop.

func (*Syncer) Sync

func (s *Syncer) Sync(ctx context.Context)

Sync fetches the feed and merges it via the injected callback.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL