github.com/btccom/go-micro/v2@v2.9.3/api/server/http/http.go (about)

     1  // Package http provides a http server with features; acme, cors, etc
     2  package http
     3  
     4  import (
     5  	"crypto/tls"
     6  	"net"
     7  	"net/http"
     8  	"os"
     9  	"sync"
    10  
    11  	"github.com/gorilla/handlers"
    12  	"github.com/btccom/go-micro/v2/api/server"
    13  	"github.com/btccom/go-micro/v2/api/server/cors"
    14  	"github.com/btccom/go-micro/v2/logger"
    15  )
    16  
    17  type httpServer struct {
    18  	mux  *http.ServeMux
    19  	opts server.Options
    20  
    21  	mtx     sync.RWMutex
    22  	address string
    23  	exit    chan chan error
    24  }
    25  
    26  func NewServer(address string, opts ...server.Option) server.Server {
    27  	var options server.Options
    28  	for _, o := range opts {
    29  		o(&options)
    30  	}
    31  
    32  	return &httpServer{
    33  		opts:    options,
    34  		mux:     http.NewServeMux(),
    35  		address: address,
    36  		exit:    make(chan chan error),
    37  	}
    38  }
    39  
    40  func (s *httpServer) Address() string {
    41  	s.mtx.RLock()
    42  	defer s.mtx.RUnlock()
    43  	return s.address
    44  }
    45  
    46  func (s *httpServer) Init(opts ...server.Option) error {
    47  	for _, o := range opts {
    48  		o(&s.opts)
    49  	}
    50  	return nil
    51  }
    52  
    53  func (s *httpServer) Handle(path string, handler http.Handler) {
    54  	// TODO: move this stuff out to one place with ServeHTTP
    55  
    56  	// apply the wrappers, e.g. auth
    57  	for _, wrapper := range s.opts.Wrappers {
    58  		handler = wrapper(handler)
    59  	}
    60  
    61  	// wrap with cors
    62  	if s.opts.EnableCORS {
    63  		handler = cors.CombinedCORSHandler(handler)
    64  	}
    65  
    66  	// wrap with logger
    67  	handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
    68  
    69  	s.mux.Handle(path, handler)
    70  }
    71  
    72  func (s *httpServer) Start() error {
    73  	var l net.Listener
    74  	var err error
    75  
    76  	if s.opts.EnableACME && s.opts.ACMEProvider != nil {
    77  		// should we check the address to make sure its using :443?
    78  		l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
    79  	} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
    80  		l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
    81  	} else {
    82  		// otherwise plain listen
    83  		l, err = net.Listen("tcp", s.address)
    84  	}
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	if logger.V(logger.InfoLevel, logger.DefaultLogger) {
    90  		logger.Infof("HTTP API Listening on %s", l.Addr().String())
    91  	}
    92  
    93  	s.mtx.Lock()
    94  	s.address = l.Addr().String()
    95  	s.mtx.Unlock()
    96  
    97  	go func() {
    98  		if err := http.Serve(l, s.mux); err != nil {
    99  			// temporary fix
   100  			//logger.Fatal(err)
   101  		}
   102  	}()
   103  
   104  	go func() {
   105  		ch := <-s.exit
   106  		ch <- l.Close()
   107  	}()
   108  
   109  	return nil
   110  }
   111  
   112  func (s *httpServer) Stop() error {
   113  	ch := make(chan error)
   114  	s.exit <- ch
   115  	return <-ch
   116  }
   117  
   118  func (s *httpServer) String() string {
   119  	return "http"
   120  }