refactor: add unified all service gateway

This commit is contained in:
2026-08-10 10:03:46 +08:00
parent 5ea45a76fe
commit f994b2de9c
143 changed files with 2853 additions and 2129 deletions

View File

@@ -0,0 +1,90 @@
package server
import (
"bytes"
"context"
"fmt"
"net"
"net/http"
"strings"
"github.com/gin-gonic/gin"
gwRuntime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
type Server struct {
GRPC *grpc.Server
Gateway *gwRuntime.ServeMux
HTTP *gin.Engine
server *http.Server
}
func New() *Server {
grpcServer := grpc.NewServer()
reflection.Register(grpcServer)
engine := gin.New()
engine.Use(gin.Logger(), gin.Recovery())
return &Server{
GRPC: grpcServer,
Gateway: gwRuntime.NewServeMux(),
HTTP: engine,
}
}
func (s *Server) Start(addr string) error {
handler := h2c.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 && strings.HasPrefix(r.Header.Get("Content-Type"), "application/grpc") {
s.GRPC.ServeHTTP(w, r)
return
}
recorder := newBufferedResponse()
s.Gateway.ServeHTTP(recorder, r)
if recorder.status != http.StatusNotFound {
recorder.flush(w)
return
}
s.HTTP.ServeHTTP(w, r)
}), &http2.Server{})
s.server = &http.Server{Addr: addr, Handler: handler}
listener, err := net.Listen("tcp", addr)
if err != nil {
return err
}
fmt.Printf("all services listening on %s (gRPC + HTTP)\n", addr)
return s.server.Serve(listener)
}
func (s *Server) Stop(ctx context.Context) error {
s.GRPC.GracefulStop()
if s.server == nil {
return nil
}
return s.server.Shutdown(ctx)
}
type bufferedResponse struct {
header http.Header
body bytes.Buffer
status int
}
func newBufferedResponse() *bufferedResponse {
return &bufferedResponse{header: make(http.Header), status: http.StatusOK}
}
func (r *bufferedResponse) Header() http.Header { return r.header }
func (r *bufferedResponse) WriteHeader(status int) { r.status = status }
func (r *bufferedResponse) Write(data []byte) (int, error) { return r.body.Write(data) }
func (r *bufferedResponse) flush(w http.ResponseWriter) {
for key, values := range r.header {
for _, value := range values {
w.Header().Add(key, value)
}
}
w.WriteHeader(r.status)
_, _ = w.Write(r.body.Bytes())
}

View File

@@ -0,0 +1,21 @@
package server
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
)
func TestHTTPRouterIsAvailable(t *testing.T) {
srv := New()
srv.HTTP.GET("/healthz", func(c *gin.Context) { c.Status(http.StatusNoContent) })
request := httptest.NewRequest(http.MethodGet, "/healthz", nil)
response := httptest.NewRecorder()
srv.HTTP.ServeHTTP(response, request)
if response.Code != http.StatusNoContent {
t.Fatalf("unexpected status: %d", response.Code)
}
}