feat: split all grpc and http endpoints

This commit is contained in:
2026-08-11 18:47:27 +08:00
parent 3ba0bafc37
commit 53e953c3fc
8 changed files with 435 additions and 31 deletions

View File

@@ -3,16 +3,14 @@ package server
import (
"bytes"
"context"
"errors"
"fmt"
"net"
"net/http"
"strings"
"time"
"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"
)
@@ -21,7 +19,8 @@ type Server struct {
GRPC *grpc.Server
Gateway *gwRuntime.ServeMux
HTTP *gin.Engine
server *http.Server
http *http.Server
dynamic *dynamicGateway
}
func New() *Server {
@@ -36,12 +35,26 @@ func New() *Server {
}
}
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
}
func (s *Server) Start(grpcAddr, httpAddr string, allow []string) error {
grpcListener, err := net.Listen("tcp", grpcAddr)
if err != nil {
return fmt.Errorf("listen gRPC on %s: %w", grpcAddr, err)
}
httpListener, err := net.Listen("tcp", httpAddr)
if err != nil {
_ = grpcListener.Close()
return fmt.Errorf("listen HTTP on %s: %w", httpAddr, err)
}
s.dynamic, err = newDynamicGateway(grpcAddr, allow)
if err != nil {
_ = grpcListener.Close()
_ = httpListener.Close()
return err
}
s.HTTP.POST("/rpc/:method", s.dynamic.handle)
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
recorder := newBufferedResponse()
s.Gateway.ServeHTTP(recorder, r)
if recorder.status != http.StatusNotFound {
@@ -49,20 +62,25 @@ func (s *Server) Start(addr string) error {
return
}
s.HTTP.ServeHTTP(w, r)
}), &http2.Server{})
s.server = &http.Server{
Addr: addr,
})
s.http = &http.Server{
Addr: httpAddr,
Handler: handler,
ReadHeaderTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
MaxHeaderBytes: 1 << 20,
}
listener, err := net.Listen("tcp", addr)
if err != nil {
return err
fmt.Printf("all gRPC services listening on %s\n", grpcAddr)
fmt.Printf("all HTTP services listening on %s\n", httpAddr)
errCh := make(chan error, 2)
go func() { errCh <- s.GRPC.Serve(grpcListener) }()
go func() { errCh <- s.http.Serve(httpListener) }()
serveErr := <-errCh
if errors.Is(serveErr, grpc.ErrServerStopped) || errors.Is(serveErr, http.ErrServerClosed) {
return http.ErrServerClosed
}
fmt.Printf("all services listening on %s (gRPC + HTTP)\n", addr)
return s.server.Serve(listener)
return serveErr
}
func (s *Server) Stop(ctx context.Context) error {
@@ -76,10 +94,13 @@ func (s *Server) Stop(ctx context.Context) error {
case <-ctx.Done():
s.GRPC.Stop()
}
if s.server == nil {
return ctx.Err()
if s.dynamic != nil {
_ = s.dynamic.Close()
}
return s.server.Shutdown(ctx)
if s.http == nil {
return nil
}
return s.http.Shutdown(ctx)
}
type bufferedResponse struct {