github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/fast/transport.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package fast 19 20 import ( 21 "fmt" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/context" 24 "github.com/aacfactory/fns/transports" 25 "github.com/aacfactory/json" 26 "github.com/valyala/fasthttp" 27 ) 28 29 const ( 30 transportName = "fasthttp" 31 ) 32 33 type Http2Config struct { 34 Enable bool `json:"enable"` 35 PingSeconds int `json:"pingSeconds"` 36 MaxConcurrentStreams int `json:"maxConcurrentStreams"` 37 MaxResponseSeconds int `json:"maxResponseSeconds"` 38 } 39 40 type Config struct { 41 ReadBufferSize string `json:"readBufferSize"` 42 ReadTimeout string `json:"readTimeout"` 43 WriteBufferSize string `json:"writeBufferSize"` 44 WriteTimeout string `json:"writeTimeout"` 45 MaxIdleWorkerDuration string `json:"maxIdleWorkerDuration"` 46 TCPKeepalive bool `json:"tcpKeepalive"` 47 TCPKeepalivePeriod string `json:"tcpKeepalivePeriod"` 48 MaxRequestBodySize string `json:"maxRequestBodySize"` 49 ReduceMemoryUsage bool `json:"reduceMemoryUsage"` 50 MaxRequestsPerConn int `json:"maxRequestsPerConn"` 51 KeepHijackedConns bool `json:"keepHijackedConns"` 52 StreamRequestBody bool `json:"streamRequestBody"` 53 Prefork bool `json:"prefork"` 54 Http2 Http2Config `json:"http2"` 55 Client ClientConfig `json:"client"` 56 } 57 58 func New() transports.Transport { 59 return &Transport{} 60 } 61 62 type Transport struct { 63 server *Server 64 dialer *Dialer 65 } 66 67 func (tr *Transport) Name() (name string) { 68 name = transportName 69 return 70 } 71 72 func (tr *Transport) Construct(options transports.Options) (err error) { 73 // log 74 log := options.Log.With("transport", transportName) 75 // tls 76 tlsConfig, tlsConfigErr := options.Config.GetTLS() 77 if tlsConfigErr != nil { 78 err = errors.Warning("fns: fast transport construct failed").WithCause(tlsConfigErr).WithMeta("transport", transportName) 79 return 80 } 81 82 // handler 83 if options.Handler == nil { 84 err = errors.Warning("fns: fast transport construct failed").WithCause(fmt.Errorf("handler is nil")).WithMeta("transport", transportName) 85 return 86 } 87 88 // port 89 port, portErr := options.Config.GetPort() 90 if portErr != nil { 91 err = errors.Warning("fns: fast transport construct failed").WithCause(portErr).WithMeta("transport", transportName) 92 return 93 } 94 // config 95 optConfig, optConfigErr := options.Config.OptionsConfig() 96 if optConfigErr != nil { 97 err = errors.Warning("fns: fast transport construct failed").WithCause(optConfigErr).WithMeta("transport", transportName) 98 return 99 } 100 config := &Config{} 101 configErr := optConfig.As(config) 102 if configErr != nil { 103 err = errors.Warning("fns: fast transport construct failed").WithCause(configErr).WithMeta("transport", transportName) 104 return 105 } 106 // server 107 srv, srvErr := newServer(log, port, tlsConfig, config, options.Handler) 108 if srvErr != nil { 109 err = errors.Warning("fns: fast transport construct failed").WithCause(srvErr).WithMeta("transport", transportName) 110 return 111 } 112 tr.server = srv 113 114 // dialer 115 clientConfig := config.Client 116 if tlsConfig != nil { 117 cliTLS, dialer := tlsConfig.Client() 118 clientConfig.TLSConfig = cliTLS 119 clientConfig.http2 = ClientHttp2Config{ 120 Enabled: config.Http2.Enable, 121 PingSeconds: config.Http2.PingSeconds, 122 MaxResponseSeconds: config.Http2.MaxResponseSeconds, 123 } 124 if dialer != nil { 125 clientConfig.TLSDialer = dialer 126 } 127 } 128 dialer, dialerErr := NewDialer(clientConfig) 129 if dialerErr != nil { 130 err = errors.Warning("fns: fast transport construct failed").WithCause(dialerErr) 131 return 132 } 133 tr.dialer = dialer 134 return 135 } 136 137 func (tr *Transport) Dial(address []byte) (client transports.Client, err error) { 138 client, err = tr.dialer.Dial(address) 139 return 140 } 141 142 func (tr *Transport) Port() (port int) { 143 port = tr.server.port 144 return 145 } 146 147 func (tr *Transport) ListenAndServe() (err error) { 148 err = tr.server.ListenAndServe() 149 return 150 } 151 152 func (tr *Transport) Shutdown(ctx context.Context) { 153 tr.dialer.Close() 154 _ = tr.server.Shutdown(ctx) 155 return 156 } 157 158 // +-------------------------------------------------------------------------------------------------------------------+ 159 160 func errorHandler(ctx *fasthttp.RequestCtx, err error) { 161 ctx.SetStatusCode(555) 162 ctx.SetContentTypeBytes(transports.ContentTypeJsonHeaderValue) 163 p, _ := json.Marshal(errors.Warning("fns: transport receiving or parsing the request failed").WithCause(err).WithMeta("transport", transportName)) 164 ctx.SetBody(p) 165 }