@@ -19,10 +19,13 @@ import (
19
19
"encoding/json"
20
20
"errors"
21
21
"fmt"
22
+ "io"
22
23
"io/ioutil"
23
24
"net/url"
25
+ "strconv"
24
26
"time"
25
27
28
+ "github.com/uber/kraken/build-index/tagmodels"
26
29
"github.com/uber/kraken/core"
27
30
"github.com/uber/kraken/lib/healthcheck"
28
31
"github.com/uber/kraken/utils/httputil"
@@ -40,7 +43,9 @@ type Client interface {
40
43
Get (tag string ) (core.Digest , error )
41
44
Has (tag string ) (bool , error )
42
45
List (prefix string ) ([]string , error )
46
+ ListWithPagination (prefix string , filter ListFilter ) (tagmodels.ListResponse , error )
43
47
ListRepository (repo string ) ([]string , error )
48
+ ListRepositoryWithPagination (repo string , filter ListFilter ) (tagmodels.ListResponse , error )
44
49
Replicate (tag string ) error
45
50
Origin () (string , error )
46
51
@@ -54,6 +59,12 @@ type singleClient struct {
54
59
tls * tls.Config
55
60
}
56
61
62
+ // ListFilter contains filter request for list with pagination operations.
63
+ type ListFilter struct {
64
+ Offset string
65
+ Limit int
66
+ }
67
+
57
68
// NewSingleClient returns a Client scoped to a single tagserver instance.
58
69
func NewSingleClient (addr string , config * tls.Config ) Client {
59
70
return & singleClient {addr , config }
@@ -112,37 +123,90 @@ func (c *singleClient) Has(tag string) (bool, error) {
112
123
return true , nil
113
124
}
114
125
115
- func (c * singleClient ) List (prefix string ) ([]string , error ) {
116
- resp , err := httputil .Get (
117
- fmt .Sprintf ("http://%s/list/%s" , c .addr , prefix ),
126
+ func (c * singleClient ) doListPaginated (urlFormat string , pathSub string ,
127
+ filter ListFilter ) (tagmodels.ListResponse , error ) {
128
+
129
+ // Build query.
130
+ reqVal := url.Values {}
131
+ if filter .Offset != "" {
132
+ reqVal .Add (tagmodels .OffsetQ , filter .Offset )
133
+ }
134
+ if filter .Limit != 0 {
135
+ reqVal .Add (tagmodels .LimitQ , strconv .Itoa (filter .Limit ))
136
+ }
137
+
138
+ // Fetch list response from server.
139
+ serverUrl := url.URL {
140
+ Scheme : "http" ,
141
+ Host : c .addr ,
142
+ Path : fmt .Sprintf (urlFormat , pathSub ),
143
+ RawQuery : reqVal .Encode (),
144
+ }
145
+ var resp tagmodels.ListResponse
146
+ httpResp , err := httputil .Get (
147
+ serverUrl .String (),
118
148
httputil .SendTimeout (60 * time .Second ),
119
149
httputil .SendTLS (c .tls ))
120
150
if err != nil {
121
- return nil , err
151
+ return resp , err
122
152
}
123
- defer resp .Body .Close ()
153
+ defer httpResp .Body .Close ()
154
+ if err := json .NewDecoder (httpResp .Body ).Decode (& resp ); err != nil {
155
+ return resp , fmt .Errorf ("json decode: %s" , err )
156
+ }
157
+
158
+ return resp , nil
159
+ }
160
+
161
+ func (c * singleClient ) doList (pathSub string ,
162
+ fn func (pathSub string , filter ListFilter ) (tagmodels.ListResponse , error )) (
163
+ []string , error ) {
164
+
124
165
var names []string
125
- if err := json .NewDecoder (resp .Body ).Decode (& names ); err != nil {
126
- return nil , fmt .Errorf ("json decode: %s" , err )
166
+
167
+ offset := ""
168
+ for ok := true ; ok ; ok = (offset != "" ) {
169
+ filter := ListFilter {Offset : offset }
170
+ resp , err := fn (pathSub , filter )
171
+ if err != nil {
172
+ return nil , err
173
+ }
174
+ offset , err = resp .GetOffset ()
175
+ if err != nil && err != io .EOF {
176
+ return nil , err
177
+ }
178
+ names = append (names , resp .Result ... )
127
179
}
128
180
return names , nil
129
181
}
130
182
183
+ func (c * singleClient ) List (prefix string ) ([]string , error ) {
184
+ return c .doList (prefix , func (prefix string , filter ListFilter ) (
185
+ tagmodels.ListResponse , error ) {
186
+
187
+ return c .ListWithPagination (prefix , filter )
188
+ })
189
+ }
190
+
191
+ func (c * singleClient ) ListWithPagination (prefix string , filter ListFilter ) (
192
+ tagmodels.ListResponse , error ) {
193
+
194
+ return c .doListPaginated ("list/%s" , prefix , filter )
195
+ }
196
+
131
197
// XXX: Deprecated. Use List instead.
132
198
func (c * singleClient ) ListRepository (repo string ) ([]string , error ) {
133
- resp , err := httputil .Get (
134
- fmt .Sprintf ("http://%s/repositories/%s/tags" , c .addr , url .PathEscape (repo )),
135
- httputil .SendTimeout (60 * time .Second ),
136
- httputil .SendTLS (c .tls ))
137
- if err != nil {
138
- return nil , err
139
- }
140
- defer resp .Body .Close ()
141
- var tags []string
142
- if err := json .NewDecoder (resp .Body ).Decode (& tags ); err != nil {
143
- return nil , fmt .Errorf ("json decode: %s" , err )
144
- }
145
- return tags , nil
199
+ return c .doList (repo , func (repo string , filter ListFilter ) (
200
+ tagmodels.ListResponse , error ) {
201
+
202
+ return c .ListRepositoryWithPagination (repo , filter )
203
+ })
204
+ }
205
+
206
+ func (c * singleClient ) ListRepositoryWithPagination (repo string ,
207
+ filter ListFilter ) (tagmodels.ListResponse , error ) {
208
+
209
+ return c .doListPaginated ("repositories/%s/tags" , url .PathEscape (repo ), filter )
146
210
}
147
211
148
212
// ReplicateRequest defines a Replicate request body.
@@ -279,6 +343,16 @@ func (cc *clusterClient) List(prefix string) (tags []string, err error) {
279
343
return
280
344
}
281
345
346
+ func (cc * clusterClient ) ListWithPagination (prefix string , filter ListFilter ) (
347
+ resp tagmodels.ListResponse , err error ) {
348
+
349
+ err = cc .do (func (c Client ) error {
350
+ resp , err = c .ListWithPagination (prefix , filter )
351
+ return err
352
+ })
353
+ return
354
+ }
355
+
282
356
func (cc * clusterClient ) ListRepository (repo string ) (tags []string , err error ) {
283
357
err = cc .do (func (c Client ) error {
284
358
tags , err = c .ListRepository (repo )
@@ -287,6 +361,16 @@ func (cc *clusterClient) ListRepository(repo string) (tags []string, err error)
287
361
return
288
362
}
289
363
364
+ func (cc * clusterClient ) ListRepositoryWithPagination (repo string ,
365
+ filter ListFilter ) (resp tagmodels.ListResponse , err error ) {
366
+
367
+ err = cc .do (func (c Client ) error {
368
+ resp , err = c .ListRepositoryWithPagination (repo , filter )
369
+ return err
370
+ })
371
+ return
372
+ }
373
+
290
374
func (cc * clusterClient ) Replicate (tag string ) error {
291
375
return cc .do (func (c Client ) error { return c .Replicate (tag ) })
292
376
}
0 commit comments