github.com/maeglindeveloper/gqlgen@v0.13.1-0.20210413081235-57808b12a0a0/example/chat/resolvers.go (about) 1 //go:generate go run ../../testdata/gqlgen.go 2 3 package chat 4 5 import ( 6 "context" 7 "math/rand" 8 "sync" 9 "time" 10 11 "github.com/99designs/gqlgen/graphql" 12 ) 13 14 type ckey string 15 16 type resolver struct { 17 Rooms map[string]*Chatroom 18 mu sync.Mutex // nolint: structcheck 19 } 20 21 func (r *resolver) Mutation() MutationResolver { 22 return &mutationResolver{r} 23 } 24 25 func (r *resolver) Query() QueryResolver { 26 return &queryResolver{r} 27 } 28 29 func (r *resolver) Subscription() SubscriptionResolver { 30 return &subscriptionResolver{r} 31 } 32 33 func New() Config { 34 return Config{ 35 Resolvers: &resolver{ 36 Rooms: map[string]*Chatroom{}, 37 }, 38 Directives: DirectiveRoot{ 39 User: func(ctx context.Context, obj interface{}, next graphql.Resolver, username string) (res interface{}, err error) { 40 return next(context.WithValue(ctx, ckey("username"), username)) 41 }, 42 }, 43 } 44 } 45 46 func getUsername(ctx context.Context) string { 47 if username, ok := ctx.Value(ckey("username")).(string); ok { 48 return username 49 } 50 return "" 51 } 52 53 type Chatroom struct { 54 Name string 55 Messages []Message 56 Observers map[string]struct { 57 Username string 58 Message chan *Message 59 } 60 } 61 62 type mutationResolver struct{ *resolver } 63 64 func (r *mutationResolver) Post(ctx context.Context, text string, username string, roomName string) (*Message, error) { 65 r.mu.Lock() 66 room := r.Rooms[roomName] 67 if room == nil { 68 room = &Chatroom{ 69 Name: roomName, 70 Observers: map[string]struct { 71 Username string 72 Message chan *Message 73 }{}, 74 } 75 r.Rooms[roomName] = room 76 } 77 r.mu.Unlock() 78 79 message := Message{ 80 ID: randString(8), 81 CreatedAt: time.Now(), 82 Text: text, 83 CreatedBy: username, 84 } 85 86 room.Messages = append(room.Messages, message) 87 r.mu.Lock() 88 for _, observer := range room.Observers { 89 if observer.Username == "" || observer.Username == message.CreatedBy { 90 observer.Message <- &message 91 } 92 } 93 r.mu.Unlock() 94 return &message, nil 95 } 96 97 type queryResolver struct{ *resolver } 98 99 func (r *queryResolver) Room(ctx context.Context, name string) (*Chatroom, error) { 100 r.mu.Lock() 101 room := r.Rooms[name] 102 if room == nil { 103 room = &Chatroom{ 104 Name: name, 105 Observers: map[string]struct { 106 Username string 107 Message chan *Message 108 }{}, 109 } 110 r.Rooms[name] = room 111 } 112 r.mu.Unlock() 113 114 return room, nil 115 } 116 117 type subscriptionResolver struct{ *resolver } 118 119 func (r *subscriptionResolver) MessageAdded(ctx context.Context, roomName string) (<-chan *Message, error) { 120 r.mu.Lock() 121 room := r.Rooms[roomName] 122 if room == nil { 123 room = &Chatroom{ 124 Name: roomName, 125 Observers: map[string]struct { 126 Username string 127 Message chan *Message 128 }{}, 129 } 130 r.Rooms[roomName] = room 131 } 132 r.mu.Unlock() 133 134 id := randString(8) 135 events := make(chan *Message, 1) 136 137 go func() { 138 <-ctx.Done() 139 r.mu.Lock() 140 delete(room.Observers, id) 141 r.mu.Unlock() 142 }() 143 144 r.mu.Lock() 145 room.Observers[id] = struct { 146 Username string 147 Message chan *Message 148 }{Username: getUsername(ctx), Message: events} 149 r.mu.Unlock() 150 151 return events, nil 152 } 153 154 var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") 155 156 func randString(n int) string { 157 b := make([]rune, n) 158 for i := range b { 159 b[i] = letterRunes[rand.Intn(len(letterRunes))] 160 } 161 return string(b) 162 }