fix(lotw): send a date even for 'all', and give the report time to arrive
Without qso_qslsince LoTW does not answer 'every confirmation' — it answers with a few recent ones, as a 200 and a valid ADIF. 'All' therefore downloaded a nearly empty report and said 'matched 1 of 1' on an account holding twelve thousand. It now asks from 1945-11-15, older than any QSO LoTW accepts. And the request had two minutes: LoTW spends several of them building a full account before the first byte, so asking for everything ended in 'context deadline exceeded while reading body' — a network-shaped message for a too-short deadline. Twenty minutes, and the read cap raised past the 18 MB such a report actually weighs.
This commit is contained in:
+17
-4
@@ -41,23 +41,36 @@ func DownloadLoTWConfirmations(ctx context.Context, client *http.Client, cfg Ser
|
||||
if c := strings.TrimSpace(ownCall); c != "" {
|
||||
q.Set("qso_owncall", c) // restrict to this station callsign
|
||||
}
|
||||
if s := strings.TrimSpace(since); s != "" {
|
||||
q.Set("qso_qslsince", s)
|
||||
// qso_qslsince is ALWAYS sent, even for "everything".
|
||||
//
|
||||
// Left out, LoTW does not answer "all confirmations" — it answers with a
|
||||
// handful of recent ones, which arrives as a 200 and a valid ADIF and reads
|
||||
// as a successful download of a nearly empty account. Asking from a date
|
||||
// older than the service itself is the only way to mean "all".
|
||||
sinceDate := strings.TrimSpace(since)
|
||||
if sinceDate == "" {
|
||||
sinceDate = "1945-11-15" // older than any QSO LoTW will accept
|
||||
}
|
||||
q.Set("qso_qslsince", sinceDate)
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, lotwReportURL+"?"+q.Encode(), nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("lotw: build request: %w", err)
|
||||
}
|
||||
if client == nil {
|
||||
client = &http.Client{Timeout: 120 * time.Second}
|
||||
// A full account is tens of megabytes and LoTW builds it slowly — several
|
||||
// minutes for a log of 30 000 QSOs, all of it before the first byte. The
|
||||
// old two-minute limit turned that into "context deadline exceeded while
|
||||
// reading body", which reads as a network fault rather than as "ask for
|
||||
// less at a time".
|
||||
client = &http.Client{Timeout: 20 * time.Minute}
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("lotw: request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 32*1024*1024))
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, 256*1024*1024))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("lotw: read response: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user