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  }