github.com/jepp2078/gqlgen@v0.7.2/example/chat/resolvers.go (about)

     1  //go:generate gorunpkg github.com/99designs/gqlgen
     2  
     3  package chat
     4  
     5  import (
     6  	context "context"
     7  	"math/rand"
     8  	"sync"
     9  	"time"
    10  )
    11  
    12  type resolver struct {
    13  	Rooms map[string]*Chatroom
    14  	mu    sync.Mutex // nolint: structcheck
    15  }
    16  
    17  func (r *resolver) Mutation() MutationResolver {
    18  	return &mutationResolver{r}
    19  }
    20  
    21  func (r *resolver) Query() QueryResolver {
    22  	return &queryResolver{r}
    23  }
    24  
    25  func (r *resolver) Subscription() SubscriptionResolver {
    26  	return &subscriptionResolver{r}
    27  }
    28  
    29  func New() Config {
    30  	return Config{
    31  		Resolvers: &resolver{
    32  			Rooms: map[string]*Chatroom{},
    33  		},
    34  	}
    35  }
    36  
    37  type Chatroom struct {
    38  	Name      string
    39  	Messages  []Message
    40  	Observers map[string]chan Message
    41  }
    42  
    43  type mutationResolver struct{ *resolver }
    44  
    45  func (r *mutationResolver) Post(ctx context.Context, text string, username string, roomName string) (Message, error) {
    46  	r.mu.Lock()
    47  	room := r.Rooms[roomName]
    48  	if room == nil {
    49  		room = &Chatroom{Name: roomName, Observers: map[string]chan Message{}}
    50  		r.Rooms[roomName] = room
    51  	}
    52  	r.mu.Unlock()
    53  
    54  	message := Message{
    55  		ID:        randString(8),
    56  		CreatedAt: time.Now(),
    57  		Text:      text,
    58  		CreatedBy: username,
    59  	}
    60  
    61  	room.Messages = append(room.Messages, message)
    62  	r.mu.Lock()
    63  	for _, observer := range room.Observers {
    64  		observer <- message
    65  	}
    66  	r.mu.Unlock()
    67  	return message, nil
    68  }
    69  
    70  type queryResolver struct{ *resolver }
    71  
    72  func (r *queryResolver) Room(ctx context.Context, name string) (*Chatroom, error) {
    73  	r.mu.Lock()
    74  	room := r.Rooms[name]
    75  	if room == nil {
    76  		room = &Chatroom{Name: name, Observers: map[string]chan Message{}}
    77  		r.Rooms[name] = room
    78  	}
    79  	r.mu.Unlock()
    80  
    81  	return room, nil
    82  }
    83  
    84  type subscriptionResolver struct{ *resolver }
    85  
    86  func (r *subscriptionResolver) MessageAdded(ctx context.Context, roomName string) (<-chan Message, error) {
    87  	r.mu.Lock()
    88  	room := r.Rooms[roomName]
    89  	if room == nil {
    90  		room = &Chatroom{Name: roomName, Observers: map[string]chan Message{}}
    91  		r.Rooms[roomName] = room
    92  	}
    93  	r.mu.Unlock()
    94  
    95  	id := randString(8)
    96  	events := make(chan Message, 1)
    97  
    98  	go func() {
    99  		<-ctx.Done()
   100  		r.mu.Lock()
   101  		delete(room.Observers, id)
   102  		r.mu.Unlock()
   103  	}()
   104  
   105  	r.mu.Lock()
   106  	room.Observers[id] = events
   107  	r.mu.Unlock()
   108  
   109  	return events, nil
   110  }
   111  
   112  var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
   113  
   114  func randString(n int) string {
   115  	b := make([]rune, n)
   116  	for i := range b {
   117  		b[i] = letterRunes[rand.Intn(len(letterRunes))]
   118  	}
   119  	return string(b)
   120  }