-
Notifications
You must be signed in to change notification settings - Fork 6
/
endpoints_wharf.go
304 lines (249 loc) · 10.1 KB
/
endpoints_wharf.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
package itchio
import (
"context"
"encoding/json"
"github.com/pkg/errors"
)
//-------------------------------------------------------
// WharfStatusResponse is what the API responds with when we ask for
// the status of the wharf infrastructure
type WharfStatusResponse struct {
Success bool `json:"success"`
}
// WharfStatus requests the status of the wharf infrastructure
func (c *Client) WharfStatus(ctx context.Context) (*WharfStatusResponse, error) {
q := NewQuery(c, "/wharf/status")
r := &WharfStatusResponse{}
return r, q.Get(ctx, r)
}
//-------------------------------------------------------
// ListChannelsResponse is what the API responds with when we ask for all the
// channels of a particular game
type ListChannelsResponse struct {
Channels map[string]*Channel `json:"channels"`
}
// Channel contains information about a channel and its current status
type Channel struct {
// Name of the channel, usually something like `windows-64-beta` or `osx-universal`
Name string `json:"name"`
Tags string `json:"tags"`
Upload *Upload `json:"upload"`
Head *Build `json:"head"`
Pending *Build `json:"pending"`
}
// ListChannels returns a list of the channels for a game
func (c *Client) ListChannels(ctx context.Context, target string) (*ListChannelsResponse, error) {
q := NewQuery(c, "/wharf/channels")
q.AddString("target", target)
r := &ListChannelsResponse{}
return r, q.Get(ctx, r)
}
//-------------------------------------------------------
// GetChannelResponse is what the API responds with when we ask info about a channel
type GetChannelResponse struct {
Channel *Channel `json:"channel"`
}
// GetChannel returns information about a given channel for a given game
func (c *Client) GetChannel(ctx context.Context, target string, channel string) (*GetChannelResponse, error) {
q := NewQuery(c, "/wharf/channels/%s", channel)
q.AddString("target", target)
r := &GetChannelResponse{}
return r, q.Get(ctx, r)
}
//-------------------------------------------------------
// CreateBuildParams : params for CreateBuild
type CreateBuildParams struct {
Target string
Channel string
UserVersion string
}
// CreateBuildResponse : response for CreateBuild
type CreateBuildResponse struct {
Build struct {
ID int64 `json:"id"`
UploadID int64 `json:"uploadId"`
ParentBuild struct {
ID int64 `json:"id"`
} `json:"parentBuild"`
}
}
// CreateBuild creates a new build for a given user/game:channel, with
// an optional user version
func (c *Client) CreateBuild(ctx context.Context, p CreateBuildParams) (*CreateBuildResponse, error) {
q := NewQuery(c, "/wharf/builds")
q.AddString("target", p.Target)
q.AddString("channel", p.Channel)
q.AddStringIfNonEmpty("user_version", p.UserVersion)
r := &CreateBuildResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
// ListBuildFilesResponse : response for ListBuildFiles
type ListBuildFilesResponse struct {
Files []*BuildFile `json:"files"`
}
// ListBuildFiles returns a list of files associated to a build
func (c *Client) ListBuildFiles(ctx context.Context, buildID int64) (*ListBuildFilesResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/files", buildID)
r := &ListBuildFilesResponse{}
return r, q.Get(ctx, r)
}
//-------------------------------------------------------
// FileUploadType describes which strategy is used for uploading to storage
// some types allow for uploading in blocks (which is resumable), some
// expect the whole payload in one request.
type FileUploadType string
const (
// FileUploadTypeMultipart lets you send metadata + all the content in a single request
FileUploadTypeMultipart FileUploadType = "multipart"
// FileUploadTypeResumable lets you send blocks of N*128KB at a time. The upload session is
// started from the API server, so the ingest point will be anchored wherever the API server is.
FileUploadTypeResumable FileUploadType = "resumable"
// FileUploadTypeDeferredResumable also lets you send blocks of N*128KB at a time, but it
// lets you start the upload session from the client, which means you might get a closer ingest point.
FileUploadTypeDeferredResumable FileUploadType = "deferred_resumable"
)
// FileUploadSpec contains the info needed to upload one specific build file
type FileUploadSpec struct {
ID int64 `json:"id"`
UploadURL string `json:"uploadUrl"`
UploadParams map[string]string `json:"uploadParams"`
UploadHeaders map[string]string `json:"uploadHeaders"`
}
// CreateBuildFileParams : params for CreateBuildFile
type CreateBuildFileParams struct {
BuildID int64
Type BuildFileType
SubType BuildFileSubType
FileUploadType FileUploadType
Filename string
}
// CreateBuildFileResponse : response for CreateBuildFile
type CreateBuildFileResponse struct {
File *FileUploadSpec `json:"file"`
}
// CreateBuildFile creates a new build file for a build.
func (c *Client) CreateBuildFile(ctx context.Context, p CreateBuildFileParams) (*CreateBuildFileResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/files", p.BuildID)
q.AddString("type", string(p.Type))
q.AddStringIfNonEmpty("sub_type", string(p.SubType))
q.AddStringIfNonEmpty("upload_type", string(p.FileUploadType))
q.AddStringIfNonEmpty("filename", p.Filename)
r := &CreateBuildFileResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
// FinalizeBuildFileParams : params for FinalizeBuildFile
type FinalizeBuildFileParams struct {
BuildID int64
FileID int64
Size int64
}
// FinalizeBuildFileResponse : response for FinalizeBuildFile
type FinalizeBuildFileResponse struct{}
// FinalizeBuildFile marks the end of the upload for a build file.
// It validates that the size of the file in storage is the same
// we pass to this API call.
func (c *Client) FinalizeBuildFile(ctx context.Context, p FinalizeBuildFileParams) (*FinalizeBuildFileResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/files/%d", p.BuildID, p.FileID)
q.AddInt64("size", p.Size)
r := &FinalizeBuildFileResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
var (
// ErrBuildFileNotFound is returned when someone is asking for a non-existent file
ErrBuildFileNotFound = errors.New("build file not found in storage")
)
// MakeBuildFileDownloadURLParams : params for MakeBuildFileDownloadURL
type MakeBuildFileDownloadURLParams struct {
BuildID int64
FileID int64
}
// MakeBuildFileDownloadURL returns a download URL for a given build file
func (c *Client) MakeBuildFileDownloadURL(p MakeBuildFileDownloadURLParams) string {
q := NewQuery(c, "/wharf/builds/%d/files/%d/download", p.BuildID, p.FileID)
q.AddAPICredentials()
return q.URL()
}
//-------------------------------------------------------
// CreateBuildEventParams : params for CreateBuildEvent
type CreateBuildEventParams struct {
BuildID int64
Type BuildEventType
Message string
Data BuildEventData
}
// BuildEventType specifies what kind of event a build event is - could be a log message, etc.
type BuildEventType string
const (
// BuildEventLog is for build events of type log message
BuildEventLog BuildEventType = "log"
)
// BuildEventData is a JSON object associated with a build event
type BuildEventData map[string]interface{}
// CreateBuildEventResponse is what the API responds with when you create a new build event
type CreateBuildEventResponse struct{}
// CreateBuildEvent associates a new build event to a build
func (c *Client) CreateBuildEvent(ctx context.Context, p CreateBuildEventParams) (*CreateBuildEventResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/events", p.BuildID)
q.AddString("type", string(p.Type))
q.AddString("message", p.Message)
jsonData, err := json.Marshal(p.Data)
if err != nil {
return nil, errors.WithStack(err)
}
q.AddString("data", string(jsonData))
r := &CreateBuildEventResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
// CreateBuildFailureParams : params for CreateBuildFailure
type CreateBuildFailureParams struct {
BuildID int64
Message string
Fatal bool
}
// CreateBuildFailureResponse : response for CreateBuildFailure
type CreateBuildFailureResponse struct{}
// CreateBuildFailure marks a given build as failed. We get to specify an error message and
// if it's a fatal error (if not, the build can be retried after a bit)
func (c *Client) CreateBuildFailure(ctx context.Context, p CreateBuildFailureParams) (*CreateBuildFailureResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/failures", p.BuildID)
q.AddString("message", p.Message)
q.AddBoolIfTrue("fatal", p.Fatal)
r := &CreateBuildFailureResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
// CreateRediffBuildFailureParams : params for CreateRediffBuildFailure
type CreateRediffBuildFailureParams struct {
BuildID int64
Message string
}
// CreateRediffBuildFailureResponse : response for CreateRediffBuildFailure
type CreateRediffBuildFailureResponse struct{}
// CreateRediffBuildFailure marks a given build as having failed to rediff (optimize)
func (c *Client) CreateRediffBuildFailure(ctx context.Context, p CreateRediffBuildFailureParams) (*CreateRediffBuildFailureResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/failures/rediff", p.BuildID)
q.AddString("message", p.Message)
r := &CreateRediffBuildFailureResponse{}
return r, q.Post(ctx, r)
}
//-------------------------------------------------------
// ListBuildEventsResponse is what the API responds with when we ask for the list of events for a build
type ListBuildEventsResponse struct {
Events []*BuildEvent `json:"events"`
}
// A BuildEvent describes something that happened while we were processing a build.
type BuildEvent struct {
Type BuildEventType `json:"type"`
Message string `json:"message"`
Data BuildEventData `json:"data"`
}
// ListBuildEvents returns a series of events associated with a given build
func (c *Client) ListBuildEvents(ctx context.Context, buildID int64) (*ListBuildEventsResponse, error) {
q := NewQuery(c, "/wharf/builds/%d/events", buildID)
r := &ListBuildEventsResponse{}
return r, q.Get(ctx, r)
}