-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstatus.go
145 lines (120 loc) · 3.88 KB
/
status.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
package spn
import (
"encoding/json"
"net/http"
"time"
)
// UserStatus represent the data returned by the /save/status/user endpoint
type UserStatus struct {
DailyCaptures int `json:"daily_captures"`
DailyCapturesLimit int `json:"daily_captures_limit"`
Available int `json:"available"`
Processing int `json:"processing"`
}
func (to *UserStatus) Update(from UserStatus) {
to.DailyCaptures = from.DailyCaptures
to.DailyCapturesLimit = from.DailyCapturesLimit
to.Available = from.Available
to.Processing = from.Processing
}
// CaptureStatus represent the date returned by the /save/status/{job_id} endpoint
type CaptureStatus struct {
Timestamp string `json:"timestamp"`
DurationSec float64 `json:"duration_sec"`
OriginalURL string `json:"original_url"`
Status string `json:"status"`
StatusExt string `json:"status_ext"`
JobID string `json:"job_id"`
Outlinks []string `json:"outlinks"`
Resources []string `json:"resources"`
Exception string `json:"exception"`
Message string `json:"message"`
}
// GetCaptureStatus retrieve the informations about a SPN job
func (c Connector) GetCaptureStatus(jobID string) (captureStatus CaptureStatus, err error) {
// Build request
req, err := http.NewRequest("GET", "https://web.archive.org/save/status/"+jobID, nil)
if err != nil {
return captureStatus, err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "LOW "+c.AccessKey+":"+c.SecretKey)
// Execute request
resp, err := c.HTTPClient.Do(req)
if err != nil {
return captureStatus, err
}
json.NewDecoder(resp.Body).Decode(&captureStatus)
if captureStatus.Outlinks == nil {
captureStatus.Outlinks = []string{""}
}
if captureStatus.Resources == nil {
captureStatus.Resources = []string{""}
}
return captureStatus, nil
}
// GetUserStatus retrieve the user status for a given SPN account
func (c Connector) GetUserStatus() (userStatus UserStatus, err error) {
// Build request
req, err := http.NewRequest("GET", "https://web.archive.org/save/status/user", nil)
if err != nil {
return userStatus, err
}
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Authorization", "LOW "+c.AccessKey+":"+c.SecretKey)
// Execute request
resp, err := c.HTTPClient.Do(req)
if err != nil {
return userStatus, err
}
json.NewDecoder(resp.Body).Decode(&userStatus)
return userStatus, nil
}
// Refresh the cached user status in the background
func (c *Connector) cachedUserStatusFetcher() {
logger.Debug("Starting cachedUserStatusFetcher")
defer logger.Debug("cachedUserStatusFetcher exited")
lastFetch := time.Unix(0, 0)
for {
select {
case <-c.cachedStatusFetcherIntr:
return
default:
}
if time.Since(lastFetch) < time.Second*10 && c.cachedStatus.Available > 2 {
time.Sleep(time.Second)
continue
}
// Make sure we don't fetch the status too often (< 2s)
wait := time.Second*2 - time.Since(lastFetch)
if wait > 0 {
logger.Debug("Waiting before fetching user status", "wait", wait)
time.Sleep(wait)
}
logger.Debug("Fetching user status")
lastFetch = time.Now()
userStatus, err := c.GetUserStatus()
if err != nil {
logger.Error("Failed to fetch user status", "error", err)
continue
}
logger.Debug("User status fetched", "status", userStatus)
c.cachedStatus.Update(userStatus)
logger.Debug("cachedStatus updated", "cachedStatus", c.cachedStatus)
}
}
// Wait until a capture slot is available
func (c Connector) GetAvailableCaptureSlot() (err error) {
for {
if c.cachedStatus.Available > 0 {
c.cachedStatus.Available--
c.cachedStatus.Processing++
logger.Debug("AwaitAvailableSlot return", "cachedStatus", c.cachedStatus)
return nil
}
logger.Debug("AwaitAvailableSlot waiting")
time.Sleep(time.Second)
}
}