15 files "github.com/ipfs/go-ipfs-files"
22 Opts map[string]string
24 Headers map[string]string
27 func NewRequest(ctx context.Context, url, command string, args ...string) *Request {
28 if !strings.HasPrefix(url, "http") {
32 opts := map[string]string{
34 "stream-channels": "true",
37 ApiBase: url + "/api/v0",
41 Headers: make(map[string]string),
45 type trailerReader struct {
49 func (r *trailerReader) Read(b []byte) (int, error) {
50 n, err := r.resp.Body.Read(b)
52 if e := r.resp.Trailer.Get("X-Stream-Error"); e != "" {
59 func (r *trailerReader) Close() error {
60 return r.resp.Body.Close()
63 type Response struct {
68 func (r *Response) Close() error {
70 // always drain output (response body)
71 _, err1 := io.Copy(ioutil.Discard, r.Output)
72 err2 := r.Output.Close()
83 func (r *Response) Decode(dec interface{}) error {
89 return json.NewDecoder(r.Output).Decode(dec)
98 func (e *Error) Error() string {
101 out = e.Command + ": "
104 out = fmt.Sprintf("%s%d: ", out, e.Code)
106 return out + e.Message
109 func (r *Request) Send(c *http.Client) (*Response, error) {
111 req, err := http.NewRequest("POST", url, r.Body)
116 // Add any headers that were supplied via the RequestBuilder.
117 for k, v := range r.Headers {
121 if fr, ok := r.Body.(*files.MultiFileReader); ok {
122 req.Header.Set("Content-Type", "multipart/form-data; boundary="+fr.Boundary())
123 req.Header.Set("Content-Disposition", "form-data; name=\"files\"")
126 resp, err := c.Do(req)
131 contentType := resp.Header.Get("Content-Type")
132 parts := strings.Split(contentType, ";")
133 contentType = parts[0]
135 nresp := new(Response)
137 nresp.Output = &trailerReader{resp}
138 if resp.StatusCode >= http.StatusBadRequest {
143 case resp.StatusCode == http.StatusNotFound:
144 e.Message = "command not found"
145 case contentType == "text/plain":
146 out, err := ioutil.ReadAll(resp.Body)
148 fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) read error: %s\n", resp.StatusCode, err)
150 e.Message = string(out)
151 case contentType == "application/json":
152 if err = json.NewDecoder(resp.Body).Decode(e); err != nil {
153 fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) unmarshall error: %s\n", resp.StatusCode, err)
156 fmt.Fprintf(os.Stderr, "ipfs-shell: warning! unhandled response (%d) encoding: %s", resp.StatusCode, contentType)
157 out, err := ioutil.ReadAll(resp.Body)
159 fmt.Fprintf(os.Stderr, "ipfs-shell: response (%d) read error: %s\n", resp.StatusCode, err)
161 e.Message = fmt.Sprintf("unknown ipfs-shell error encoding: %q - %q", contentType, out)
166 // drain body and close
167 io.Copy(ioutil.Discard, resp.Body)
174 func (r *Request) getURL() string {
176 values := make(url.Values)
177 for _, arg := range r.Args {
178 values.Add("arg", arg)
180 for k, v := range r.Opts {
184 return fmt.Sprintf("%s/%s?%s", r.ApiBase, r.Command, values.Encode())