// Serve on a given port // // The server will log to the default logger and will gracefully terminate on // receipt of an interrupt or kill signal. // // The following URLs are defined: // / // /healthz // /varz // /streamz // /birpc // /debug/pprof // // Setting port to 0 will start the server on an ephemeral port. The assigned // port will be logged. func ServeForever(port int) error { l, err := vnet.SignalListener(port) if err != nil { log.Errorf("govtil/net/server: failed to open port: %v", err) return err } return ServeListenerForever(l) }
// Split a WriteCloser into 'n' WriteClosers. When all returned WriteClosers // have been Close()'d, then the underlying ReadCloser is also closed. func SplitWriteCloser(wc io.WriteCloser, n uint) []io.WriteCloser { var r []io.WriteCloser c := make(chan wop) cg := new(sync.WaitGroup) cg.Add(int(n)) for i := 0; i < int(n); i++ { wpx := &wproxy{ i, c, make(chan rp), cg, } r = append(r, wpx) } // Closer go func() { cg.Wait() wc.Close() }() // Write pump wpump := func() { var err error defer func() { if err != nil && err != io.EOF { log.Errorf("govtil/io/multiplex: wpump error: %v", err) } }() enc := gob.NewEncoder(wc) for { w, ok := <-c if !ok { err = nil return } if err = enc.Encode(uint(w.id)); err != nil { w.c <- rp{0, err} err = nil continue } if err = enc.Encode(w.b); err != nil { w.c <- rp{0, err} err = nil continue } w.c <- rp{len(w.b), nil} } } go wpump() return r }
// ServeListenerForever is the same as ServeForever except it uses the specified // listener. This is useful in testing when an ephemeral port should be used. func ServeListenerForever(l net.Listener) error { // Wrap with logger handler := logginghandler.New(http.DefaultServeMux, log.GetVerbosity()) _, aps, err := net.SplitHostPort(l.Addr().String()) if err != nil { log.Errorf("govtil/net/server: failed to get port - %v", err) } log.Printf("govtil/net/server: starting on port %v", aps) // Serve err = http.Serve(l, handler) if err != nil { if vnet.SocketClosed(err) { err = nil // closed due to signal, no error } else { log.Errorf("govtil/net/server: %v", err) } } log.Println("govtil/net/server: Terminating") return err }
// Split a ReadCloser into 'n' ReadClosers. When all returned ReadClosers have // been Close()'d, then the underlying ReadCloser is also closed. func SplitReadCloser(rc io.ReadCloser, n uint) []io.ReadCloser { var r []io.ReadCloser var w []io.WriteCloser cg := new(sync.WaitGroup) cg.Add(int(n)) for i := 0; i < int(n); i++ { rp, wp := io.Pipe() brp := bufio.NewReader(rp) w = append(w, wp) rpx := &rproxy{ i, rp, brp, cg, } r = append(r, rpx) } // Closer go func() { cg.Wait() rc.Close() }() // Read pump rpump := func() { var err error defer func() { if err != nil && err != io.EOF { log.Errorf("govtil/io/multiplex: rpump error: %v", err) } for i := 0; i < len(w); i++ { w[i].Close() } }() dec := gob.NewDecoder(rc) var chno uint var d []byte for { if err = dec.Decode(&chno); err != nil { return } if err = dec.Decode(&d); err != nil { return } if _, err = w[chno].Write(d); err != nil { if err == io.ErrClosedPipe { // closed sub-channel, keep serving other sub-channels log.Debugf("govtil/io/multiplex: sub-channel closed, dumping payload of len %v", len(d)) continue } else { // something wrong, stop log.Debugf("govtil/io/multiplex: failed to write received payload of length %v to pipe for channel %v", len(d), chno) return } } } } go rpump() return r }