| package jsonstream |
| |
| import ( |
| "context" |
| "io" |
| |
| "github.com/docker/cli/cli/streams" |
| "github.com/moby/moby/api/types/jsonstream" |
| "github.com/moby/moby/client/pkg/jsonmessage" |
| ) |
| |
| type ( |
| JSONError = jsonstream.Error |
| JSONMessage = jsonstream.Message |
| JSONProgress = jsonstream.Progress |
| ) |
| |
| type ctxReader struct { |
| err chan error |
| r io.Reader |
| } |
| |
| func (r *ctxReader) Read(p []byte) (n int, err error) { |
| select { |
| case err = <-r.err: |
| return 0, err |
| default: |
| return r.r.Read(p) |
| } |
| } |
| |
| type Options func(*options) |
| |
| type options struct { |
| AuxCallback func(JSONMessage) |
| } |
| |
| func WithAuxCallback(cb func(JSONMessage)) Options { |
| return func(o *options) { |
| o.AuxCallback = cb |
| } |
| } |
| |
| // Display prints the JSON messages from the given reader to the given stream. |
| // |
| // It wraps the [jsonmessage.DisplayJSONMessagesStream] function to make it |
| // "context aware" and appropriately returns why the function was canceled. |
| // |
| // It returns an error if the context is canceled, but not if the input reader / stream is closed. |
| func Display(ctx context.Context, in io.Reader, stream *streams.Out, opts ...Options) error { |
| if ctx.Err() != nil { |
| return ctx.Err() |
| } |
| |
| reader := &ctxReader{err: make(chan error, 1), r: in} |
| stopFunc := context.AfterFunc(ctx, func() { reader.err <- ctx.Err() }) |
| defer stopFunc() |
| |
| o := options{} |
| for _, opt := range opts { |
| opt(&o) |
| } |
| |
| if err := jsonmessage.DisplayJSONMessagesStream(reader, stream, stream.FD(), stream.IsTerminal(), o.AuxCallback); err != nil { |
| return err |
| } |
| |
| return ctx.Err() |
| } |