package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"go-grpc-gateway-template/internal/config"
"go-grpc-gateway-template/internal/server"
)
func main() {
// Load configuration
cfg := config.Load()
if err := cfg.Validate(); err != nil {
log.Fatalf("Invalid configuration: %v", err)
}
// Create server
srv := server.New(cfg)
// Setup graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Handle signals
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigChan
log.Println("Received shutdown signal")
cancel()
}()
// Start server
if err := srv.Start(ctx); err != nil {
log.Printf("Server error: %v", err)
}
// Shutdown server
if err := srv.Shutdown(context.Background()); err != nil {
log.Printf("Shutdown error: %v", err)
}
}
package config
import (
"fmt"
"os"
"strconv"
"strings"
)
// Config holds all configuration for the application
type Config struct {
Server ServerConfig
Log LogConfig
Metrics MetricsConfig
}
// ServerConfig holds server-related configuration
type ServerConfig struct {
GRPCPort string
HTTPPort string
}
// LogConfig holds logging configuration
type LogConfig struct {
Level string
Format string
}
// MetricsConfig holds metrics configuration
type MetricsConfig struct {
Enabled bool
}
// Load loads configuration from environment variables with defaults
func Load() *Config {
return &Config{
Server: ServerConfig{
GRPCPort: getEnv("SERVER_GRPC_PORT", "8080"),
HTTPPort: getEnv("SERVER_HTTP_PORT", "8090"),
},
Log: LogConfig{
Level: strings.ToLower(getEnv("LOG_LEVEL", "info")),
Format: strings.ToLower(getEnv("LOG_FORMAT", "json")),
},
Metrics: MetricsConfig{
Enabled: getEnvBool("METRICS_ENABLED", true),
},
}
}
// Validate validates the configuration
func (c *Config) Validate() error {
if c.Server.GRPCPort == "" {
return fmt.Errorf("gRPC port cannot be empty")
}
if c.Server.HTTPPort == "" {
return fmt.Errorf("HTTP port cannot be empty")
}
if c.Server.GRPCPort == c.Server.HTTPPort {
return fmt.Errorf("gRPC and HTTP ports cannot be the same")
}
validLogLevels := map[string]bool{
"debug": true,
"info": true,
"warn": true,
"error": true,
}
if !validLogLevels[c.Log.Level] {
return fmt.Errorf("invalid log level: %s", c.Log.Level)
}
validLogFormats := map[string]bool{
"json": true,
"text": true,
}
if !validLogFormats[c.Log.Format] {
return fmt.Errorf("invalid log format: %s", c.Log.Format)
}
return nil
}
// getEnv gets an environment variable or returns a default value
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}
// getEnvBool gets a boolean environment variable or returns a default value
func getEnvBool(key string, defaultValue bool) bool {
if value := os.Getenv(key); value != "" {
if parsed, err := strconv.ParseBool(value); err == nil {
return parsed
}
}
return defaultValue
}
package health
import (
"encoding/json"
"net/http"
"time"
)
// Response represents a health check response
type Response struct {
Status string `json:"status"`
Timestamp time.Time `json:"timestamp"`
Version string `json:"version,omitempty"`
Checks []Check `json:"checks,omitempty"`
}
// Check represents an individual health check
type Check struct {
Name string `json:"name"`
Status string `json:"status"`
Error string `json:"error,omitempty"`
}
// Handler handles health check requests
type Handler struct {
version string
checks []HealthChecker
}
// HealthChecker interface for health checks
type HealthChecker interface {
Name() string
Check() error
}
// NewHandler creates a new health check handler
func NewHandler(version string) *Handler {
return &Handler{
version: version,
checks: make([]HealthChecker, 0),
}
}
// AddCheck adds a health checker
func (h *Handler) AddCheck(checker HealthChecker) {
h.checks = append(h.checks, checker)
}
// ServeHTTP implements http.Handler
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
response := Response{
Status: "ok",
Timestamp: time.Now().UTC(),
Version: h.version,
Checks: make([]Check, 0, len(h.checks)),
}
allHealthy := true
for _, checker := range h.checks {
check := Check{
Name: checker.Name(),
Status: "ok",
}
if err := checker.Check(); err != nil {
check.Status = "error"
check.Error = err.Error()
allHealthy = false
}
response.Checks = append(response.Checks, check)
}
if !allHealthy {
response.Status = "error"
w.WriteHeader(http.StatusServiceUnavailable)
} else {
w.WriteHeader(http.StatusOK)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// SimpleChecker is a basic health checker
type SimpleChecker struct {
name string
fn func() error
}
// NewSimpleChecker creates a new simple health checker
func NewSimpleChecker(name string, fn func() error) *SimpleChecker {
return &SimpleChecker{
name: name,
fn: fn,
}
}
// Name returns the checker name
func (c *SimpleChecker) Name() string {
return c.name
}
// Check performs the health check
func (c *SimpleChecker) Check() error {
return c.fn()
}
package server
import (
"context"
"fmt"
"log/slog"
"net"
"net/http"
"os"
"sync"
"time"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
"go-grpc-gateway-template/internal/config"
"go-grpc-gateway-template/internal/health"
helloworldpb "go-grpc-gateway-template/proto/helloworld"
)
// Server wraps gRPC and HTTP servers with configuration
type Server struct {
config *config.Config
logger *slog.Logger
grpcServer *grpc.Server
httpServer *http.Server
healthHandler *health.Handler
}
// New creates a new server instance
func New(cfg *config.Config) *Server {
// Setup logger
var handler slog.Handler
if cfg.Log.Format == "json" {
handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: parseLogLevel(cfg.Log.Level),
})
} else {
handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: parseLogLevel(cfg.Log.Level),
})
}
logger := slog.New(handler)
// Create health handler
healthHandler := health.NewHandler("1.0.0")
return &Server{
config: cfg,
logger: logger,
healthHandler: healthHandler,
}
}
// Start starts both gRPC and HTTP servers
func (s *Server) Start(ctx context.Context) error {
var wg sync.WaitGroup
errChan := make(chan error, 2)
// Start gRPC server
wg.Add(1)
go func() {
defer wg.Done()
if err := s.startGRPCServer(ctx); err != nil {
errChan <- fmt.Errorf("gRPC server error: %w", err)
}
}()
// Start HTTP server
wg.Add(1)
go func() {
defer wg.Done()
if err := s.startHTTPServer(ctx); err != nil && err != http.ErrServerClosed {
errChan <- fmt.Errorf("HTTP server error: %w", err)
}
}()
// Wait for servers to start
go func() {
wg.Wait()
close(errChan)
}()
// Return first error if any
return <-errChan
}
func (s *Server) startGRPCServer(ctx context.Context) error {
lis, err := net.Listen("tcp", ":"+s.config.Server.GRPCPort)
if err != nil {
return fmt.Errorf("failed to listen on port %s: %w", s.config.Server.GRPCPort, err)
}
s.grpcServer = grpc.NewServer()
// Register services
greeter := &GreeterService{}
helloworldpb.RegisterGreeterServer(s.grpcServer, greeter)
// Enable reflection for development
reflection.Register(s.grpcServer)
s.logger.Info("Starting gRPC server", "port", s.config.Server.GRPCPort)
return s.grpcServer.Serve(lis)
}
func (s *Server) startHTTPServer(ctx context.Context) error {
// Create gRPC client connection
conn, err := grpc.DialContext(
ctx,
"localhost:"+s.config.Server.GRPCPort,
grpc.WithBlock(),
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
return fmt.Errorf("failed to dial gRPC server: %w", err)
}
// Create gateway mux
gwMux := runtime.NewServeMux()
// Register gRPC gateway handlers
err = helloworldpb.RegisterGreeterHandler(ctx, gwMux, conn)
if err != nil {
return fmt.Errorf("failed to register gateway: %w", err)
}
// Create HTTP mux with health endpoint
mux := http.NewServeMux()
mux.Handle("/", gwMux)
mux.Handle("/health", s.healthHandler)
s.httpServer = &http.Server{
Addr: ":" + s.config.Server.HTTPPort,
Handler: mux,
ReadTimeout: 30 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 120 * time.Second,
}
s.logger.Info("Starting HTTP server", "port", s.config.Server.HTTPPort)
return s.httpServer.ListenAndServe()
}
// Shutdown gracefully shuts down the servers
func (s *Server) Shutdown(ctx context.Context) error {
s.logger.Info("Shutting down servers...")
var wg sync.WaitGroup
// Shutdown HTTP server
if s.httpServer != nil {
wg.Add(1)
go func() {
defer wg.Done()
if err := s.httpServer.Shutdown(ctx); err != nil {
s.logger.Error("HTTP server shutdown error", "error", err)
}
}()
}
// Shutdown gRPC server
if s.grpcServer != nil {
wg.Add(1)
go func() {
defer wg.Done()
s.grpcServer.GracefulStop()
}()
}
wg.Wait()
s.logger.Info("Servers stopped")
return nil
}
// GreeterService implements the helloworld.Greeter service
type GreeterService struct {
helloworldpb.UnimplementedGreeterServer
}
// SayHello implements the SayHello RPC method
func (g *GreeterService) SayHello(ctx context.Context, req *helloworldpb.HelloRequest) (*helloworldpb.HelloReply, error) {
return &helloworldpb.HelloReply{
Message: "Hello " + req.GetName(),
}, nil
}
func parseLogLevel(level string) slog.Level {
switch level {
case "debug":
return slog.LevelDebug
case "info":
return slog.LevelInfo
case "warn":
return slog.LevelWarn
case "error":
return slog.LevelError
default:
return slog.LevelInfo
}
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.7
// protoc (unknown)
// source: proto/helloworld/hello_world.proto
package helloworld
import (
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type HelloRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HelloRequest) Reset() {
*x = HelloRequest{}
mi := &file_proto_helloworld_hello_world_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HelloRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HelloRequest) ProtoMessage() {}
func (x *HelloRequest) ProtoReflect() protoreflect.Message {
mi := &file_proto_helloworld_hello_world_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
func (*HelloRequest) Descriptor() ([]byte, []int) {
return file_proto_helloworld_hello_world_proto_rawDescGZIP(), []int{0}
}
func (x *HelloRequest) GetName() string {
if x != nil {
return x.Name
}
return ""
}
type HelloReply struct {
state protoimpl.MessageState `protogen:"open.v1"`
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *HelloReply) Reset() {
*x = HelloReply{}
mi := &file_proto_helloworld_hello_world_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *HelloReply) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*HelloReply) ProtoMessage() {}
func (x *HelloReply) ProtoReflect() protoreflect.Message {
mi := &file_proto_helloworld_hello_world_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
func (*HelloReply) Descriptor() ([]byte, []int) {
return file_proto_helloworld_hello_world_proto_rawDescGZIP(), []int{1}
}
func (x *HelloReply) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
var File_proto_helloworld_hello_world_proto protoreflect.FileDescriptor
const file_proto_helloworld_hello_world_proto_rawDesc = "" +
"\n" +
"\"proto/helloworld/hello_world.proto\x12\n" +
"helloworld\x1a\x1cgoogle/api/annotations.proto\"\"\n" +
"\fHelloRequest\x12\x12\n" +
"\x04name\x18\x01 \x01(\tR\x04name\"&\n" +
"\n" +
"HelloReply\x12\x18\n" +
"\amessage\x18\x01 \x01(\tR\amessage2d\n" +
"\aGreeter\x12Y\n" +
"\bSayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x1b\x82\xd3\xe4\x93\x02\x15:\x01*\"\x10/v1/example/echoB+Z)go-grpc-gateway-template/proto/helloworldb\x06proto3"
var (
file_proto_helloworld_hello_world_proto_rawDescOnce sync.Once
file_proto_helloworld_hello_world_proto_rawDescData []byte
)
func file_proto_helloworld_hello_world_proto_rawDescGZIP() []byte {
file_proto_helloworld_hello_world_proto_rawDescOnce.Do(func() {
file_proto_helloworld_hello_world_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_helloworld_hello_world_proto_rawDesc), len(file_proto_helloworld_hello_world_proto_rawDesc)))
})
return file_proto_helloworld_hello_world_proto_rawDescData
}
var file_proto_helloworld_hello_world_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_proto_helloworld_hello_world_proto_goTypes = []any{
(*HelloRequest)(nil), // 0: helloworld.HelloRequest
(*HelloReply)(nil), // 1: helloworld.HelloReply
}
var file_proto_helloworld_hello_world_proto_depIdxs = []int32{
0, // 0: helloworld.Greeter.SayHello:input_type -> helloworld.HelloRequest
1, // 1: helloworld.Greeter.SayHello:output_type -> helloworld.HelloReply
1, // [1:2] is the sub-list for method output_type
0, // [0:1] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_proto_helloworld_hello_world_proto_init() }
func file_proto_helloworld_hello_world_proto_init() {
if File_proto_helloworld_hello_world_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_helloworld_hello_world_proto_rawDesc), len(file_proto_helloworld_hello_world_proto_rawDesc)),
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_proto_helloworld_hello_world_proto_goTypes,
DependencyIndexes: file_proto_helloworld_hello_world_proto_depIdxs,
MessageInfos: file_proto_helloworld_hello_world_proto_msgTypes,
}.Build()
File_proto_helloworld_hello_world_proto = out.File
file_proto_helloworld_hello_world_proto_goTypes = nil
file_proto_helloworld_hello_world_proto_depIdxs = nil
}
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: proto/helloworld/hello_world.proto
/*
Package helloworld is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package helloworld
import (
"context"
"errors"
"io"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
// Suppress "imported and not used" errors
var (
_ codes.Code
_ io.Reader
_ status.Status
_ = errors.New
_ = runtime.String
_ = utilities.NewDoubleArray
_ = metadata.Join
)
func request_Greeter_SayHello_0(ctx context.Context, marshaler runtime.Marshaler, client GreeterClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq HelloRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if req.Body != nil {
_, _ = io.Copy(io.Discard, req.Body)
}
msg, err := client.SayHello(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Greeter_SayHello_0(ctx context.Context, marshaler runtime.Marshaler, server GreeterServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var (
protoReq HelloRequest
metadata runtime.ServerMetadata
)
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.SayHello(ctx, &protoReq)
return msg, metadata, err
}
// RegisterGreeterHandlerServer registers the http handlers for service Greeter to "mux".
// UnaryRPC :call GreeterServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterGreeterHandlerFromEndpoint instead.
// GRPC interceptors will not work for this type of registration. To use interceptors, you must use the "runtime.WithMiddlewares" option in the "runtime.NewServeMux" call.
func RegisterGreeterHandlerServer(ctx context.Context, mux *runtime.ServeMux, server GreeterServer) error {
mux.Handle(http.MethodPost, pattern_Greeter_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/helloworld.Greeter/SayHello", runtime.WithHTTPPathPattern("/v1/example/echo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Greeter_SayHello_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Greeter_SayHello_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterGreeterHandlerFromEndpoint is same as RegisterGreeterHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterGreeterHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterGreeterHandler(ctx, mux, conn)
}
// RegisterGreeterHandler registers the http handlers for service Greeter to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterGreeterHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterGreeterHandlerClient(ctx, mux, NewGreeterClient(conn))
}
// RegisterGreeterHandlerClient registers the http handlers for service Greeter
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "GreeterClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "GreeterClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "GreeterClient" to call the correct interceptors. This client ignores the HTTP middlewares.
func RegisterGreeterHandlerClient(ctx context.Context, mux *runtime.ServeMux, client GreeterClient) error {
mux.Handle(http.MethodPost, pattern_Greeter_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/helloworld.Greeter/SayHello", runtime.WithHTTPPathPattern("/v1/example/echo"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Greeter_SayHello_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_Greeter_SayHello_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Greeter_SayHello_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "example", "echo"}, ""))
)
var (
forward_Greeter_SayHello_0 = runtime.ForwardResponseMessage
)
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc (unknown)
// source: proto/helloworld/hello_world.proto
package helloworld
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
Greeter_SayHello_FullMethodName = "/helloworld.Greeter/SayHello"
)
// GreeterClient is the client API for Greeter service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type GreeterClient interface {
SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error)
}
type greeterClient struct {
cc grpc.ClientConnInterface
}
func NewGreeterClient(cc grpc.ClientConnInterface) GreeterClient {
return &greeterClient{cc}
}
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(HelloReply)
err := c.cc.Invoke(ctx, Greeter_SayHello_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// GreeterServer is the server API for Greeter service.
// All implementations must embed UnimplementedGreeterServer
// for forward compatibility.
type GreeterServer interface {
SayHello(context.Context, *HelloRequest) (*HelloReply, error)
mustEmbedUnimplementedGreeterServer()
}
// UnimplementedGreeterServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedGreeterServer struct{}
func (UnimplementedGreeterServer) SayHello(context.Context, *HelloRequest) (*HelloReply, error) {
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
}
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {}
func (UnimplementedGreeterServer) testEmbeddedByValue() {}
// UnsafeGreeterServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to GreeterServer will
// result in compilation errors.
type UnsafeGreeterServer interface {
mustEmbedUnimplementedGreeterServer()
}
func RegisterGreeterServer(s grpc.ServiceRegistrar, srv GreeterServer) {
// If the following call pancis, it indicates UnimplementedGreeterServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Greeter_ServiceDesc, srv)
}
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(HelloRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(GreeterServer).SayHello(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Greeter_SayHello_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
}
return interceptor(ctx, in, info, handler)
}
// Greeter_ServiceDesc is the grpc.ServiceDesc for Greeter service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Greeter_ServiceDesc = grpc.ServiceDesc{
ServiceName: "helloworld.Greeter",
HandlerType: (*GreeterServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "SayHello",
Handler: _Greeter_SayHello_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "proto/helloworld/hello_world.proto",
}