Files
asciinema/api/api.go

129 lines
2.8 KiB
Go
Raw Permalink Normal View History

2014-08-03 19:50:39 +02:00
package api
import (
2014-11-02 19:04:19 +01:00
"bytes"
2014-11-13 18:39:29 +01:00
"errors"
2014-11-02 19:04:19 +01:00
"fmt"
2014-08-03 19:50:39 +02:00
"io"
"net/http"
2014-08-03 19:50:39 +02:00
"os"
"runtime"
"strings"
2014-08-03 19:50:39 +02:00
)
2014-11-15 13:33:20 +01:00
type API interface {
AuthUrl() string
UploadAsciicast(string) (string, string, error)
2014-08-03 19:50:39 +02:00
}
2014-11-15 13:33:20 +01:00
type AsciinemaAPI struct {
url string
user string
token string
version string
http HTTP
2014-08-03 20:48:48 +02:00
}
func New(url, user, token, version string) *AsciinemaAPI {
2014-11-15 13:33:20 +01:00
return &AsciinemaAPI{
url: url,
user: user,
token: token,
version: version,
2014-11-15 13:33:20 +01:00
http: &HTTPClient{},
}
2014-08-03 20:48:48 +02:00
}
func (a *AsciinemaAPI) AuthUrl() string {
return fmt.Sprintf("%v/connect/%v", a.url, a.token)
}
func (a *AsciinemaAPI) UploadAsciicast(path string) (string, string, error) {
files, err := filesForUpload(path)
if err != nil {
return "", "", err
}
response, err := a.makeUploadRequest(files)
2014-11-02 19:04:19 +01:00
if err != nil {
return "", "", fmt.Errorf("Connection failed (%v)", err.Error())
2014-11-02 19:04:19 +01:00
}
defer response.Body.Close()
body, err := extractBody(response)
2015-03-02 20:31:51 +01:00
if err != nil {
return "", "", err
2015-03-02 20:31:51 +01:00
}
warn := extractWarningMessage(response)
2014-11-13 18:39:29 +01:00
if response.StatusCode != 200 && response.StatusCode != 201 {
return "", warn, handleError(response, body)
2014-11-13 18:39:29 +01:00
}
return body, warn, nil
}
func (a *AsciinemaAPI) makeUploadRequest(files map[string]io.ReadCloser) (*http.Response, error) {
return a.http.PostForm(a.urlForUpload(), a.user, a.token, a.headersForUpload(), files)
2014-08-03 20:48:48 +02:00
}
func (a *AsciinemaAPI) urlForUpload() string {
return a.url + "/api/asciicasts"
}
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
2014-11-02 19:04:19 +01:00
}
return map[string]io.ReadCloser{"asciicast:asciicast.json": file}, nil
2014-08-03 19:50:39 +02:00
}
func extractWarningMessage(response *http.Response) string {
parts := strings.SplitN(response.Header.Get("Warning"), " ", 2)
if len(parts) == 2 {
return parts[1]
}
return ""
}
func extractBody(response *http.Response) (string, error) {
body := &bytes.Buffer{}
_, err := body.ReadFrom(response.Body)
if err != nil {
return "", err
}
return body.String(), nil
}
func handleError(response *http.Response, body string) error {
switch response.StatusCode {
2015-03-23 17:48:25 +01:00
case 400:
return fmt.Errorf("Invalid request: %v", body)
2015-04-16 13:17:09 +02:00
case 401:
2015-04-16 13:19:02 +02:00
return fmt.Errorf("Invalid or revoked recorder token")
case 404:
return errors.New("Your client version is no longer supported. Please upgrade to the latest version.")
case 413:
return errors.New("Sorry, your asciicast is too big.")
case 422:
return fmt.Errorf("Invalid asciicast: %v", body)
case 504:
return errors.New("The server is down for maintenance. Try again in a minute.")
default:
return errors.New("HTTP status: " + response.Status)
}
}