···130130 log.Fatal().Err(err).Msg("Failed to initialize OAuth")
131131 }
132132133133- // Initialize feed registry (in-memory; populated from SQLite after feedIndex opens)
134134- feedRegistry := feed.NewRegistry()
135135- feedService := feed.NewService(feedRegistry)
133133+ // feedRegistry and feedService are initialised after feedIndex opens below
136134137135 // Setup context for graceful shutdown
138136 ctx, cancel := context.WithCancel(context.Background())
···176174177175 log.Info().Str("path", feedIndexPath).Msg("Feed index opened")
178176179179- // One-time seed: copy any DIDs from the legacy BoltDB feed_registry bucket into
180180- // SQLite known_dids. INSERT OR IGNORE makes this a no-op once DIDs are present.
177177+ // One-time seed: copy DIDs from the legacy BoltDB feed_registry bucket into
178178+ // SQLite registered_dids. INSERT OR IGNORE makes this a no-op after first run.
181179 if legacyDIDs := store.LegacyFeedDIDs(); len(legacyDIDs) > 0 {
182182- added, err := feedIndex.SeedKnownDIDs(legacyDIDs)
180180+ added, err := feedIndex.SeedRegisteredDIDs(legacyDIDs)
183181 if err != nil {
184184- log.Warn().Err(err).Msg("Failed to seed known DIDs from legacy feed registry")
182182+ log.Warn().Err(err).Msg("Failed to seed registered DIDs from legacy feed registry")
185183 } else if added > 0 {
186186- log.Info().Int("seeded", added).Msg("Seeded known_dids from legacy BoltDB feed registry")
184184+ log.Info().Int("seeded", added).Msg("Seeded registered_dids from legacy BoltDB feed registry")
187185 }
188186 }
189187190190- // Populate feed registry from SQLite known_dids (replaces BoltDB feed registry)
191191- if knownDIDs, err := feedIndex.GetKnownDIDs(); err == nil {
192192- for _, did := range knownDIDs {
193193- feedRegistry.Register(did)
194194- }
195195- log.Info().Int("registered_users", feedRegistry.Count()).Msg("Feed registry populated from index")
196196- } else {
197197- log.Warn().Err(err).Msg("Failed to load known DIDs into feed registry")
198198- }
188188+ // Initialise feed registry backed by SQLite registered_dids.
189189+ // This preserves the distinction between registered users (explicit logins)
190190+ // and known_dids (any user whose records have been indexed via firehose).
191191+ feedRegistry := feed.NewPersistentRegistry(feedIndex)
192192+ feedService := feed.NewService(feedRegistry)
193193+194194+ log.Info().Int("registered_users", feedRegistry.Count()).Msg("Feed service initialised")
199195200196 // Create and start consumer
201197 firehoseConsumer := firehose.NewConsumer(firehoseConfig, feedIndex)
+4-17
internal/firehose/index.go
···106106);
107107108108CREATE TABLE IF NOT EXISTS known_dids (did TEXT PRIMARY KEY);
109109+CREATE TABLE IF NOT EXISTS registered_dids (
110110+ did TEXT PRIMARY KEY,
111111+ registered_at TEXT NOT NULL
112112+);
109113CREATE TABLE IF NOT EXISTS backfilled (did TEXT PRIMARY KEY, backfilled_at TEXT NOT NULL);
110114111115CREATE TABLE IF NOT EXISTS profiles (
···245249 return idx.db
246250}
247251248248-// SeedKnownDIDs inserts DIDs into known_dids, ignoring any that already exist.
249249-// Used for one-time migration from legacy storage.
250250-func (idx *FeedIndex) SeedKnownDIDs(dids []string) (int, error) {
251251- if len(dids) == 0 {
252252- return 0, nil
253253- }
254254- var added int
255255- for _, did := range dids {
256256- res, err := idx.db.Exec(`INSERT OR IGNORE INTO known_dids (did) VALUES (?)`, did)
257257- if err != nil {
258258- return added, fmt.Errorf("seed known DID %s: %w", did, err)
259259- }
260260- n, _ := res.RowsAffected()
261261- added += int(n)
262262- }
263263- return added, nil
264264-}
265252266253// Close closes the index database
267254func (idx *FeedIndex) Close() error {
+80
internal/firehose/registry.go
···11+package firehose
22+33+import (
44+ "time"
55+66+ "arabica/internal/feed"
77+)
88+99+// Ensure FeedIndex implements feed.PersistentStore at compile time.
1010+var _ feed.PersistentStore = (*FeedIndex)(nil)
1111+1212+// Register adds a DID to the registered_dids table.
1313+// This records users who have explicitly logged into Arabica.
1414+func (idx *FeedIndex) Register(did string) error {
1515+ _, err := idx.db.Exec(
1616+ `INSERT OR IGNORE INTO registered_dids (did, registered_at) VALUES (?, ?)`,
1717+ did, time.Now().Format(time.RFC3339),
1818+ )
1919+ return err
2020+}
2121+2222+// Unregister removes a DID from the registered_dids table.
2323+func (idx *FeedIndex) Unregister(did string) error {
2424+ _, err := idx.db.Exec(`DELETE FROM registered_dids WHERE did = ?`, did)
2525+ return err
2626+}
2727+2828+// IsRegistered reports whether a DID is in the registered_dids table.
2929+func (idx *FeedIndex) IsRegistered(did string) bool {
3030+ var exists int
3131+ _ = idx.db.QueryRow(`SELECT 1 FROM registered_dids WHERE did = ?`, did).Scan(&exists)
3232+ return exists == 1
3333+}
3434+3535+// List returns all registered DIDs.
3636+func (idx *FeedIndex) List() []string {
3737+ rows, err := idx.db.Query(`SELECT did FROM registered_dids`)
3838+ if err != nil {
3939+ return nil
4040+ }
4141+ defer rows.Close()
4242+4343+ var dids []string
4444+ for rows.Next() {
4545+ var did string
4646+ if err := rows.Scan(&did); err != nil {
4747+ continue
4848+ }
4949+ dids = append(dids, did)
5050+ }
5151+ return dids
5252+}
5353+5454+// Count returns the number of registered users.
5555+func (idx *FeedIndex) Count() int {
5656+ var count int
5757+ _ = idx.db.QueryRow(`SELECT COUNT(*) FROM registered_dids`).Scan(&count)
5858+ return count
5959+}
6060+6161+// SeedRegisteredDIDs inserts DIDs into registered_dids, ignoring duplicates.
6262+// Used for one-time migration from the legacy BoltDB feed_registry.
6363+func (idx *FeedIndex) SeedRegisteredDIDs(dids []string) (int, error) {
6464+ if len(dids) == 0 {
6565+ return 0, nil
6666+ }
6767+ var added int
6868+ for _, did := range dids {
6969+ res, err := idx.db.Exec(
7070+ `INSERT OR IGNORE INTO registered_dids (did, registered_at) VALUES (?, ?)`,
7171+ did, time.Now().Format(time.RFC3339),
7272+ )
7373+ if err != nil {
7474+ return added, err
7575+ }
7676+ n, _ := res.RowsAffected()
7777+ added += int(n)
7878+ }
7979+ return added, nil
8080+}