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  }