1package notify
2
3import (
4 "context"
5 "log/slog"
6 "reflect"
7 "sync"
8
9 "github.com/bluesky-social/indigo/atproto/syntax"
10 "tangled.org/core/appview/models"
11 "tangled.org/core/log"
12)
13
14type mergedNotifier struct {
15 notifiers []Notifier
16 logger *slog.Logger
17}
18
19func NewMergedNotifier(notifiers []Notifier, logger *slog.Logger) Notifier {
20 return &mergedNotifier{notifiers, logger}
21}
22
23var _ Notifier = &mergedNotifier{}
24
25// fanout calls the same method on all notifiers concurrently
26func (m *mergedNotifier) fanout(method string, ctx context.Context, args ...any) {
27 ctx = log.IntoContext(ctx, m.logger.With("method", method))
28 var wg sync.WaitGroup
29 for _, n := range m.notifiers {
30 wg.Add(1)
31 go func(notifier Notifier) {
32 defer wg.Done()
33 v := reflect.ValueOf(notifier).MethodByName(method)
34 in := make([]reflect.Value, len(args)+1)
35 in[0] = reflect.ValueOf(ctx)
36 for i, arg := range args {
37 in[i+1] = reflect.ValueOf(arg)
38 }
39 v.Call(in)
40 }(n)
41 }
42 wg.Wait()
43}
44
45func (m *mergedNotifier) NewRepo(ctx context.Context, repo *models.Repo) {
46 m.fanout("NewRepo", ctx, repo)
47}
48
49func (m *mergedNotifier) NewStar(ctx context.Context, star *models.Star) {
50 m.fanout("NewStar", ctx, star)
51}
52
53func (m *mergedNotifier) DeleteStar(ctx context.Context, star *models.Star) {
54 m.fanout("DeleteStar", ctx, star)
55}
56
57func (m *mergedNotifier) NewIssue(ctx context.Context, issue *models.Issue, mentions []syntax.DID) {
58 m.fanout("NewIssue", ctx, issue, mentions)
59}
60
61func (m *mergedNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) {
62 m.fanout("NewIssueComment", ctx, comment, mentions)
63}
64
65func (m *mergedNotifier) NewIssueState(ctx context.Context, actor syntax.DID, issue *models.Issue) {
66 m.fanout("NewIssueState", ctx, actor, issue)
67}
68
69func (m *mergedNotifier) DeleteIssue(ctx context.Context, issue *models.Issue) {
70 m.fanout("DeleteIssue", ctx, issue)
71}
72
73func (m *mergedNotifier) NewFollow(ctx context.Context, follow *models.Follow) {
74 m.fanout("NewFollow", ctx, follow)
75}
76
77func (m *mergedNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {
78 m.fanout("DeleteFollow", ctx, follow)
79}
80
81func (m *mergedNotifier) NewPull(ctx context.Context, pull *models.Pull) {
82 m.fanout("NewPull", ctx, pull)
83}
84
85func (m *mergedNotifier) NewPullComment(ctx context.Context, comment *models.PullComment, mentions []syntax.DID) {
86 m.fanout("NewPullComment", ctx, comment, mentions)
87}
88
89func (m *mergedNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {
90 m.fanout("NewPullState", ctx, actor, pull)
91}
92
93func (m *mergedNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {
94 m.fanout("UpdateProfile", ctx, profile)
95}
96
97func (m *mergedNotifier) NewString(ctx context.Context, s *models.String) {
98 m.fanout("NewString", ctx, s)
99}
100
101func (m *mergedNotifier) EditString(ctx context.Context, s *models.String) {
102 m.fanout("EditString", ctx, s)
103}
104
105func (m *mergedNotifier) DeleteString(ctx context.Context, did, rkey string) {
106 m.fanout("DeleteString", ctx, did, rkey)
107}