package poster import ( "log/slog" "sync" "time" "pete/internal/storage" "maunium.net/go/mautrix/id" ) // ReactionCallback is an optional hook fired after a reaction is recorded. // Used to wire reaction-driven features (e.g. ❓ → summary) without coupling // poster to those packages. type ReactionCallback func(roomID id.RoomID, targetEventID id.EventID, guid, channel, emoji string) var ( reactionCallbackMu sync.RWMutex reactionCallback ReactionCallback ) // SetReactionCallback installs a hook called after every recorded reaction. // Pass nil to clear. Safe to call before or after the matrix client starts. func SetReactionCallback(fn ReactionCallback) { reactionCallbackMu.Lock() reactionCallback = fn reactionCallbackMu.Unlock() } // HandleReaction processes a reaction event by mapping it back to the story GUID. func HandleReaction(roomID id.RoomID, eventID id.EventID, targetEventID id.EventID, emoji string, userID id.UserID) { guid, channel, found := storage.LookupPostGUID(string(targetEventID)) if !found { // Reaction on a message we didn't post — ignore return } storage.InsertReaction(guid, channel, string(eventID), emoji, string(userID), time.Now().Unix()) slog.Debug("reaction recorded", "guid", guid, "channel", channel, "emoji", emoji, "user", userID, ) reactionCallbackMu.RLock() cb := reactionCallback reactionCallbackMu.RUnlock() if cb != nil { go cb(roomID, targetEventID, guid, channel, emoji) } }