-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
121 lines (96 loc) · 2.79 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package g3server
import (
"context"
"net"
"net/http"
"strings"
"time"
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/credentials/insecure"
)
const readHeaderTimeout = 3 * time.Second
// Server gRPC 和 gRPC-Gateway 共用 port 的 server
type Server struct {
pipe *PipeListener
gRPCServer *grpc.Server
gwProxyMux *gwRuntime.ServeMux
httpServer *http.Server
}
type GatewayRegisterFunc func(ctx context.Context, mux *gwRuntime.ServeMux, conn *grpc.ClientConn) error
// New 建立一個新的 ggserver
func New(ctx context.Context, gs *grpc.Server, gwRegFunc GatewayRegisterFunc, optArgs ...Option) (s *Server, err error) {
opt := defaultg3SOption
for _, o := range optArgs {
o.apply(&opt)
}
pipe := ListenPipe()
// setting gRPC Dial
if opt.grpcDialOptList == nil {
opt.grpcDialOptList = make([]grpc.DialOption, 0, 2)
}
opt.grpcDialOptList = append(opt.grpcDialOptList,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithContextDialer(func(c context.Context, s string) (net.Conn, error) {
return pipe.DialContext(c, `pipe`, s)
}),
)
clientPipeConn, err := grpc.Dial(`pipe`, opt.grpcDialOptList...)
if err != nil {
return
}
// setting gRPC Gateway
proxyMux := gwRuntime.NewServeMux(opt.gwServeMuxOptList...)
if ctx == nil {
ctx = context.Background()
}
err = gwRegFunc(ctx, proxyMux, clientPipeConn)
if err != nil {
return
}
if opt.httpServer == nil {
opt.httpServer = &http.Server{
ReadHeaderTimeout: readHeaderTimeout,
}
}
s = &Server{
pipe: pipe,
gRPCServer: gs,
gwProxyMux: proxyMux,
httpServer: opt.httpServer,
}
s.httpServer.Handler = s
return s, nil
}
// ServeHTTP 實作 http.Handler
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.ProtoMajor == 2 && strings.Contains(r.Header.Get("Content-Type"), "application/grpc") {
s.gRPCServer.ServeHTTP(w, r) // application/grpc 直接給 gRPC 處理
} else {
s.gwProxyMux.ServeHTTP(w, r) // 非 gRPC 交給 gRPC-Gateway 處理
}
}
func (s *Server) startGRPCServer() {
go func() {
_ = s.gRPCServer.Serve(s.pipe)
}()
}
func (s *Server) Serve(l net.Listener) (err error) {
s.startGRPCServer()
// 配置 h2c
// gPRC 必須使用 http2 連線,但是內建的 http 並不支援非 TLS 的 HTTP2(h2c)
// 所以這裡得要配置 h2c,讓 gRPC 客戶端可以正常連線
var http2Server http2.Server
err = http2.ConfigureServer(s.httpServer, &http2Server)
if err != nil {
return
}
s.httpServer.Handler = h2c.NewHandler(s, &http2Server)
return s.httpServer.Serve(l)
}
func (s *Server) ServeTLS(l net.Listener, certFile, keyFile string) (err error) {
s.startGRPCServer()
return s.httpServer.ServeTLS(l, certFile, keyFile)
}