package api import ( "bytes" "errors" "fmt" "io" "net/http" "os" "runtime" "strings" ) type API interface { UploadAsciicast(string) (string, string, error) } type AsciinemaAPI struct { url string token string version string http HTTP } func New(url, token, version string) *AsciinemaAPI { return &AsciinemaAPI{ url: url, token: token, version: version, http: &HTTPClient{}, } } func (a *AsciinemaAPI) UploadAsciicast(path string) (string, string, error) { files, err := filesForUpload(path) if err != nil { return "", "", err } response, err := a.http.PostForm( a.urlForUpload(), a.username(), a.token, a.headersForUpload(), files, ) if err != nil { return "", "", fmt.Errorf("Connection failed (%v)", err.Error()) } defer response.Body.Close() body := &bytes.Buffer{} _, err = body.ReadFrom(response.Body) if err != nil { return "", "", err } warn := extractWarningMessage(response) if response.StatusCode != 200 && response.StatusCode != 201 { switch response.StatusCode { case 404: return "", warn, errors.New("Your client version is no longer supported. Please upgrade to the latest version.") case 413: return "", warn, errors.New("Sorry, your asciicast is too big.") case 422: return "", warn, fmt.Errorf("Invalid asciicast: %v", body.String()) case 504: return "", warn, errors.New("The server is down for maintenance. Try again in a minute.") default: return "", warn, errors.New("HTTP status: " + response.Status) } } return body.String(), warn, nil } func (a *AsciinemaAPI) urlForUpload() string { return a.url + "/api/asciicasts" } func (a *AsciinemaAPI) username() string { return os.Getenv("USER") } func (a *AsciinemaAPI) headersForUpload() map[string]string { return map[string]string{ "User-Agent": fmt.Sprintf("asciinema/%s %s/%s %s-%s", a.version, runtime.Compiler, runtime.Version(), runtime.GOOS, runtime.GOARCH), } } func filesForUpload(path string) (map[string]io.ReadCloser, error) { file, err := os.Open(path) if err != nil { return nil, err } return map[string]io.ReadCloser{"asciicast:asciicast.json": file}, nil } func extractWarningMessage(response *http.Response) string { parts := strings.SplitN(response.Header.Get("Warning"), " ", 2) if len(parts) == 2 { return parts[1] } return "" }