package protosocket import "strings" type EventSubscriber interface { Subscribe(connectionID string, subscription EventSubscription) EventSubscription } type EventSubscription struct { Events []string RepoID string Branch string } func (s EventSubscription) Normalized() EventSubscription { events := make([]string, 0, len(s.Events)) seen := make(map[string]struct{}, len(s.Events)) for _, event := range s.Events { event = strings.TrimSpace(event) if event == "" { continue } if _, ok := seen[event]; ok { continue } seen[event] = struct{}{} events = append(events, event) } return EventSubscription{ Events: events, RepoID: strings.TrimSpace(s.RepoID), Branch: strings.TrimSpace(s.Branch), } } func (s EventSubscription) Allows(env Envelope) bool { s = s.Normalized() if env.Type != "event" { return false } if !s.allowsEventName(env.Action, stringPayload(env.Payload, "type")) { return false } if s.RepoID != "" && s.RepoID != stringPayload(env.Payload, "repo_id") { return false } if s.Branch != "" && s.Branch != stringPayload(env.Payload, "branch") { return false } return true } func (s EventSubscription) Payload() map[string]any { s = s.Normalized() events := make([]any, 0, len(s.Events)) for _, event := range s.Events { events = append(events, event) } return map[string]any{ "events": events, "repo_id": s.RepoID, "branch": s.Branch, } } func (s EventSubscription) allowsEventName(action, payloadType string) bool { if len(s.Events) == 0 { return true } for _, event := range s.Events { if event == "*" || event == action || event == payloadType { return true } } return false } func stringPayload(payload map[string]any, key string) string { value, ok := payload[key] if !ok { return "" } text, ok := value.(string) if !ok { return "" } return strings.TrimSpace(text) }