github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/standard/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 standard
    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  	"net"
    30  	"net/http"
    31  	"strings"
    32  	"time"
    33  )
    34  
    35  func newServer(log logs.Logger, port int, tlsConfig ssl.Config, config *Config, handler transports.Handler) (srv *Server, err error) {
    36  	var srvTLS *tls.Config
    37  	var lnf ssl.ListenerFunc
    38  	if tlsConfig != nil {
    39  		srvTLS, lnf = tlsConfig.Server()
    40  	}
    41  
    42  	maxRequestHeaderSize := uint64(0)
    43  	if config.MaxRequestHeaderSize != "" {
    44  		maxRequestHeaderSize, err = bytex.ParseBytes(strings.TrimSpace(config.MaxRequestHeaderSize))
    45  		if err != nil {
    46  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("maxRequestHeaderSize is invalid").WithCause(err).WithMeta("hit", "format must be bytes"))
    47  			return
    48  		}
    49  	}
    50  	maxRequestBodySize := uint64(0)
    51  	if config.MaxRequestBodySize != "" {
    52  		maxRequestBodySize, err = bytex.ParseBytes(strings.TrimSpace(config.MaxRequestBodySize))
    53  		if err != nil {
    54  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("maxRequestBodySize is invalid").WithCause(err).WithMeta("hit", "format must be bytes"))
    55  			return
    56  		}
    57  	}
    58  	if maxRequestBodySize == 0 {
    59  		maxRequestBodySize = 4 * bytex.MEGABYTE
    60  	}
    61  	readTimeout := 10 * time.Second
    62  	if config.ReadTimeout != "" {
    63  		readTimeout, err = time.ParseDuration(strings.TrimSpace(config.ReadTimeout))
    64  		if err != nil {
    65  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("readTimeout is invalid").WithCause(err).WithMeta("hit", "format must time.Duration"))
    66  			return
    67  		}
    68  	}
    69  	readHeaderTimeout := 5 * time.Second
    70  	if config.ReadHeaderTimeout != "" {
    71  		readHeaderTimeout, err = time.ParseDuration(strings.TrimSpace(config.ReadHeaderTimeout))
    72  		if err != nil {
    73  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("readHeaderTimeout is invalid").WithCause(err).WithMeta("hit", "format must time.Duration"))
    74  			return
    75  		}
    76  	}
    77  	writeTimeout := 10 * time.Second
    78  	if config.WriteTimeout != "" {
    79  		writeTimeout, err = time.ParseDuration(strings.TrimSpace(config.WriteTimeout))
    80  		if err != nil {
    81  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("writeTimeout is invalid").WithCause(err).WithMeta("hit", "format must time.Duration"))
    82  			return
    83  		}
    84  	}
    85  	idleTimeout := 30 * time.Second
    86  	if config.IdleTimeout != "" {
    87  		idleTimeout, err = time.ParseDuration(strings.TrimSpace(config.IdleTimeout))
    88  		if err != nil {
    89  			err = errors.Warning("http: build server failed").WithCause(errors.Warning("idleTimeout is invalid").WithCause(err).WithMeta("hit", "format must time.Duration"))
    90  			return
    91  		}
    92  	}
    93  
    94  	server := &http.Server{
    95  		Addr:                         fmt.Sprintf(":%d", port),
    96  		Handler:                      HttpTransportHandlerAdaptor(handler, int(maxRequestBodySize), writeTimeout),
    97  		DisableGeneralOptionsHandler: false,
    98  		TLSConfig:                    srvTLS,
    99  		ReadTimeout:                  readTimeout,
   100  		ReadHeaderTimeout:            readHeaderTimeout,
   101  		WriteTimeout:                 writeTimeout,
   102  		IdleTimeout:                  idleTimeout,
   103  		MaxHeaderBytes:               int(maxRequestHeaderSize),
   104  		ErrorLog:                     logs.ConvertToStandardLogger(log, logs.DebugLevel, false),
   105  	}
   106  
   107  	srv = &Server{
   108  		port: port,
   109  		lnf:  lnf,
   110  		srv:  server,
   111  	}
   112  	return
   113  }
   114  
   115  type Server struct {
   116  	port int
   117  	lnf  ssl.ListenerFunc
   118  	srv  *http.Server
   119  }
   120  
   121  func (srv *Server) ListenAndServe() (err error) {
   122  	ln, lnErr := net.Listen("tcp", fmt.Sprintf(":%d", srv.port))
   123  	if lnErr != nil {
   124  		err = errors.Warning("fns: transport listen and serve failed").WithCause(lnErr)
   125  		return
   126  	}
   127  	if srv.lnf != nil {
   128  		ln = srv.lnf(ln)
   129  	}
   130  	if srv.srv.TLSConfig == nil {
   131  		err = srv.srv.Serve(ln)
   132  	} else {
   133  		err = srv.srv.ServeTLS(ln, "", "")
   134  	}
   135  	if err != nil {
   136  		err = errors.Warning("fns: transport listen and serve failed").WithCause(err).WithMeta("transport", transportName)
   137  		return
   138  	}
   139  	return
   140  }
   141  
   142  func (srv *Server) Shutdown(ctx context.Context) (err error) {
   143  	err = srv.srv.Shutdown(ctx)
   144  	if err != nil {
   145  		err = errors.Warning("fns: transport shutdown failed").WithCause(err).WithMeta("transport", transportName)
   146  	}
   147  	return
   148  }