Skip to content

Commit

Permalink
yet another attempt to handle stdio streams correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
oclaussen committed Aug 27, 2020
1 parent 833d946 commit 0ac8cb4
Showing 1 changed file with 51 additions and 29 deletions.
80 changes: 51 additions & 29 deletions pkg/runtime/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ package runtime
import (
"io"
"io/ioutil"
"net"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/stdcopy"
log "github.com/hashicorp/go-hclog"
dodo "github.com/dodo-cli/dodo-core/pkg/types"
log "github.com/hashicorp/go-hclog"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -38,40 +39,44 @@ func (c *ContainerRuntime) StreamContainer(id string, r io.Reader, w io.Writer)
if err != nil {
return err
}
defer closeStreamingConnection(attach.Conn)

if cw, ok := attach.Conn.(CloseWriter); ok {
defer func() {
if err := cw.CloseWrite(); err != nil {
log.L().Error("could not close streaming connection", "error", err)
}
}()
} else {
defer func() {
if err := attach.Conn.Close(); err != nil {
log.L().Error("could not close streaming connection", "error", err)
}
}()
}

if config.Config.Tty {
go func() {
if _, err := io.Copy(w, attach.Reader); err != nil {
log.L().Warn("could not copy container output", "error", err)
}
}()
} else {
// TODO: stderr
go func() {
if _, err := stdcopy.StdCopy(w, ioutil.Discard, attach.Reader); err != nil {
log.L().Warn("could not copy container output", "error", err)
}
}()
}
outputDone := make(chan error)
go func() {
if config.Config.Tty {
_, err := io.Copy(w, attach.Reader)
outputDone <- err
} else {
// TODO: stderr
_, err := stdcopy.StdCopy(w, ioutil.Discard, attach.Reader)
outputDone <- err
}
}()

inputDone := make(chan struct{})
go func() {
if _, err := io.Copy(attach.Conn, r); err != nil {
log.L().Warn("could not copy container input", "error", err)
}
closeStreamingConnection(attach.Conn)
close(inputDone)
}()

streamChan := make(chan error, 1)
go func() {
select {
case err := <-outputDone:
streamChan <- err
case <-inputDone:
select {
case err := <-outputDone:
streamChan <- err
case <-ctx.Done():
streamChan <- ctx.Err()
}
case <-ctx.Done():
streamChan <- ctx.Err()
}
}()

waitCh, errorCh := c.client.ContainerWait(ctx, id, container.WaitConditionRemoved)
Expand All @@ -80,6 +85,10 @@ func (c *ContainerRuntime) StreamContainer(id string, r io.Reader, w io.Writer)
return err
}

if err := <-streamChan; err != nil {
return err
}

select {
case resp := <-waitCh:
if resp.Error != nil {
Expand All @@ -106,6 +115,19 @@ func (c *ContainerRuntime) ResizeContainer(id string, height uint32, width uint3
)
}

func closeStreamingConnection(conn net.Conn) {
log.L().Info("closing writer")
if cw, ok := conn.(CloseWriter); ok {
if err := cw.CloseWrite(); err != nil {
log.L().Warn("could not close streaming connection", "error", err)
}
} else {
if err := conn.Close(); err != nil {
log.L().Warn("could not close streaming connection", "error", err)
}
}
}

// TODO there must be something easier
type CloseWriter interface {
CloseWrite() error
Expand Down

0 comments on commit 0ac8cb4

Please sign in to comment.