gitlab.com/ignitionrobotics/web/ign-go@v1.0.0-rc4/net/server.go (about)

     1  package net
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
     8  	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
     9  	grpc_ctxtags "github.com/grpc-ecosystem/go-grpc-middleware/tags"
    10  	grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
    11  	grpc_validator "github.com/grpc-ecosystem/go-grpc-middleware/validator"
    12  	"google.golang.org/grpc"
    13  	"log"
    14  	"net"
    15  	"net/http"
    16  	"time"
    17  )
    18  
    19  // Server is a web server to listen to incoming requests. It supports different types of transport mechanisms used through Ignition Robotics projects.
    20  // It currently supports HTTP and gRPC servers.
    21  type Server struct {
    22  	// httpServer holds a group of HTTP servers. All these servers will be listening to different ports.
    23  	httpServers []*http.Server
    24  	// grpcServers holds a group of gRPC servers. All these servers will be listening in the same port.
    25  	grpcServers []*grpc.Server
    26  	// listener holds a reference to a TCP listener for gRPC servers.
    27  	// All gRPC servers will use this listener to listen for incoming requests.
    28  	listener net.Listener
    29  }
    30  
    31  // ListenAndServe starts listening for incoming requests for the different HTTP and gRPC servers.
    32  // Returns a channel that will receive an error from any of the current underlying transport mechanisms.
    33  // Each underlying server will be launched in a different go routine.
    34  func (s *Server) ListenAndServe() <-chan error {
    35  	errs := make(chan error, 1)
    36  
    37  	// Start HTTP servers
    38  	for _, srv := range s.httpServers {
    39  		go func(srv *http.Server, errs chan<- error) {
    40  			if err := srv.ListenAndServe(); err != nil {
    41  				errs <- err
    42  				close(errs)
    43  			}
    44  		}(srv, errs)
    45  	}
    46  
    47  	// Start gRPC servers
    48  	if s.grpcServers != nil && len(s.grpcServers) > 0 && s.listener == nil {
    49  		errs <- errors.New("a listener must be provided to the Server through an Option to support gRPC")
    50  		return errs
    51  	}
    52  	for _, srv := range s.grpcServers {
    53  		go func(srv *grpc.Server, listener net.Listener, errs chan<- error) {
    54  			if err := srv.Serve(listener); err != nil {
    55  				errs <- err
    56  				close(errs)
    57  			}
    58  		}(srv, s.listener, errs)
    59  	}
    60  
    61  	return errs
    62  }
    63  
    64  // Close gracefully closes all the underlying servers (HTTP & gRPC).
    65  func (s *Server) Close() {
    66  	for _, srv := range s.httpServers {
    67  		ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
    68  		if err := srv.Shutdown(ctx); err != nil {
    69  			log.Println("Failed to shutdown HTTP server:", err)
    70  		}
    71  		cancel()
    72  	}
    73  	for _, srv := range s.grpcServers {
    74  		srv.GracefulStop()
    75  	}
    76  }
    77  
    78  // Option contains logic that can be passed to a server in its initializer to modify it.
    79  type Option func(*Server) *Server
    80  
    81  // HTTP initializes a new HTTP server to serve endpoints defined in handler on a certain port.
    82  func HTTP(handler http.Handler, port uint) Option {
    83  	return func(s *Server) *Server {
    84  		s.httpServers = append(s.httpServers, &http.Server{
    85  			Handler: handler,
    86  			Addr:    fmt.Sprintf(":%d", port),
    87  		})
    88  
    89  		return s
    90  	}
    91  }
    92  
    93  // GRPC initializes and adds a new gRPC server to the Server.
    94  // Multiple gRPC servers use the same ListenerTCP. ListenerTCP is required if this Option is passed.
    95  // A set of gRPC options are passed as a function in order to inject custom middlewares to the gRPC server.
    96  // DefaultServerOptionsGRPC contains a set of basic middlewares to use in any application, but we encourage you to create or extend
    97  // your own opts function.
    98  func GRPC(register func(s grpc.ServiceRegistrar), opts []grpc.ServerOption) Option {
    99  	return func(s *Server) *Server {
   100  		grpcServer := newGRPC(opts)
   101  		register(grpcServer)
   102  		s.grpcServers = append(s.grpcServers, grpcServer)
   103  
   104  		return s
   105  	}
   106  }
   107  
   108  // DefaultServerOptionsGRPC is a predefined set of gRPC server options that can be used by any Server when calling the GRPC function.
   109  // We encourage you to create or extend your own opts function taking this one as a starting point.
   110  func DefaultServerOptionsGRPC() []grpc.ServerOption {
   111  	return []grpc.ServerOption{
   112  		grpc.StreamInterceptor(
   113  			grpc_middleware.ChainStreamServer(
   114  				grpc_ctxtags.StreamServerInterceptor(),
   115  				grpc_opentracing.StreamServerInterceptor(),
   116  				grpc_recovery.StreamServerInterceptor(),
   117  				grpc_validator.StreamServerInterceptor(),
   118  			),
   119  		),
   120  		grpc.UnaryInterceptor(
   121  			grpc_middleware.ChainUnaryServer(
   122  				grpc_ctxtags.UnaryServerInterceptor(),
   123  				grpc_opentracing.UnaryServerInterceptor(),
   124  				grpc_recovery.UnaryServerInterceptor(),
   125  				grpc_validator.UnaryServerInterceptor(),
   126  			),
   127  		),
   128  	}
   129  }
   130  
   131  // newGRPC initializes a new gRPC server and uses the options received from calling opts().
   132  func newGRPC(opts []grpc.ServerOption) *grpc.Server {
   133  	return grpc.NewServer(
   134  		opts...,
   135  	)
   136  }
   137  
   138  // ListenerTCP initializes a new Listener for server.
   139  // This Option is required for GRPC servers when registered in Server.
   140  func ListenerTCP(port uint) Option {
   141  	return func(s *Server) *Server {
   142  		var err error
   143  		s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", port))
   144  		if err != nil {
   145  			panic(fmt.Sprintf("failed to initialize listener: %s", err))
   146  		}
   147  		return s
   148  	}
   149  }
   150  
   151  // NewServer initializes a new server.
   152  func NewServer(opts ...Option) *Server {
   153  	var s Server
   154  	for _, o := range opts {
   155  		o(&s)
   156  	}
   157  
   158  	return &s
   159  }
   160  
   161  // ServiceRegistrator registers a gRPC service in a gRPC server.
   162  type ServiceRegistrator interface {
   163  	// Register registers the current service into the given server.
   164  	Register(s grpc.ServiceRegistrar)
   165  }