1package resolvers
2
3import (
4 "context"
5 "fmt"
6
7 "github.com/git-bug/git-bug/api/graphql/graph"
8 "github.com/git-bug/git-bug/api/graphql/models"
9 "github.com/git-bug/git-bug/cache"
10 "github.com/git-bug/git-bug/entities/bug"
11 "github.com/git-bug/git-bug/entities/identity"
12 "github.com/git-bug/git-bug/entity"
13)
14
15var _ graph.SubscriptionResolver = &subscriptionResolver{}
16
17type subscriptionResolver struct {
18 cache *cache.MultiRepoCache
19}
20
21func (s subscriptionResolver) AllEvents(ctx context.Context, repoRef *string, typename *string) (<-chan *models.EntityEvent, error) {
22 out := make(chan *models.EntityEvent)
23 sub := &subscription[models.EntityEvent]{
24 cache: s.cache,
25 out: out,
26 makeEvent: func(repo *cache.RepoCache, excerpt cache.Excerpt, eventType cache.EntityEventType) *models.EntityEvent {
27 switch excerpt := excerpt.(type) {
28 case *cache.BugExcerpt:
29 return &models.EntityEvent{Type: eventType, Entity: models.NewLazyBug(repo, excerpt)}
30 case *cache.IdentityExcerpt:
31 return &models.EntityEvent{Type: eventType, Entity: models.NewLazyIdentity(repo, excerpt)}
32 default:
33 panic(fmt.Sprintf("unknown excerpt type: %T", excerpt))
34 }
35 },
36 }
37
38 var repoRefStr string
39 if repoRef != nil {
40 repoRefStr = *repoRef
41 }
42
43 var typenameStr string
44 if typename != nil {
45 typenameStr = *typename
46 }
47
48 err := s.cache.RegisterObserver(sub, repoRefStr, typenameStr)
49 if err != nil {
50 return nil, err
51 }
52
53 go func() {
54 <-ctx.Done()
55 s.cache.UnregisterObserver(sub)
56 }()
57
58 return out, nil
59}
60
61func (s subscriptionResolver) BugEvents(ctx context.Context, repoRef *string) (<-chan *models.BugEvent, error) {
62 out := make(chan *models.BugEvent)
63 sub := &subscription[models.BugEvent]{
64 cache: s.cache,
65 out: out,
66 makeEvent: func(repo *cache.RepoCache, excerpt cache.Excerpt, event cache.EntityEventType) *models.BugEvent {
67 return &models.BugEvent{Type: event, Bug: models.NewLazyBug(repo, excerpt.(*cache.BugExcerpt))}
68 },
69 }
70
71 var repoRefStr string
72 if repoRef != nil {
73 repoRefStr = *repoRef
74 }
75
76 err := s.cache.RegisterObserver(sub, repoRefStr, bug.Typename)
77 if err != nil {
78 return nil, err
79 }
80
81 go func() {
82 <-ctx.Done()
83 s.cache.UnregisterObserver(sub)
84 }()
85
86 return out, nil
87}
88
89func (s subscriptionResolver) IdentityEvents(ctx context.Context, repoRef *string) (<-chan *models.IdentityEvent, error) {
90 out := make(chan *models.IdentityEvent)
91 sub := &subscription[models.IdentityEvent]{
92 cache: s.cache,
93 out: out,
94 makeEvent: func(repo *cache.RepoCache, excerpt cache.Excerpt, event cache.EntityEventType) *models.IdentityEvent {
95 return &models.IdentityEvent{Type: event, Identity: models.NewLazyIdentity(repo, excerpt.(*cache.IdentityExcerpt))}
96 },
97 }
98
99 var repoRefStr string
100 if repoRef != nil {
101 repoRefStr = *repoRef
102 }
103
104 err := s.cache.RegisterObserver(sub, repoRefStr, identity.Typename)
105 if err != nil {
106 return nil, err
107 }
108
109 go func() {
110 <-ctx.Done()
111 s.cache.UnregisterObserver(sub)
112 }()
113
114 return out, nil
115}
116
117var _ cache.Observer = &subscription[any]{}
118
119type subscription[eventT any] struct {
120 cache *cache.MultiRepoCache
121 out chan *eventT
122 filter func(cache.Excerpt) bool
123 makeEvent func(repo *cache.RepoCache, excerpt cache.Excerpt, event cache.EntityEventType) *eventT
124}
125
126func (s subscription[eventT]) EntityEvent(event cache.EntityEventType, repoName string, typename string, id entity.Id) {
127 repo, err := s.cache.ResolveRepo(repoName)
128 if err != nil {
129 // something terrible happened
130 return
131 }
132 var excerpt cache.Excerpt
133 switch typename {
134 case bug.Typename:
135 excerpt, err = repo.Bugs().ResolveExcerpt(id)
136 case identity.Typename:
137 excerpt, err = repo.Identities().ResolveExcerpt(id)
138 default:
139 panic(fmt.Sprintf("unknown typename: %s", typename))
140 }
141 if s.filter != nil && !s.filter(excerpt) {
142 return
143 }
144 s.out <- s.makeEvent(repo, excerpt, event)
145}