vidispine/VSRequestor.go (108 lines of code) (raw):

package vidispine import ( "crypto/tls" "encoding/base64" "errors" "fmt" "io" "io/ioutil" "log" "net" "net/http" "net/url" "strings" "time" ) type VSRequestor struct { url url.URL auth string client http.Client } /** initialise a new VSRequestor object */ func NewVSRequestor(url url.URL, user string, passwd string) *VSRequestor { tlsConfig := &tls.Config{} tlsConfig.InsecureSkipVerify = true var transport http.RoundTripper = &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, TLSClientConfig: tlsConfig, // Set this value so that the underlying transport round-tripper // doesn't try to auto decode the body of objects with // content-encoding set to `gzip`. // // Refer: // https://golang.org/src/net/http/transport.go?h=roundTrip#L1843 DisableCompression: true, } authpart := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", user, passwd))) computedAuthString := fmt.Sprintf("Basic %s", authpart) return &VSRequestor{ url: url, auth: computedAuthString, client: http.Client{ Transport: transport, }, } } func (r *VSRequestor) url_to_call(subpath string) (*url.URL, error) { var urlToCall url.URL if strings.Contains(subpath, "://") { parsed_url, url_err := url.Parse(subpath) if url_err != nil { return nil, url_err } if parsed_url.Host != r.url.Host { return nil, errors.New("Absolute URL was not to the designated Vidispine host") } urlToCall = r.url urlToCall.Path = parsed_url.Path } else { urlToCall = r.url urlToCall.Path = subpath } return &urlToCall, nil } func (r *VSRequestor) Do(method string, subpath string, accept string, bodyContentType string, body io.Reader) (io.ReadCloser, error) { urlToCall, url_err := r.url_to_call(subpath) if url_err != nil { return nil, url_err } log.Printf("Performing %s to %s", method, urlToCall.String()) req, _ := http.NewRequest(method, urlToCall.String(), body) req.Header.Add("Authorization", r.auth) req.Header.Add("Accept", accept) if bodyContentType != "" { req.Header.Add("Content-Type", bodyContentType) } resp, err := r.client.Do(req) if err != nil { return nil, err } if resp.StatusCode == 200 { return resp.Body, nil } bodyContent, readErr := ioutil.ReadAll(resp.Body) if readErr != nil { return nil, errors.New(fmt.Sprintf("Server returned a %d but could not read the result because of %s", resp.StatusCode, readErr)) } switch resp.StatusCode { case 400: fallthrough case 500: return nil, errors.New(string(bodyContent)) case 503: fallthrough case 504: log.Print("Server is not responding, retrying after a few seconds...") time.Sleep(5 * time.Second) return r.Do(method, subpath, accept, bodyContentType, body) default: return nil, errors.New(fmt.Sprintf("Unexpected error code %d, server said %s", resp.StatusCode, string(bodyContent))) } } func (r *VSRequestor) Get(subpath string, contentType string) (io.ReadCloser, error) { return r.Do("GET", subpath, contentType, "", nil) } func (r *VSRequestor) Post(subpath string, accept string, bodyContentType string, body io.Reader) (io.ReadCloser, error) { return r.Do("POST", subpath, accept, bodyContentType, body) }