Repository navigation
Expand file tree
/
Copy pathrecord.go
More file actions
92 lines (88 loc) · 2.76 KB
/
Copy pathrecord.go
File metadata and controls
92 lines (88 loc) · 2.76 KB
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
package warc
import (
"context"
"errors"
"io"
)
// WriteRecordContext writes one non-HTTP WARC record and returns only after the
// writer has accepted it. Once submitted, the writer result is authoritative
// even if ctx is canceled concurrently.
func (c *CustomHTTPClient) WriteRecordContext(ctx context.Context, targetURI, warcType, contentType, payloadString string, payloadReader io.Reader) (RecordEvent, error) {
// Initialize the record
record, err := newRecord(c.TempDir)
if err != nil {
return RecordEvent{}, err
}
owned := true
defer func() {
if owned {
_ = record.Content.Close()
}
}()
// Set the headers
record.Header.Set("WARC-Type", warcType)
record.Header.Set("WARC-Target-URI", targetURI)
if contentType != "" {
record.Header.Set("Content-Type", contentType)
}
// Write the payload
switch {
case payloadString != "":
_, err = io.WriteString(record.Content, payloadString)
case payloadReader != nil:
_, err = io.Copy(record.Content, payloadReader)
default:
err = errors.New("warc: no record payload provided")
}
if err != nil {
return RecordEvent{}, err
}
// Add it to the batch
batch := NewRecordBatch(nil)
batch.Records = []*Record{record}
// Wait for the record to be written
result, err := c.WriteBatch(ctx, batch)
owned = false
if err != nil {
return RecordEvent{}, err
}
if len(result.Events) != 1 {
return RecordEvent{}, errors.New("warc: writer returned an invalid record count")
}
return result.Events[0], nil
}
// WriteBatch submits a caller-constructed batch and waits for its writer result.
func (c *CustomHTTPClient) WriteBatch(ctx context.Context, batch *RecordBatch) (WriteResult, error) {
if batch == nil || batch.resultDone == nil {
return WriteResult{}, errors.New("warc: invalid record batch")
}
_, writerOwned := ctx.Value(writerOwnerContextKey{}).(bool)
registered := exchangeStateFromContext(ctx) == nil && !writerOwned
if registered {
c.lifecycleMu.Lock()
if c.closing {
c.lifecycleMu.Unlock()
return WriteResult{}, errors.New("warc: client is closing")
}
c.WaitGroup.Add(1)
c.lifecycleMu.Unlock()
defer c.WaitGroup.Done()
}
select {
case c.WARCWriter <- batch:
case <-ctx.Done():
return WriteResult{}, context.Cause(ctx)
}
result, err := batch.Wait(context.Background())
return result, err
}
// WriteRecord is retained for source compatibility. New code should use
// WriteRecordContext so archival failure is part of normal error handling.
func (c *CustomHTTPClient) WriteRecord(targetURI, warcType, contentType, payloadString string, payloadReader io.Reader) {
if _, err := c.WriteRecordContext(context.Background(), targetURI, warcType, contentType, payloadString, payloadReader); err != nil {
select {
case c.ErrChan <- &Error{Err: err, Func: "WriteRecord"}:
default:
}
}
}