package greeter import ( "context" "errors" "fmt" "io" "gitea.dwysokinski.me/Kichiyaki/grpc-demo/proto" "go.uber.org/zap" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" ) type Server struct { proto.UnimplementedGreeterServer logger *zap.Logger } func NewServer(logger *zap.Logger) *Server { return &Server{logger: logger} } func (s *Server) SayHello(ctx context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) { md, ok := metadata.FromIncomingContext(ctx) if ok { s.logger.Debug("received metadata", zap.Any("metadata", md)) } return &proto.HelloReply{ Message: buildHelloMsg(r.GetName()), }, nil } func (s *Server) SayHelloToJames(_ context.Context, r *proto.HelloRequest) (*proto.HelloReply, error) { name := r.GetName() if name != "James" { st, err := status. New(codes.InvalidArgument, "invalid name"). WithDetails(&errdetails.BadRequest{ FieldViolations: []*errdetails.BadRequest_FieldViolation{ { Field: "name", Description: "must be James", }, }, }) if err != nil { return nil, status.New(codes.Internal, "internal server error").Err() } return nil, st.Err() } return &proto.HelloReply{ Message: buildHelloMsg(name), }, nil } func (s *Server) SayHelloServerStream(r *proto.MultiHelloRequest, stream proto.Greeter_SayHelloServerStreamServer) error { for _, n := range r.GetNames() { if err := stream.Send(&proto.HelloReply{ Message: buildHelloMsg(n), }); err != nil { return err } } return nil } func (s *Server) SayHelloClientStream(stream proto.Greeter_SayHelloClientStreamServer) error { var messages []string for { r, err := stream.Recv() if errors.Is(err, io.EOF) { return stream.SendAndClose(&proto.MultiHelloReply{ Messages: messages, }) } if err != nil { return fmt.Errorf("stream returned error: %w", err) } messages = append(messages, buildHelloMsg(r.GetName())) } } func (s *Server) SayHelloBidirectionalStream(stream proto.Greeter_SayHelloBidirectionalStreamServer) error { for { r, err := stream.Recv() if errors.Is(err, io.EOF) { return nil } if err != nil { return fmt.Errorf("stream returned error: %w", err) } if err = stream.Send(&proto.HelloReply{Message: buildHelloMsg(r.GetName())}); err != nil { return fmt.Errorf("couldn't send reply: %w", err) } } } func buildHelloMsg(name string) string { return "Hello " + name + "!" }