OSDN Git Service

add ipfs package
[bytom/vapor.git] / vendor / github.com / ipfs / go-ipfs-api / request.go
diff --git a/vendor/github.com/ipfs/go-ipfs-api/request.go b/vendor/github.com/ipfs/go-ipfs-api/request.go
new file mode 100644 (file)
index 0000000..a87d8a3
--- /dev/null
@@ -0,0 +1,185 @@
+package shell
+
+import (
+       "context"
+       "encoding/json"
+       "errors"
+       "fmt"
+       "io"
+       "io/ioutil"
+       "net/http"
+       "net/url"
+       "os"
+       "strings"
+
+       files "github.com/ipfs/go-ipfs-files"
+)
+
+type Request struct {
+       ApiBase string
+       Command string
+       Args    []string
+       Opts    map[string]string
+       Body    io.Reader
+       Headers map[string]string
+}
+
+func NewRequest(ctx context.Context, url, command string, args ...string) *Request {
+       if !strings.HasPrefix(url, "http") {
+               url = "http://" + url
+       }
+
+       opts := map[string]string{
+               "encoding":        "json",
+               "stream-channels": "true",
+       }
+       return &Request{
+               ApiBase: url + "/api/v0",
+               Command: command,
+               Args:    args,
+               Opts:    opts,
+               Headers: make(map[string]string),
+       }
+}
+
+type trailerReader struct {
+       resp *http.Response
+}
+
+func (r *trailerReader) Read(b []byte) (int, error) {
+       n, err := r.resp.Body.Read(b)
+       if err != nil {
+               if e := r.resp.Trailer.Get("X-Stream-Error"); e != "" {
+                       err = errors.New(e)
+               }
+       }
+       return n, err
+}
+
+func (r *trailerReader) Close() error {
+       return r.resp.Body.Close()
+}
+
+type Response struct {
+       Output io.ReadCloser
+       Error  *Error
+}
+
+func (r *Response) Close() error {
+       if r.Output != nil {
+               // always drain output (response body)
+               _, err1 := io.Copy(ioutil.Discard, r.Output)
+               err2 := r.Output.Close()
+               if err1 != nil {
+                       return err1
+               }
+               if err2 != nil {
+                       return err2
+               }
+       }
+       return nil
+}
+
+func (r *Response) Decode(dec interface{}) error {
+       defer r.Close()
+       if r.Error != nil {
+               return r.Error
+       }
+
+       return json.NewDecoder(r.Output).Decode(dec)
+}
+
+type Error struct {
+       Command string
+       Message string
+       Code    int
+}
+
+func (e *Error) Error() string {
+       var out string
+       if e.Command != "" {
+               out = e.Command + ": "
+       }
+       if e.Code != 0 {
+               out = fmt.Sprintf("%s%d: ", out, e.Code)
+       }
+       return out + e.Message
+}
+
+func (r *Request) Send(c *http.Client) (*Response, error) {
+       url := r.getURL()
+       req, err := http.NewRequest("POST", url, r.Body)
+       if err != nil {
+               return nil, err
+       }
+
+       // Add any headers that were supplied via the RequestBuilder.
+       for k, v := range r.Headers {
+               req.Header.Add(k, v)
+       }
+
+       if fr, ok := r.Body.(*files.MultiFileReader); ok {
+               req.Header.Set("Content-Type", "multipart/form-data; boundary="+fr.Boundary())
+               req.Header.Set("Content-Disposition", "form-data; name=\"files\"")
+       }
+
+       resp, err := c.Do(req)
+       if err != nil {
+               return nil, err
+       }
+
+       contentType := resp.Header.Get("Content-Type")
+       parts := strings.Split(contentType, ";")
+       contentType = parts[0]
+
+       nresp := new(Response)
+
+       nresp.Output = &trailerReader{resp}
+       if resp.StatusCode >= http.StatusBadRequest {
+               e := &Error{
+                       Command: r.Command,
+               }
+               switch {
+               case resp.StatusCode == http.StatusNotFound:
+                       e.Message = "command not found"
+               case contentType == "text/plain":
+                       out, err := ioutil.ReadAll(resp.Body)
+                       if err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) read error: %s\n", resp.StatusCode, err)
+                       }
+                       e.Message = string(out)
+               case contentType == "application/json":
+                       if err = json.NewDecoder(resp.Body).Decode(e); err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: warning! response (%d) unmarshall error: %s\n", resp.StatusCode, err)
+                       }
+               default:
+                       fmt.Fprintf(os.Stderr, "ipfs-shell: warning! unhandled response (%d) encoding: %s", resp.StatusCode, contentType)
+                       out, err := ioutil.ReadAll(resp.Body)
+                       if err != nil {
+                               fmt.Fprintf(os.Stderr, "ipfs-shell: response (%d) read error: %s\n", resp.StatusCode, err)
+                       }
+                       e.Message = fmt.Sprintf("unknown ipfs-shell error encoding: %q - %q", contentType, out)
+               }
+               nresp.Error = e
+               nresp.Output = nil
+
+               // drain body and close
+               io.Copy(ioutil.Discard, resp.Body)
+               resp.Body.Close()
+       }
+
+       return nresp, nil
+}
+
+func (r *Request) getURL() string {
+
+       values := make(url.Values)
+       for _, arg := range r.Args {
+               values.Add("arg", arg)
+       }
+       for k, v := range r.Opts {
+               values.Add(k, v)
+       }
+
+       return fmt.Sprintf("%s/%s?%s", r.ApiBase, r.Command, values.Encode())
+}