github.com/yandex/pandora@v0.5.32/examples/grpc/server/server.go (about) 1 package server 2 3 import ( 4 "context" 5 "fmt" 6 "log/slog" 7 "strconv" 8 "sync" 9 10 "github.com/yandex/pandora/lib/str" 11 "google.golang.org/grpc/codes" 12 "google.golang.org/grpc/status" 13 ) 14 15 const ( 16 userCount = 10 17 userMultiplicator = 1000 18 itemMultiplicator = 100 19 ) 20 21 func NewServer(logger *slog.Logger, seed int64) *GRPCServer { 22 keys := make(map[string]int64, userCount) 23 for i := int64(1); i <= userCount; i++ { 24 keys[str.RandStringRunes(64, "")] = i 25 } 26 logger.Info("New server created", slog.Any("keys", keys)) 27 28 return &GRPCServer{Log: logger, keys: keys, stats: newStats(userCount)} 29 } 30 31 type GRPCServer struct { 32 UnimplementedTargetServiceServer 33 Log *slog.Logger 34 stats *Stats 35 keys map[string]int64 36 mu sync.RWMutex 37 } 38 39 var _ TargetServiceServer = (*GRPCServer)(nil) 40 41 func (s *GRPCServer) Hello(ctx context.Context, request *HelloRequest) (*HelloResponse, error) { 42 s.stats.IncHello() 43 return &HelloResponse{ 44 Hello: fmt.Sprintf("Hello %s!", request.Name), 45 }, nil 46 } 47 48 func (s *GRPCServer) Auth(ctx context.Context, request *AuthRequest) (*AuthResponse, error) { 49 userID, token, err := s.checkLoginPass(request.GetLogin(), request.GetPass()) 50 if err != nil { 51 s.stats.IncAuth400() 52 return nil, status.Error(codes.InvalidArgument, "invalid credentials") 53 } 54 result := &AuthResponse{ 55 UserId: userID, 56 Token: token, 57 } 58 s.stats.IncAuth200(userID) 59 return result, nil 60 } 61 62 func (s *GRPCServer) List(ctx context.Context, request *ListRequest) (*ListResponse, error) { 63 s.mu.RLock() 64 userID := s.keys[request.Token] 65 s.mu.RUnlock() 66 if userID == 0 { 67 s.stats.IncList400() 68 return nil, status.Error(codes.InvalidArgument, "invalid token") 69 } 70 if userID != request.UserId { 71 s.stats.IncList400() 72 return nil, status.Error(codes.InvalidArgument, "invalid user_id") 73 } 74 75 // Logic 76 result := &ListResponse{} 77 userID *= userMultiplicator 78 result.Result = make([]*ListItem, itemMultiplicator) 79 for i := int64(0); i < itemMultiplicator; i++ { 80 result.Result[i] = &ListItem{ItemId: userID + i} 81 } 82 s.stats.IncList200(request.UserId) 83 return result, nil 84 } 85 86 func (s *GRPCServer) Order(ctx context.Context, request *OrderRequest) (*OrderResponse, error) { 87 s.mu.RLock() 88 userID := s.keys[request.Token] 89 s.mu.RUnlock() 90 if userID == 0 { 91 s.stats.IncOrder400() 92 return nil, status.Error(codes.InvalidArgument, "invalid token") 93 } 94 if userID != request.UserId { 95 s.stats.IncOrder400() 96 return nil, status.Error(codes.InvalidArgument, "invalid user_id") 97 } 98 99 // Logic 100 ranger := userID * userMultiplicator 101 if request.ItemId < ranger || request.ItemId >= ranger+itemMultiplicator { 102 s.stats.IncOrder400() 103 return nil, status.Error(codes.InvalidArgument, "invalid item_id") 104 } 105 106 result := &OrderResponse{} 107 result.OrderId = request.ItemId + 12345 108 s.stats.IncOrder200(userID) 109 return result, nil 110 } 111 112 func (s *GRPCServer) Stats(ctx context.Context, _ *StatsRequest) (*StatsResponse, error) { 113 result := &StatsResponse{ 114 Hello: int64(s.stats.hello.Load()), 115 Auth: &StatisticBodyResponse{ 116 Code200: s.stats.auth200, 117 Code400: s.stats.auth400.Load(), 118 Code500: s.stats.auth500.Load(), 119 }, 120 List: &StatisticBodyResponse{ 121 Code200: s.stats.list200, 122 Code400: s.stats.list400.Load(), 123 Code500: s.stats.list500.Load(), 124 }, 125 Order: &StatisticBodyResponse{ 126 Code200: s.stats.order200, 127 Code400: s.stats.order400.Load(), 128 Code500: s.stats.order500.Load(), 129 }, 130 } 131 return result, nil 132 } 133 134 func (s *GRPCServer) Reset(ctx context.Context, request *ResetRequest) (*ResetResponse, error) { 135 s.stats.Reset() 136 137 result := &ResetResponse{ 138 Auth: &StatisticBodyResponse{ 139 Code200: s.stats.auth200, 140 Code400: s.stats.auth400.Load(), 141 Code500: s.stats.auth500.Load(), 142 }, 143 List: &StatisticBodyResponse{ 144 Code200: s.stats.list200, 145 Code400: s.stats.list400.Load(), 146 Code500: s.stats.list500.Load(), 147 }, 148 Order: &StatisticBodyResponse{ 149 Code200: s.stats.order200, 150 Code400: s.stats.order400.Load(), 151 Code500: s.stats.order500.Load(), 152 }, 153 } 154 return result, nil 155 } 156 157 func (s *GRPCServer) checkLoginPass(login string, pass string) (int64, string, error) { 158 userID, err := strconv.ParseInt(login, 10, 64) 159 if err != nil { 160 return 0, "", fmt.Errorf("invalid login %s", login) 161 } 162 if login != pass { 163 return 0, "", fmt.Errorf("invalid login %s or pass %s", login, pass) 164 } 165 token := "" 166 s.mu.RLock() 167 for k, v := range s.keys { 168 if v == userID { 169 token = k 170 break 171 } 172 } 173 s.mu.RUnlock() 174 if token == "" { 175 return 0, "", fmt.Errorf("invalid login %s and pass %s", login, pass) 176 } 177 178 return userID, token, nil 179 }