subscription.go

  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}