-
Notifications
You must be signed in to change notification settings - Fork 288
/
snapshot_uploader.go
106 lines (89 loc) · 2.82 KB
/
snapshot_uploader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package cloud
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/pkg/errors"
"github.com/windmilleng/tilt/internal/cloud/cloudurl"
"github.com/windmilleng/tilt/internal/hud/webview"
"github.com/windmilleng/tilt/internal/store"
"github.com/windmilleng/tilt/internal/token"
proto_webview "github.com/windmilleng/tilt/pkg/webview"
)
type SnapshotID string
type SnapshotUploader interface {
TakeAndUpload(state store.EngineState) (SnapshotID, error)
Upload(token token.Token, teamID string, snapshot *proto_webview.Snapshot) (SnapshotID, error)
IDToSnapshotURL(id SnapshotID) string
}
type snapshotUploader struct {
client HttpClient
addr cloudurl.Address
}
func NewSnapshotUploader(client HttpClient, addr cloudurl.Address) SnapshotUploader {
return snapshotUploader{
client: client,
addr: addr,
}
}
func (s snapshotUploader) newSnapshotURL() string {
u := cloudurl.URL(string(s.addr))
u.Path = "/api/snapshot/new"
return u.String()
}
func (s snapshotUploader) IDToSnapshotURL(id SnapshotID) string {
u := cloudurl.URL(string(s.addr))
u.Path = fmt.Sprintf("snapshot/%s", id)
return u.String()
}
type snapshotIDResponse struct {
ID string
}
func (s snapshotUploader) TakeAndUpload(state store.EngineState) (SnapshotID, error) {
view, err := webview.StateToProtoView(state, 0)
if err != nil {
return "", err
}
return s.Upload(state.Token, state.TeamName, &proto_webview.Snapshot{View: view})
}
func (s snapshotUploader) Upload(token token.Token, teamID string, snapshot *proto_webview.Snapshot) (SnapshotID, error) {
b := &bytes.Buffer{}
jsEncoder := &runtime.JSONPb{OrigName: false, EmitDefaults: true}
err := jsEncoder.NewEncoder(b).Encode(snapshot)
if err != nil {
return "", errors.Wrap(err, "encoding snapshot")
}
request, err := http.NewRequest(http.MethodPost, s.newSnapshotURL(), b)
if err != nil {
return "", errors.Wrap(err, "Upload NewRequest")
}
request.Header.Set(TiltTokenHeaderName, token.String())
if teamID != "" {
request.Header.Set(TiltTeamIDNameHeaderName, teamID)
}
response, err := s.client.Do(request)
if err != nil {
return "", errors.Wrap(err, "Upload")
}
defer func() {
_ = response.Body.Close()
}()
if response.StatusCode != http.StatusOK {
b, err := ioutil.ReadAll(response.Body)
if err != nil {
return "", fmt.Errorf("posting snapshot failed, and then reading snapshot response failed. status: %s, error: %v", response.Status, b)
}
return "", fmt.Errorf("posting snapshot failed. status: %s, response: %s", response.Status, b)
}
// unpack response with snapshot ID
var resp snapshotIDResponse
decoder := json.NewDecoder(response.Body)
err = decoder.Decode(&resp)
if err != nil || resp.ID == "" {
return "", errors.Wrap(err, "Upload reading response")
}
return SnapshotID(resp.ID), nil
}