Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Properly handle wush error messages #31

Merged
merged 1 commit into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/coder/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (cmd *shellCmd) Run(fl *pflag.FlagSet) {

exitCode, err := runCommand(envName, command, args)
if err != nil {
flog.Fatal("run command: %v", err)
flog.Fatal("run command: %v Is it online?", err)
}
os.Exit(exitCode)
}
Expand Down
47 changes: 37 additions & 10 deletions wush/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package wush
import (
"context"
"encoding/base64"
"fmt"
"encoding/json"
"io"
"io/ioutil"

"golang.org/x/sync/errgroup"
"golang.org/x/xerrors"
Expand All @@ -15,11 +16,11 @@ import (
// Client converts a Wush connection into OS streams.
type Client struct {
statusPromise promise
exitCode uint8
err error
exitCode uint8
err error

conn *websocket.Conn
ctx context.Context
ctx context.Context

Stdin io.WriteCloser
Stdout io.Reader
Expand Down Expand Up @@ -89,17 +90,16 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
eg, ctx := errgroup.WithContext(ctx)

c := &Client{
Stdout: stdoutReader,
Stderr: stderrReader,
conn: conn,
ctx: ctx,
Stdout: stdoutReader,
Stderr: stderrReader,
conn: conn,
ctx: ctx,
statusPromise: newPromise(),
}
c.Stdin = &stdinWriter{
Client: c,
}


// We expect massive reads from some commands. Because we're streaming it's no big deal.
conn.SetReadLimit(1 << 40)

Expand Down Expand Up @@ -141,7 +141,17 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
exitCode <- uint8(exitCodeBuf[0])
return nil
default:
return fmt.Errorf("unexpected id %x", streamID[0])
// This probably means an error was returned.
errResp, err := ioutil.ReadAll(rdr)
if err != nil {
return xerrors.Errorf("read error msg: %w", err)
}

// Since we read the first byte to check the
// stream id, prepend it to the rest of the
// data.
errResp = append([]byte{streamID[0]}, errResp...)
return handleStreamError(errResp)
}
}
})
Expand All @@ -161,6 +171,23 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
return c
}

func handleStreamError(body []byte) error {
res := struct {
Error struct {
Msg string `json:"msg"`
Verbose string `json:"verbose"`
} `json:"error"`
}{}

err := json.Unmarshal(body, &res)
if err != nil {
// If it's not a JSON error just print response verbatim.
return xerrors.Errorf("unknown stream error: %s", string(body))
}

return xerrors.Errorf(res.Error.Msg)
}

// Wait returns the status code of the command, along
// with any error.
func (c *Client) Wait() (uint8, error) {
Expand Down