github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/fast/server.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  	"crypto/tls"
    22  	"fmt"
    23  	"github.com/aacfactory/errors"
    24  	"github.com/aacfactory/fns/commons/bytex"
    25  	"github.com/aacfactory/fns/context"
    26  	"github.com/aacfactory/fns/transports"
    27  	"github.com/aacfactory/fns/transports/ssl"
    28  	"github.com/aacfactory/logs"
    29  	"github.com/dgrr/http2"
    30  	"github.com/valyala/fasthttp"
    31  	"github.com/valyala/fasthttp/prefork"
    32  	"net"
    33  	"strings"
    34  	"time"
    35  )
    36  
    37  func newServer(log logs.Logger, port int, tlsConfig ssl.Config, config *Config, handler transports.Handler) (srv *Server, err error) {
    38  	var srvTLS *tls.Config
    39  	var lnf ssl.ListenerFunc
    40  	if tlsConfig != nil {
    41  		srvTLS, lnf = tlsConfig.Server()
    42  	}
    43  
    44  	readBufferSize := uint64(0)
    45  	if config.ReadBufferSize != "" {
    46  		readBufferSize, err = bytex.ParseBytes(strings.TrimSpace(config.ReadBufferSize))
    47  		if err != nil {
    48  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("readBufferSize must be bytes format")).WithCause(err).WithMeta("transport", transportName)
    49  			return
    50  		}
    51  	}
    52  	readTimeout := 10 * time.Second
    53  	if config.ReadTimeout != "" {
    54  		readTimeout, err = time.ParseDuration(strings.TrimSpace(config.ReadTimeout))
    55  		if err != nil {
    56  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("readTimeout must be time.Duration format")).WithCause(err).WithMeta("transport", transportName)
    57  			return
    58  		}
    59  	}
    60  	writeBufferSize := uint64(0)
    61  	if config.WriteBufferSize != "" {
    62  		writeBufferSize, err = bytex.ParseBytes(strings.TrimSpace(config.WriteBufferSize))
    63  		if err != nil {
    64  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("writeBufferSize must be bytes format")).WithCause(err).WithMeta("transport", transportName)
    65  			return
    66  		}
    67  	}
    68  	writeTimeout := 10 * time.Second
    69  	if config.WriteTimeout != "" {
    70  		writeTimeout, err = time.ParseDuration(strings.TrimSpace(config.WriteTimeout))
    71  		if err != nil {
    72  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("writeTimeout must be time.Duration format")).WithCause(err).WithMeta("transport", transportName)
    73  			return
    74  		}
    75  	}
    76  	maxIdleWorkerDuration := time.Duration(0)
    77  	if config.MaxIdleWorkerDuration != "" {
    78  		maxIdleWorkerDuration, err = time.ParseDuration(strings.TrimSpace(config.MaxIdleWorkerDuration))
    79  		if err != nil {
    80  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("maxIdleWorkerDuration must be time.Duration format")).WithCause(err).WithMeta("transport", transportName)
    81  			return
    82  		}
    83  	}
    84  	tcpKeepalivePeriod := time.Duration(0)
    85  	if config.TCPKeepalivePeriod != "" {
    86  		tcpKeepalivePeriod, err = time.ParseDuration(strings.TrimSpace(config.TCPKeepalivePeriod))
    87  		if err != nil {
    88  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("tcpKeepalivePeriod must be time.Duration format")).WithCause(err).WithMeta("transport", transportName)
    89  			return
    90  		}
    91  	}
    92  
    93  	maxRequestBodySize := uint64(4 * bytex.MEGABYTE)
    94  	if config.MaxRequestBodySize != "" {
    95  		maxRequestBodySize, err = bytex.ParseBytes(strings.TrimSpace(config.MaxRequestBodySize))
    96  		if err != nil {
    97  			err = errors.Warning("fns: build server failed").WithCause(errors.Warning("maxRequestBodySize must be bytes format")).WithCause(err).WithMeta("transport", transportName)
    98  			return
    99  		}
   100  	}
   101  
   102  	reduceMemoryUsage := config.ReduceMemoryUsage
   103  
   104  	server := &fasthttp.Server{
   105  		Handler:                            handlerAdaptor(handler, writeTimeout),
   106  		ErrorHandler:                       errorHandler,
   107  		Name:                               "",
   108  		Concurrency:                        0,
   109  		ReadBufferSize:                     int(readBufferSize),
   110  		WriteBufferSize:                    int(writeBufferSize),
   111  		ReadTimeout:                        readTimeout,
   112  		WriteTimeout:                       writeTimeout,
   113  		MaxRequestsPerConn:                 config.MaxRequestsPerConn,
   114  		MaxIdleWorkerDuration:              maxIdleWorkerDuration,
   115  		TCPKeepalivePeriod:                 tcpKeepalivePeriod,
   116  		MaxRequestBodySize:                 int(maxRequestBodySize),
   117  		DisableKeepalive:                   false,
   118  		TCPKeepalive:                       config.TCPKeepalive,
   119  		ReduceMemoryUsage:                  reduceMemoryUsage,
   120  		GetOnly:                            false,
   121  		DisablePreParseMultipartForm:       true,
   122  		LogAllErrors:                       false,
   123  		SecureErrorLogMessage:              false,
   124  		DisableHeaderNamesNormalizing:      false,
   125  		SleepWhenConcurrencyLimitsExceeded: 10 * time.Second,
   126  		NoDefaultServerHeader:              true,
   127  		NoDefaultDate:                      false,
   128  		NoDefaultContentType:               false,
   129  		KeepHijackedConns:                  config.KeepHijackedConns,
   130  		CloseOnShutdown:                    true,
   131  		StreamRequestBody:                  config.StreamRequestBody,
   132  		ConnState:                          nil,
   133  		Logger:                             logs.ConvertToStandardLogger(log, logs.DebugLevel, false),
   134  		TLSConfig:                          srvTLS,
   135  	}
   136  	// http2
   137  	if config.Http2.Enable && srvTLS != nil {
   138  		http2.ConfigureServer(server, http2.ServerConfig{
   139  			PingInterval:         time.Duration(config.Http2.PingSeconds) * time.Second,
   140  			MaxConcurrentStreams: config.Http2.MaxConcurrentStreams,
   141  			Debug:                false,
   142  		})
   143  	}
   144  
   145  	srv = &Server{
   146  		port:    port,
   147  		preFork: config.Prefork,
   148  		lnf:     lnf,
   149  		srv:     server,
   150  	}
   151  	return
   152  }
   153  
   154  type Server struct {
   155  	port    int
   156  	preFork bool
   157  	lnf     ssl.ListenerFunc
   158  	srv     *fasthttp.Server
   159  }
   160  
   161  func (srv *Server) preforkServe(ln net.Listener) (err error) {
   162  	if srv.lnf != nil {
   163  		ln = srv.lnf(ln)
   164  	}
   165  	err = srv.srv.Serve(ln)
   166  	return
   167  }
   168  
   169  func (srv *Server) ListenAndServe() (err error) {
   170  	if srv.preFork {
   171  		pf := prefork.New(srv.srv)
   172  		pf.ServeFunc = srv.preforkServe
   173  		err = pf.ListenAndServe(fmt.Sprintf(":%d", srv.port))
   174  		if err != nil {
   175  			err = errors.Warning("fns: transport perfork listen and serve failed").WithCause(err)
   176  			return
   177  		}
   178  		return
   179  	}
   180  	ln, lnErr := net.Listen("tcp", fmt.Sprintf(":%d", srv.port))
   181  	if lnErr != nil {
   182  		err = errors.Warning("fns: transport listen and serve failed").WithCause(lnErr)
   183  		return
   184  	}
   185  	if srv.lnf != nil {
   186  		ln = srv.lnf(ln)
   187  	}
   188  	err = srv.srv.Serve(ln)
   189  	if err != nil {
   190  		err = errors.Warning("fns: transport listen and serve failed").WithCause(err).WithMeta("transport", transportName)
   191  		return
   192  	}
   193  	return
   194  }
   195  
   196  func (srv *Server) Shutdown(ctx context.Context) (err error) {
   197  	err = srv.srv.ShutdownWithContext(ctx)
   198  	if err != nil {
   199  		err = errors.Warning("fns: transport shutdown failed").WithCause(err).WithMeta("transport", transportName)
   200  	}
   201  	return
   202  }