github.com/ActiveState/cli@v0.0.0-20240508170324-6801f60cd051/test/pseudo/cmd/internal/serve/serve.go (about)

     1  package serve
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"net/http"
    10  	"time"
    11  )
    12  
    13  type Serve struct {
    14  	h    *http.Server
    15  	errs chan error
    16  }
    17  
    18  func New() *Serve {
    19  	return &Serve{
    20  		h: &http.Server{
    21  			Handler: NewEndpoints(),
    22  		},
    23  	}
    24  }
    25  
    26  func (s *Serve) Run() (string, error) {
    27  	emsg := "serve run: %w"
    28  
    29  	l, err := net.Listen("tcp", "127.0.0.1:0")
    30  	if err != nil {
    31  		return "", fmt.Errorf(emsg, err)
    32  	}
    33  
    34  	if s.errs == nil {
    35  		s.errs = make(chan error)
    36  	}
    37  
    38  	go func() {
    39  		defer close(s.errs)
    40  		s.errs <- s.h.Serve(l)
    41  	}()
    42  
    43  	return l.Addr().String(), nil
    44  }
    45  
    46  func (s *Serve) Close() error {
    47  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
    48  	defer cancel()
    49  
    50  	if err := s.h.Shutdown(ctx); err != nil {
    51  		return err
    52  	}
    53  
    54  	if err := <-s.errs; err != nil && !errors.Is(err, http.ErrServerClosed) {
    55  		return err
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  var handleInfoPath = "/info"
    62  
    63  type Endpoints struct {
    64  	h http.Handler
    65  }
    66  
    67  func NewEndpoints() *Endpoints {
    68  	m := http.NewServeMux()
    69  	m.HandleFunc(handleInfoPath, handleInfo)
    70  
    71  	return &Endpoints{
    72  		h: m,
    73  	}
    74  }
    75  
    76  func (es *Endpoints) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    77  	es.h.ServeHTTP(w, r)
    78  }
    79  
    80  func handleInfo(w http.ResponseWriter, r *http.Request) {
    81  	fmt.Fprintln(w, "DATA")
    82  }
    83  
    84  type Client struct {
    85  	addr string
    86  	c    *http.Client
    87  }
    88  
    89  func NewClient(addr string) *Client {
    90  	return &Client{
    91  		addr: addr,
    92  		c:    &http.Client{},
    93  	}
    94  }
    95  
    96  func (c *Client) GetInfo() (string, error) {
    97  	r, err := c.c.Get("http://" + c.addr + handleInfoPath)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  	defer r.Body.Close()
   102  
   103  	body, err := io.ReadAll(r.Body)
   104  	if err != nil {
   105  		return "", err
   106  	}
   107  
   108  	return string(body), nil
   109  }