diff --git a/automod/engine.go b/automod/engine.go index c1bd0919..23641e65 100644 --- a/automod/engine.go +++ b/automod/engine.go @@ -5,25 +5,24 @@ import ( "fmt" "log/slog" "strings" - "sync" appbsky "github.com/bluesky-social/indigo/api/bsky" "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/atproto/syntax" - "github.com/bluesky-social/indigo/xrpc" ) // runtime for executing rules, managing state, and recording moderation actions. // // TODO: careful when initializing: several fields should not be null or zero, even though they are pointer type. type Engine struct { - Logger *slog.Logger + Logger *slog.Logger Directory identity.Directory // current rule sets. will eventually be possible to swap these out at runtime - RulesMap sync.Map + // TODO: RulesMap sync.Map // used to persist moderation actions in mod service (optional) - AdminClient *xrpc.Client - CountStore CountStore + // TODO: AdminClient *xrpc.Client + Counters CountStore + Sets SetStore } func (e *Engine) ProcessIdentityEvent(ctx context.Context, t string, did syntax.DID) error { @@ -92,7 +91,7 @@ func (e *Engine) ProcessRecord(ctx context.Context, did syntax.DID, path string, func (e *Engine) NewPostEvent(ident *identity.Identity, path string, post *appbsky.FeedPost) PostEvent { return PostEvent{ - RecordEvent { + RecordEvent{ Event{ Engine: e, Account: AccountMeta{Identity: ident}, @@ -119,10 +118,10 @@ func (e *Engine) NewRecordEvent(ident *identity.Identity, path string, rec any) } func (e *Engine) GetCount(key, period string) (int, error) { - return e.CountStore.GetCount(context.TODO(), key, period) + return e.Counters.GetCount(context.TODO(), key, period) } -func (e *Engine) InSet(setName, val string) (bool, error) { - // XXX: implement - return false, nil +// checks if `val` is an element of set `name` +func (e *Engine) InSet(name, val string) (bool, error) { + return e.Sets.InSet(context.TODO(), name, val) } diff --git a/automod/setstore.go b/automod/setstore.go new file mode 100644 index 00000000..d113d1bb --- /dev/null +++ b/automod/setstore.go @@ -0,0 +1,30 @@ +package automod + +import ( + "context" + "fmt" +) + +type SetStore interface { + InSet(ctx context.Context, name, val string) (bool, error) +} + +// TODO: this implementation isn't race-safe (yet)! +type MemSetStore struct { + Sets map[string]map[string]bool +} + +func NewMemSetStore() MemSetStore { + return MemSetStore{ + Sets: make(map[string]map[string]bool), + } +} + +func (s MemSetStore) InSet(ctx context.Context, name, val string) (bool, error) { + set, ok := s.Sets[name] + if !ok { + return false, fmt.Errorf("not a known set: %s", name) + } + _, ok = set[val] + return ok, nil +} diff --git a/cmd/hepa/otel.go b/cmd/hepa/otel.go index 918bd1b7..b551325c 100644 --- a/cmd/hepa/otel.go +++ b/cmd/hepa/otel.go @@ -1,10 +1,10 @@ package main import ( - "os" - "log/slog" - "log" "context" + "log" + "log/slog" + "os" "time" "go.opentelemetry.io/otel" diff --git a/cmd/hepa/server.go b/cmd/hepa/server.go index 682f84f9..332f3e61 100644 --- a/cmd/hepa/server.go +++ b/cmd/hepa/server.go @@ -38,9 +38,10 @@ func NewServer(dir identity.Directory, config Config) (*Server, error) { } engine := automod.Engine{ - Logger: logger, + Logger: logger, Directory: dir, - CountStore: automod.NewMemCountStore(), + Counters: automod.NewMemCountStore(), + Sets: automod.NewMemSetStore(), // TODO: RulesMap (loaded/config from somewhere) // TODO: AdminClient (XRPC with mod access) }