use a io.ReadCloser instead of io.Reader so we can shut down read channel gracefully