@@ -3,8 +3,9 @@ package wush
3
3
import (
4
4
"context"
5
5
"encoding/base64"
6
- "fmt "
6
+ "encoding/json "
7
7
"io"
8
+ "io/ioutil"
8
9
9
10
"golang.org/x/sync/errgroup"
10
11
"golang.org/x/xerrors"
@@ -15,11 +16,11 @@ import (
15
16
// Client converts a Wush connection into OS streams.
16
17
type Client struct {
17
18
statusPromise promise
18
- exitCode uint8
19
- err error
19
+ exitCode uint8
20
+ err error
20
21
21
22
conn * websocket.Conn
22
- ctx context.Context
23
+ ctx context.Context
23
24
24
25
Stdin io.WriteCloser
25
26
Stdout io.Reader
@@ -89,17 +90,16 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
89
90
eg , ctx := errgroup .WithContext (ctx )
90
91
91
92
c := & Client {
92
- Stdout : stdoutReader ,
93
- Stderr : stderrReader ,
94
- conn : conn ,
95
- ctx : ctx ,
93
+ Stdout : stdoutReader ,
94
+ Stderr : stderrReader ,
95
+ conn : conn ,
96
+ ctx : ctx ,
96
97
statusPromise : newPromise (),
97
98
}
98
99
c .Stdin = & stdinWriter {
99
100
Client : c ,
100
101
}
101
102
102
-
103
103
// We expect massive reads from some commands. Because we're streaming it's no big deal.
104
104
conn .SetReadLimit (1 << 40 )
105
105
@@ -141,7 +141,17 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
141
141
exitCode <- uint8 (exitCodeBuf [0 ])
142
142
return nil
143
143
default :
144
- return fmt .Errorf ("unexpected id %x" , streamID [0 ])
144
+ // This probably means an error was returned.
145
+ errResp , err := ioutil .ReadAll (rdr )
146
+ if err != nil {
147
+ return xerrors .Errorf ("read error msg: %w" , err )
148
+ }
149
+
150
+ // Since we read the first byte to check the
151
+ // stream id, prepend it to the rest of the
152
+ // data.
153
+ errResp = append ([]byte {streamID [0 ]}, errResp ... )
154
+ return handleStreamError (errResp )
145
155
}
146
156
}
147
157
})
@@ -161,6 +171,23 @@ func NewClient(ctx context.Context, conn *websocket.Conn) *Client {
161
171
return c
162
172
}
163
173
174
+ func handleStreamError (body []byte ) error {
175
+ res := struct {
176
+ Error struct {
177
+ Msg string `json:"msg"`
178
+ Verbose string `json:"verbose"`
179
+ } `json:"error"`
180
+ }{}
181
+
182
+ err := json .Unmarshal (body , & res )
183
+ if err != nil {
184
+ // If it's not a JSON error just print response verbatim.
185
+ return xerrors .Errorf ("unknown stream error: %s" , string (body ))
186
+ }
187
+
188
+ return xerrors .Errorf (res .Error .Msg )
189
+ }
190
+
164
191
// Wait returns the status code of the command, along
165
192
// with any error.
166
193
func (c * Client ) Wait () (uint8 , error ) {
0 commit comments