// Signallistener returns a net.Listener that will be closed when standard OS // stop signals are received. func SignalListener(port int) (net.Listener, error) { addr := ":" + fmt.Sprint(port) l, err := net.Listen("tcp", addr) if err != nil { log.Errorln("govtil/net: Failed to listen on", port, err) return nil, err } // Close listen port on signals (causes http.Serve() to return) signal.Go(func(s os.Signal) { log.Debugf("govtil/net: Closing listen port %v due to signal %v", l.Addr().String(), s) l.Close() }) return l, nil }
// 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 }