1042 lines
41 KiB
HTML
1042 lines
41 KiB
HTML
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<title>server: Go Coverage Report</title>
|
|
<style>
|
|
body {
|
|
background: black;
|
|
color: rgb(80, 80, 80);
|
|
}
|
|
body, pre, #legend span {
|
|
font-family: Menlo, monospace;
|
|
font-weight: bold;
|
|
}
|
|
#topbar {
|
|
background: black;
|
|
position: fixed;
|
|
top: 0; left: 0; right: 0;
|
|
height: 42px;
|
|
border-bottom: 1px solid rgb(80, 80, 80);
|
|
}
|
|
#content {
|
|
margin-top: 50px;
|
|
}
|
|
#nav, #legend {
|
|
float: left;
|
|
margin-left: 10px;
|
|
}
|
|
#legend {
|
|
margin-top: 12px;
|
|
}
|
|
#nav {
|
|
margin-top: 10px;
|
|
}
|
|
#legend span {
|
|
margin: 0 5px;
|
|
}
|
|
.cov0 { color: rgb(192, 0, 0) }
|
|
.cov1 { color: rgb(128, 128, 128) }
|
|
.cov2 { color: rgb(116, 140, 131) }
|
|
.cov3 { color: rgb(104, 152, 134) }
|
|
.cov4 { color: rgb(92, 164, 137) }
|
|
.cov5 { color: rgb(80, 176, 140) }
|
|
.cov6 { color: rgb(68, 188, 143) }
|
|
.cov7 { color: rgb(56, 200, 146) }
|
|
.cov8 { color: rgb(44, 212, 149) }
|
|
.cov9 { color: rgb(32, 224, 152) }
|
|
.cov10 { color: rgb(20, 236, 155) }
|
|
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="topbar">
|
|
<div id="nav">
|
|
<select id="files">
|
|
|
|
<option value="file0">go-grpc-gateway-template/cmd/server/main.go (0.0%)</option>
|
|
|
|
<option value="file1">go-grpc-gateway-template/internal/config/config.go (95.2%)</option>
|
|
|
|
<option value="file2">go-grpc-gateway-template/internal/health/health.go (100.0%)</option>
|
|
|
|
<option value="file3">go-grpc-gateway-template/internal/server/server.go (0.0%)</option>
|
|
|
|
<option value="file4">go-grpc-gateway-template/proto/helloworld/hello_world.pb.go (0.0%)</option>
|
|
|
|
<option value="file5">go-grpc-gateway-template/proto/helloworld/hello_world.pb.gw.go (0.0%)</option>
|
|
|
|
<option value="file6">go-grpc-gateway-template/proto/helloworld/hello_world_grpc.pb.go (0.0%)</option>
|
|
|
|
</select>
|
|
</div>
|
|
<div id="legend">
|
|
<span>not tracked</span>
|
|
|
|
<span class="cov0">not covered</span>
|
|
<span class="cov8">covered</span>
|
|
|
|
</div>
|
|
</div>
|
|
<div id="content">
|
|
|
|
<pre class="file" id="file0" style="display: none">package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"go-grpc-gateway-template/internal/config"
|
|
"go-grpc-gateway-template/internal/server"
|
|
)
|
|
|
|
func main() <span class="cov0" title="0">{
|
|
// Load configuration
|
|
cfg := config.Load()
|
|
if err := cfg.Validate(); err != nil </span><span class="cov0" title="0">{
|
|
log.Fatalf("Invalid configuration: %v", err)
|
|
}</span>
|
|
|
|
// Create server
|
|
<span class="cov0" title="0">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() </span><span class="cov0" title="0">{
|
|
<-sigChan
|
|
log.Println("Received shutdown signal")
|
|
cancel()
|
|
}</span>()
|
|
|
|
// Start server
|
|
<span class="cov0" title="0">if err := srv.Start(ctx); err != nil </span><span class="cov0" title="0">{
|
|
log.Printf("Server error: %v", err)
|
|
}</span>
|
|
|
|
// Shutdown server
|
|
<span class="cov0" title="0">if err := srv.Shutdown(context.Background()); err != nil </span><span class="cov0" title="0">{
|
|
log.Printf("Shutdown error: %v", err)
|
|
}</span>
|
|
}</pre>
|
|
|
|
<pre class="file" id="file1" style="display: none">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 <span class="cov8" title="1">{
|
|
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),
|
|
},
|
|
}
|
|
}</span>
|
|
|
|
// Validate validates the configuration
|
|
func (c *Config) Validate() error <span class="cov8" title="1">{
|
|
if c.Server.GRPCPort == "" </span><span class="cov8" title="1">{
|
|
return fmt.Errorf("gRPC port cannot be empty")
|
|
}</span>
|
|
<span class="cov8" title="1">if c.Server.HTTPPort == "" </span><span class="cov0" title="0">{
|
|
return fmt.Errorf("HTTP port cannot be empty")
|
|
}</span>
|
|
<span class="cov8" title="1">if c.Server.GRPCPort == c.Server.HTTPPort </span><span class="cov8" title="1">{
|
|
return fmt.Errorf("gRPC and HTTP ports cannot be the same")
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">validLogLevels := map[string]bool{
|
|
"debug": true,
|
|
"info": true,
|
|
"warn": true,
|
|
"error": true,
|
|
}
|
|
if !validLogLevels[c.Log.Level] </span><span class="cov8" title="1">{
|
|
return fmt.Errorf("invalid log level: %s", c.Log.Level)
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">validLogFormats := map[string]bool{
|
|
"json": true,
|
|
"text": true,
|
|
}
|
|
if !validLogFormats[c.Log.Format] </span><span class="cov8" title="1">{
|
|
return fmt.Errorf("invalid log format: %s", c.Log.Format)
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">return nil</span>
|
|
}
|
|
|
|
// getEnv gets an environment variable or returns a default value
|
|
func getEnv(key, defaultValue string) string <span class="cov8" title="1">{
|
|
if value := os.Getenv(key); value != "" </span><span class="cov8" title="1">{
|
|
return value
|
|
}</span>
|
|
<span class="cov8" title="1">return defaultValue</span>
|
|
}
|
|
|
|
// getEnvBool gets a boolean environment variable or returns a default value
|
|
func getEnvBool(key string, defaultValue bool) bool <span class="cov8" title="1">{
|
|
if value := os.Getenv(key); value != "" </span><span class="cov8" title="1">{
|
|
if parsed, err := strconv.ParseBool(value); err == nil </span><span class="cov8" title="1">{
|
|
return parsed
|
|
}</span>
|
|
}
|
|
<span class="cov8" title="1">return defaultValue</span>
|
|
}</pre>
|
|
|
|
<pre class="file" id="file2" style="display: none">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 <span class="cov8" title="1">{
|
|
return &Handler{
|
|
version: version,
|
|
checks: make([]HealthChecker, 0),
|
|
}
|
|
}</span>
|
|
|
|
// AddCheck adds a health checker
|
|
func (h *Handler) AddCheck(checker HealthChecker) <span class="cov8" title="1">{
|
|
h.checks = append(h.checks, checker)
|
|
}</span>
|
|
|
|
// ServeHTTP implements http.Handler
|
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) <span class="cov8" title="1">{
|
|
if r.Method != http.MethodGet </span><span class="cov8" title="1">{
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">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 </span><span class="cov8" title="1">{
|
|
check := Check{
|
|
Name: checker.Name(),
|
|
Status: "ok",
|
|
}
|
|
|
|
if err := checker.Check(); err != nil </span><span class="cov8" title="1">{
|
|
check.Status = "error"
|
|
check.Error = err.Error()
|
|
allHealthy = false
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">response.Checks = append(response.Checks, check)</span>
|
|
}
|
|
|
|
<span class="cov8" title="1">if !allHealthy </span><span class="cov8" title="1">{
|
|
response.Status = "error"
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
}</span> else<span class="cov8" title="1"> {
|
|
w.WriteHeader(http.StatusOK)
|
|
}</span>
|
|
|
|
<span class="cov8" title="1">w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)</span>
|
|
}
|
|
|
|
// 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 <span class="cov8" title="1">{
|
|
return &SimpleChecker{
|
|
name: name,
|
|
fn: fn,
|
|
}
|
|
}</span>
|
|
|
|
// Name returns the checker name
|
|
func (c *SimpleChecker) Name() string <span class="cov8" title="1">{
|
|
return c.name
|
|
}</span>
|
|
|
|
// Check performs the health check
|
|
func (c *SimpleChecker) Check() error <span class="cov8" title="1">{
|
|
return c.fn()
|
|
}</pre>
|
|
|
|
<pre class="file" id="file3" style="display: none">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 <span class="cov0" title="0">{
|
|
// Setup logger
|
|
var handler slog.Handler
|
|
if cfg.Log.Format == "json" </span><span class="cov0" title="0">{
|
|
handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: parseLogLevel(cfg.Log.Level),
|
|
})
|
|
}</span> else<span class="cov0" title="0"> {
|
|
handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: parseLogLevel(cfg.Log.Level),
|
|
})
|
|
}</span>
|
|
<span class="cov0" title="0">logger := slog.New(handler)
|
|
|
|
// Create health handler
|
|
healthHandler := health.NewHandler("1.0.0")
|
|
|
|
return &Server{
|
|
config: cfg,
|
|
logger: logger,
|
|
healthHandler: healthHandler,
|
|
}</span>
|
|
}
|
|
|
|
// Start starts both gRPC and HTTP servers
|
|
func (s *Server) Start(ctx context.Context) error <span class="cov0" title="0">{
|
|
var wg sync.WaitGroup
|
|
errChan := make(chan error, 2)
|
|
|
|
// Start gRPC server
|
|
wg.Add(1)
|
|
go func() </span><span class="cov0" title="0">{
|
|
defer wg.Done()
|
|
if err := s.startGRPCServer(ctx); err != nil </span><span class="cov0" title="0">{
|
|
errChan <- fmt.Errorf("gRPC server error: %w", err)
|
|
}</span>
|
|
}()
|
|
|
|
// Start HTTP server
|
|
<span class="cov0" title="0">wg.Add(1)
|
|
go func() </span><span class="cov0" title="0">{
|
|
defer wg.Done()
|
|
if err := s.startHTTPServer(ctx); err != nil && err != http.ErrServerClosed </span><span class="cov0" title="0">{
|
|
errChan <- fmt.Errorf("HTTP server error: %w", err)
|
|
}</span>
|
|
}()
|
|
|
|
// Wait for servers to start
|
|
<span class="cov0" title="0">go func() </span><span class="cov0" title="0">{
|
|
wg.Wait()
|
|
close(errChan)
|
|
}</span>()
|
|
|
|
// Return first error if any
|
|
<span class="cov0" title="0">return <-errChan</span>
|
|
}
|
|
|
|
func (s *Server) startGRPCServer(ctx context.Context) error <span class="cov0" title="0">{
|
|
lis, err := net.Listen("tcp", ":"+s.config.Server.GRPCPort)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
return fmt.Errorf("failed to listen on port %s: %w", s.config.Server.GRPCPort, err)
|
|
}</span>
|
|
|
|
<span class="cov0" title="0">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)</span>
|
|
}
|
|
|
|
func (s *Server) startHTTPServer(ctx context.Context) error <span class="cov0" title="0">{
|
|
// Create gRPC client connection
|
|
conn, err := grpc.DialContext(
|
|
ctx,
|
|
"localhost:"+s.config.Server.GRPCPort,
|
|
grpc.WithBlock(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
return fmt.Errorf("failed to dial gRPC server: %w", err)
|
|
}</span>
|
|
|
|
// Create gateway mux
|
|
<span class="cov0" title="0">gwMux := runtime.NewServeMux()
|
|
|
|
// Register gRPC gateway handlers
|
|
err = helloworldpb.RegisterGreeterHandler(ctx, gwMux, conn)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
return fmt.Errorf("failed to register gateway: %w", err)
|
|
}</span>
|
|
|
|
// Create HTTP mux with health endpoint
|
|
<span class="cov0" title="0">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()</span>
|
|
}
|
|
|
|
// Shutdown gracefully shuts down the servers
|
|
func (s *Server) Shutdown(ctx context.Context) error <span class="cov0" title="0">{
|
|
s.logger.Info("Shutting down servers...")
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// Shutdown HTTP server
|
|
if s.httpServer != nil </span><span class="cov0" title="0">{
|
|
wg.Add(1)
|
|
go func() </span><span class="cov0" title="0">{
|
|
defer wg.Done()
|
|
if err := s.httpServer.Shutdown(ctx); err != nil </span><span class="cov0" title="0">{
|
|
s.logger.Error("HTTP server shutdown error", "error", err)
|
|
}</span>
|
|
}()
|
|
}
|
|
|
|
// Shutdown gRPC server
|
|
<span class="cov0" title="0">if s.grpcServer != nil </span><span class="cov0" title="0">{
|
|
wg.Add(1)
|
|
go func() </span><span class="cov0" title="0">{
|
|
defer wg.Done()
|
|
s.grpcServer.GracefulStop()
|
|
}</span>()
|
|
}
|
|
|
|
<span class="cov0" title="0">wg.Wait()
|
|
s.logger.Info("Servers stopped")
|
|
return nil</span>
|
|
}
|
|
|
|
// 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) <span class="cov0" title="0">{
|
|
return &helloworldpb.HelloReply{
|
|
Message: "Hello " + req.GetName(),
|
|
}, nil
|
|
}</span>
|
|
|
|
func parseLogLevel(level string) slog.Level <span class="cov0" title="0">{
|
|
switch level </span>{
|
|
case "debug":<span class="cov0" title="0">
|
|
return slog.LevelDebug</span>
|
|
case "info":<span class="cov0" title="0">
|
|
return slog.LevelInfo</span>
|
|
case "warn":<span class="cov0" title="0">
|
|
return slog.LevelWarn</span>
|
|
case "error":<span class="cov0" title="0">
|
|
return slog.LevelError</span>
|
|
default:<span class="cov0" title="0">
|
|
return slog.LevelInfo</span>
|
|
}
|
|
}</pre>
|
|
|
|
<pre class="file" id="file4" style="display: none">// 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() <span class="cov0" title="0">{
|
|
*x = HelloRequest{}
|
|
mi := &file_proto_helloworld_hello_world_proto_msgTypes[0]
|
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
ms.StoreMessageInfo(mi)
|
|
}</span>
|
|
|
|
func (x *HelloRequest) String() string <span class="cov0" title="0">{
|
|
return protoimpl.X.MessageStringOf(x)
|
|
}</span>
|
|
|
|
func (*HelloRequest) ProtoMessage() {<span class="cov0" title="0">}</span>
|
|
|
|
func (x *HelloRequest) ProtoReflect() protoreflect.Message <span class="cov0" title="0">{
|
|
mi := &file_proto_helloworld_hello_world_proto_msgTypes[0]
|
|
if x != nil </span><span class="cov0" title="0">{
|
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
if ms.LoadMessageInfo() == nil </span><span class="cov0" title="0">{
|
|
ms.StoreMessageInfo(mi)
|
|
}</span>
|
|
<span class="cov0" title="0">return ms</span>
|
|
}
|
|
<span class="cov0" title="0">return mi.MessageOf(x)</span>
|
|
}
|
|
|
|
// Deprecated: Use HelloRequest.ProtoReflect.Descriptor instead.
|
|
func (*HelloRequest) Descriptor() ([]byte, []int) <span class="cov0" title="0">{
|
|
return file_proto_helloworld_hello_world_proto_rawDescGZIP(), []int{0}
|
|
}</span>
|
|
|
|
func (x *HelloRequest) GetName() string <span class="cov0" title="0">{
|
|
if x != nil </span><span class="cov0" title="0">{
|
|
return x.Name
|
|
}</span>
|
|
<span class="cov0" title="0">return ""</span>
|
|
}
|
|
|
|
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() <span class="cov0" title="0">{
|
|
*x = HelloReply{}
|
|
mi := &file_proto_helloworld_hello_world_proto_msgTypes[1]
|
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
ms.StoreMessageInfo(mi)
|
|
}</span>
|
|
|
|
func (x *HelloReply) String() string <span class="cov0" title="0">{
|
|
return protoimpl.X.MessageStringOf(x)
|
|
}</span>
|
|
|
|
func (*HelloReply) ProtoMessage() {<span class="cov0" title="0">}</span>
|
|
|
|
func (x *HelloReply) ProtoReflect() protoreflect.Message <span class="cov0" title="0">{
|
|
mi := &file_proto_helloworld_hello_world_proto_msgTypes[1]
|
|
if x != nil </span><span class="cov0" title="0">{
|
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
if ms.LoadMessageInfo() == nil </span><span class="cov0" title="0">{
|
|
ms.StoreMessageInfo(mi)
|
|
}</span>
|
|
<span class="cov0" title="0">return ms</span>
|
|
}
|
|
<span class="cov0" title="0">return mi.MessageOf(x)</span>
|
|
}
|
|
|
|
// Deprecated: Use HelloReply.ProtoReflect.Descriptor instead.
|
|
func (*HelloReply) Descriptor() ([]byte, []int) <span class="cov0" title="0">{
|
|
return file_proto_helloworld_hello_world_proto_rawDescGZIP(), []int{1}
|
|
}</span>
|
|
|
|
func (x *HelloReply) GetMessage() string <span class="cov0" title="0">{
|
|
if x != nil </span><span class="cov0" title="0">{
|
|
return x.Message
|
|
}</span>
|
|
<span class="cov0" title="0">return ""</span>
|
|
}
|
|
|
|
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 <span class="cov0" title="0">{
|
|
file_proto_helloworld_hello_world_proto_rawDescOnce.Do(func() </span><span class="cov0" title="0">{
|
|
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)))
|
|
}</span>)
|
|
<span class="cov0" title="0">return file_proto_helloworld_hello_world_proto_rawDescData</span>
|
|
}
|
|
|
|
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() <span class="cov0" title="0">{ file_proto_helloworld_hello_world_proto_init() }</span>
|
|
func file_proto_helloworld_hello_world_proto_init() <span class="cov0" title="0">{
|
|
if File_proto_helloworld_hello_world_proto != nil </span><span class="cov0" title="0">{
|
|
return
|
|
}</span>
|
|
<span class="cov0" title="0">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</span>
|
|
}
|
|
</pre>
|
|
|
|
<pre class="file" id="file5" style="display: none">// 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) <span class="cov0" title="0">{
|
|
var (
|
|
protoReq HelloRequest
|
|
metadata runtime.ServerMetadata
|
|
)
|
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) </span><span class="cov0" title="0">{
|
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
}</span>
|
|
<span class="cov0" title="0">if req.Body != nil </span><span class="cov0" title="0">{
|
|
_, _ = io.Copy(io.Discard, req.Body)
|
|
}</span>
|
|
<span class="cov0" title="0">msg, err := client.SayHello(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
|
return msg, metadata, err</span>
|
|
}
|
|
|
|
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) <span class="cov0" title="0">{
|
|
var (
|
|
protoReq HelloRequest
|
|
metadata runtime.ServerMetadata
|
|
)
|
|
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil && !errors.Is(err, io.EOF) </span><span class="cov0" title="0">{
|
|
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
}</span>
|
|
<span class="cov0" title="0">msg, err := server.SayHello(ctx, &protoReq)
|
|
return msg, metadata, err</span>
|
|
}
|
|
|
|
// 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 <span class="cov0" title="0">{
|
|
mux.Handle(http.MethodPost, pattern_Greeter_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) </span><span class="cov0" title="0">{
|
|
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 </span><span class="cov0" title="0">{
|
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
return
|
|
}</span>
|
|
<span class="cov0" title="0">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 </span><span class="cov0" title="0">{
|
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
|
return
|
|
}</span>
|
|
<span class="cov0" title="0">forward_Greeter_SayHello_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)</span>
|
|
})
|
|
|
|
<span class="cov0" title="0">return nil</span>
|
|
}
|
|
|
|
// 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) <span class="cov0" title="0">{
|
|
conn, err := grpc.NewClient(endpoint, opts...)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
return err
|
|
}</span>
|
|
<span class="cov0" title="0">defer func() </span><span class="cov0" title="0">{
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
if cerr := conn.Close(); cerr != nil </span><span class="cov0" title="0">{
|
|
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
|
|
}</span>
|
|
<span class="cov0" title="0">return</span>
|
|
}
|
|
<span class="cov0" title="0">go func() </span><span class="cov0" title="0">{
|
|
<-ctx.Done()
|
|
if cerr := conn.Close(); cerr != nil </span><span class="cov0" title="0">{
|
|
grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr)
|
|
}</span>
|
|
}()
|
|
}()
|
|
<span class="cov0" title="0">return RegisterGreeterHandler(ctx, mux, conn)</span>
|
|
}
|
|
|
|
// 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 <span class="cov0" title="0">{
|
|
return RegisterGreeterHandlerClient(ctx, mux, NewGreeterClient(conn))
|
|
}</span>
|
|
|
|
// 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 <span class="cov0" title="0">{
|
|
mux.Handle(http.MethodPost, pattern_Greeter_SayHello_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) </span><span class="cov0" title="0">{
|
|
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 </span><span class="cov0" title="0">{
|
|
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
return
|
|
}</span>
|
|
<span class="cov0" title="0">resp, md, err := request_Greeter_SayHello_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
|
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
|
return
|
|
}</span>
|
|
<span class="cov0" title="0">forward_Greeter_SayHello_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)</span>
|
|
})
|
|
<span class="cov0" title="0">return nil</span>
|
|
}
|
|
|
|
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
|
|
)
|
|
</pre>
|
|
|
|
<pre class="file" id="file6" style="display: none">// 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 <span class="cov0" title="0">{
|
|
return &greeterClient{cc}
|
|
}</span>
|
|
|
|
func (c *greeterClient) SayHello(ctx context.Context, in *HelloRequest, opts ...grpc.CallOption) (*HelloReply, error) <span class="cov0" title="0">{
|
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
out := new(HelloReply)
|
|
err := c.cc.Invoke(ctx, Greeter_SayHello_FullMethodName, in, out, cOpts...)
|
|
if err != nil </span><span class="cov0" title="0">{
|
|
return nil, err
|
|
}</span>
|
|
<span class="cov0" title="0">return out, nil</span>
|
|
}
|
|
|
|
// 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) <span class="cov0" title="0">{
|
|
return nil, status.Errorf(codes.Unimplemented, "method SayHello not implemented")
|
|
}</span>
|
|
func (UnimplementedGreeterServer) mustEmbedUnimplementedGreeterServer() {<span class="cov0" title="0">}</span>
|
|
func (UnimplementedGreeterServer) testEmbeddedByValue() {<span class="cov0" title="0">}</span>
|
|
|
|
// 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) <span class="cov0" title="0">{
|
|
// 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 </span><span class="cov0" title="0">{
|
|
t.testEmbeddedByValue()
|
|
}</span>
|
|
<span class="cov0" title="0">s.RegisterService(&Greeter_ServiceDesc, srv)</span>
|
|
}
|
|
|
|
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) <span class="cov0" title="0">{
|
|
in := new(HelloRequest)
|
|
if err := dec(in); err != nil </span><span class="cov0" title="0">{
|
|
return nil, err
|
|
}</span>
|
|
<span class="cov0" title="0">if interceptor == nil </span><span class="cov0" title="0">{
|
|
return srv.(GreeterServer).SayHello(ctx, in)
|
|
}</span>
|
|
<span class="cov0" title="0">info := &grpc.UnaryServerInfo{
|
|
Server: srv,
|
|
FullMethod: Greeter_SayHello_FullMethodName,
|
|
}
|
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) </span><span class="cov0" title="0">{
|
|
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
|
}</span>
|
|
<span class="cov0" title="0">return interceptor(ctx, in, info, handler)</span>
|
|
}
|
|
|
|
// 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",
|
|
}
|
|
</pre>
|
|
|
|
</div>
|
|
</body>
|
|
<script>
|
|
(function() {
|
|
var files = document.getElementById('files');
|
|
var visible;
|
|
files.addEventListener('change', onChange, false);
|
|
function select(part) {
|
|
if (visible)
|
|
visible.style.display = 'none';
|
|
visible = document.getElementById(part);
|
|
if (!visible)
|
|
return;
|
|
files.value = part;
|
|
visible.style.display = 'block';
|
|
location.hash = part;
|
|
}
|
|
function onChange() {
|
|
select(files.value);
|
|
window.scrollTo(0, 0);
|
|
}
|
|
if (location.hash != "") {
|
|
select(location.hash.substr(1));
|
|
}
|
|
if (!visible) {
|
|
select("file0");
|
|
}
|
|
})();
|
|
</script>
|
|
</html>
|