replace Redis with an embedded SQLite string->string KV store (group commit, in-tx events, SQL search)
Build and Push Docker Image / build (push) Successful in 2m44s

This commit is contained in:
Worph
2026-10-19 20:51:00 +00:00
parent c53146e514
commit dc5cbdfb9b
80 changed files with 4601 additions and 6077 deletions
+10 -10
View File
@@ -11,7 +11,7 @@ import (
)
const (
// EventsStream is the Redis Stream name for file events
// EventsStream is the stream name for file events
EventsStream = "file:events"
// EventsStreamMaxLen is the approximate cap on stream length. Bounded
@@ -20,7 +20,7 @@ const (
EventsStreamMaxLen = 100_000
)
// Dispatcher sends file events to Redis Stream
// Dispatcher sends file events to the file:events stream
type Dispatcher struct {
mu sync.RWMutex
storageClient *storage.Client
@@ -31,20 +31,20 @@ func NewDispatcher() *Dispatcher {
return &Dispatcher{}
}
// SetStorageClient sets the storage client for Redis Stream publishing
// SetStorageClient sets the storage client for file:events publishing
func (d *Dispatcher) SetStorageClient(client *storage.Client) {
d.mu.Lock()
defer d.mu.Unlock()
d.storageClient = client
log.Println("[Dispatcher] Storage client set for Redis Stream publishing")
log.Println("[Dispatcher] Storage client set for file:events publishing")
}
// Dispatch sends an event to Redis Stream
// Dispatch sends an event to the file:events stream
func (d *Dispatcher) Dispatch(event FileEvent) {
go d.dispatchToStream(event)
}
// dispatchToStream publishes event to Redis Stream for service consumption
// dispatchToStream publishes event to the file:events stream for service consumption
func (d *Dispatcher) dispatchToStream(event FileEvent) {
d.mu.RLock()
client := d.storageClient
@@ -114,7 +114,7 @@ func (d *Dispatcher) EmitReset(watcherID string) error {
// Emit reset event as the first message in the fresh stream
event := FileEvent{
Type: EventTypeReset,
Path: "", // No specific path for reset
Path: "", // No specific path for reset
WatcherID: watcherID,
Timestamp: NowMS(),
}
@@ -125,7 +125,7 @@ func (d *Dispatcher) EmitReset(watcherID string) error {
return nil
}
// GetRecentEvents reads recent events from the Redis stream, newest first.
// GetRecentEvents reads recent events from the stream, newest first.
// If sinceMS > 0, only events strictly newer than that timestamp are returned.
// limit caps the number of returned events (defaults to 100 when <= 0).
func (d *Dispatcher) GetRecentEvents(sinceMS int64, limit int) ([]FileEvent, error) {
@@ -160,7 +160,7 @@ func (d *Dispatcher) GetRecentEvents(sinceMS int64, limit int) ([]FileEvent, err
return events, nil
}
// parseStreamEntry converts a Redis stream entry back into a FileEvent.
// parseStreamEntry converts a stream entry back into a FileEvent.
// All fields are stored as strings by XADD, so numerics need parsing.
func parseStreamEntry(entry storage.StreamEntry) FileEvent {
event := FileEvent{}
@@ -192,7 +192,7 @@ func parseStreamEntry(entry storage.StreamEntry) FileEvent {
}
// Fall back to the stream ID's millisecond prefix if the timestamp
// field is missing or unparseable — every Redis stream ID starts with ms.
// field is missing or unparseable — every stream ID starts with ms.
if event.Timestamp == 0 && entry.ID != "" {
if dash := strings.IndexByte(entry.ID, '-'); dash > 0 {
if n, err := strconv.ParseInt(entry.ID[:dash], 10, 64); err == nil {