@@ -155,42 +155,42 @@ type httpLeafWriter struct {
155
155
bearerToken string
156
156
}
157
157
158
- func (w httpLeafWriter ) Write (ctx context.Context , newLeaf []byte ) (uint64 , error ) {
158
+ func (w httpLeafWriter ) Write (ctx context.Context , newLeaf []byte ) (uint64 , uint64 , error ) {
159
159
req , err := http .NewRequest (http .MethodPost , w .u .String (), bytes .NewReader (newLeaf ))
160
160
if err != nil {
161
- return 0 , fmt .Errorf ("failed to create request: %v" , err )
161
+ return 0 , 0 , fmt .Errorf ("failed to create request: %v" , err )
162
162
}
163
163
if w .bearerToken != "" {
164
164
req .Header .Add ("Authorization" , fmt .Sprintf ("Bearer %s" , w .bearerToken ))
165
165
}
166
166
resp , err := w .hc .Do (req .WithContext (ctx ))
167
167
if err != nil {
168
- return 0 , fmt .Errorf ("failed to write leaf: %v" , err )
168
+ return 0 , 0 , fmt .Errorf ("failed to write leaf: %v" , err )
169
169
}
170
170
body , err := io .ReadAll (resp .Body )
171
171
_ = resp .Body .Close ()
172
172
if err != nil {
173
- return 0 , fmt .Errorf ("failed to read body: %v" , err )
173
+ return 0 , 0 , fmt .Errorf ("failed to read body: %v" , err )
174
174
}
175
175
switch resp .StatusCode {
176
176
case http .StatusOK :
177
177
if resp .Request .Method != http .MethodPost {
178
- return 0 , fmt .Errorf ("write leaf was redirected to %s" , resp .Request .URL )
178
+ return 0 , 0 , fmt .Errorf ("write leaf was redirected to %s" , resp .Request .URL )
179
179
}
180
180
// Continue below
181
181
case http .StatusServiceUnavailable , http .StatusBadGateway , http .StatusGatewayTimeout :
182
182
// These status codes may indicate a delay before retrying, so handle that here:
183
183
time .Sleep (retryDelay (resp .Header .Get ("RetryAfter" ), time .Second ))
184
184
185
- return 0 , fmt .Errorf ("log not available. Status code: %d. Body: %q %w" , resp .StatusCode , body , ErrRetry )
185
+ return 0 , 0 , fmt .Errorf ("log not available. Status code: %d. Body: %q %w" , resp .StatusCode , body , ErrRetry )
186
186
default :
187
- return 0 , fmt .Errorf ("write leaf was not OK. Status code: %d. Body: %q" , resp .StatusCode , body )
187
+ return 0 , 0 , fmt .Errorf ("write leaf was not OK. Status code: %d. Body: %q" , resp .StatusCode , body )
188
188
}
189
- index , err := parseAddChainResponse (body )
189
+ index , timestamp , err := parseAddChainResponse (body )
190
190
if err != nil {
191
- return 0 , fmt .Errorf ("write leaf failed to parse response: %v" , body )
191
+ return 0 , 0 , fmt .Errorf ("write leaf failed to parse response: %v" , body )
192
192
}
193
- return index , nil
193
+ return index , timestamp , nil
194
194
}
195
195
196
196
func retryDelay (retryAfter string , defaultDur time.Duration ) time.Duration {
@@ -216,7 +216,7 @@ type roundRobinLeafWriter struct {
216
216
ws []httpLeafWriter
217
217
}
218
218
219
- func (rr * roundRobinLeafWriter ) Write (ctx context.Context , newLeaf []byte ) (uint64 , error ) {
219
+ func (rr * roundRobinLeafWriter ) Write (ctx context.Context , newLeaf []byte ) (uint64 , uint64 , error ) {
220
220
w := rr .next ()
221
221
return w (ctx , newLeaf )
222
222
}
@@ -232,39 +232,39 @@ func (rr *roundRobinLeafWriter) next() LeafWriter {
232
232
}
233
233
234
234
// parseAddChainResponse parses the add-chain response and returns the leaf
235
- // index from the extensions.
235
+ // index from the extensions and timestamp from the response .
236
236
// Code is inspired by https://github.com/FiloSottile/sunlight/blob/main/tile.go.
237
- func parseAddChainResponse (body []byte ) (uint64 , error ) {
237
+ func parseAddChainResponse (body []byte ) (uint64 , uint64 , error ) {
238
238
var resp types.AddChainResponse
239
239
if err := json .Unmarshal (body , & resp ); err != nil {
240
- return 0 , fmt .Errorf ("can't parse add-chain response: %v" , err )
240
+ return 0 , 0 , fmt .Errorf ("can't parse add-chain response: %v" , err )
241
241
}
242
242
243
243
extensionBytes , err := base64 .StdEncoding .DecodeString (resp .Extensions )
244
244
if err != nil {
245
- return 0 , fmt .Errorf ("can't decode extensions: %v" , err )
245
+ return 0 , 0 , fmt .Errorf ("can't decode extensions: %v" , err )
246
246
}
247
247
extensions := cryptobyte .String (extensionBytes )
248
248
var extensionType uint8
249
249
var extensionData cryptobyte.String
250
250
var leafIdx int64
251
251
if ! extensions .ReadUint8 (& extensionType ) {
252
- return 0 , fmt .Errorf ("can't read extension type" )
252
+ return 0 , 0 , fmt .Errorf ("can't read extension type" )
253
253
}
254
254
if extensionType != 0 {
255
- return 0 , fmt .Errorf ("wrong extension type %d, want 0" , extensionType )
255
+ return 0 , 0 , fmt .Errorf ("wrong extension type %d, want 0" , extensionType )
256
256
}
257
257
if ! extensions .ReadUint16LengthPrefixed (& extensionData ) {
258
- return 0 , fmt .Errorf ("can't read extension data" )
258
+ return 0 , 0 , fmt .Errorf ("can't read extension data" )
259
259
}
260
260
if ! readUint40 (& extensionData , & leafIdx ) {
261
- return 0 , fmt .Errorf ("can't read leaf index from extension" )
261
+ return 0 , 0 , fmt .Errorf ("can't read leaf index from extension" )
262
262
}
263
263
if ! extensionData .Empty () ||
264
264
! extensions .Empty () {
265
- return 0 , fmt .Errorf ("invalid data tile extensions: %v" , resp .Extensions )
265
+ return 0 , 0 , fmt .Errorf ("invalid data tile extensions: %v" , resp .Extensions )
266
266
}
267
- return uint64 (leafIdx ), nil
267
+ return uint64 (leafIdx ), resp . Timestamp , nil
268
268
}
269
269
270
270
// readUint40 decodes a big-endian, 40-bit value into out and advances over it.
0 commit comments