tumblrandom: do some redirect-based stuff to avoid timeouts while fetching

This commit is contained in:
Luke Granger-Brown 2024-09-09 00:28:21 +00:00
parent 8c75a20274
commit 93efb988cb

View file

@ -4,6 +4,7 @@ import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
@ -19,6 +20,7 @@ import (
"os/signal"
"path/filepath"
"strings"
"sync"
"golang.org/x/oauth2"
)
@ -202,6 +204,11 @@ type likesResponse struct {
} `json:"response"`
}
var (
refreshBuf map[string][]Post
refreshBufMu sync.Mutex
)
func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
u, ok := user(ctx)
@ -214,39 +221,88 @@ func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) {
var likes []Post
const urlPrefix = "https://api.tumblr.com"
urlSuffix := "/v2/user/likes"
for {
req, err := http.NewRequestWithContext(ctx, "GET", urlPrefix+urlSuffix, nil)
if err != nil {
http.Error(rw, fmt.Sprintf("formulating likes request: %v", err), http.StatusInternalServerError)
refreshSess := r.FormValue("refresh_session")
if refreshSess == "" {
refreshSessBytes := make([]byte, 32)
if _, err := rand.Read(refreshSessBytes); err != nil {
http.Error(rw, fmt.Sprintf("generating refresh session token: %v", err), http.StatusInternalServerError)
return
}
fmt.Println(req.URL)
resp, err := client.Do(req)
if err != nil {
http.Error(rw, fmt.Sprintf("performing likes request: %v", err), http.StatusInternalServerError)
refreshSess = base64.RawURLEncoding.EncodeToString(refreshSessBytes)
refreshBufMu.Lock()
_, ok := refreshBuf[refreshSess]
refreshBufMu.Unlock()
if ok {
http.Error(rw, fmt.Sprintf("randomness isn't random enough"), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errBody, _ := io.ReadAll(resp.Body)
http.Error(rw, fmt.Sprintf("likes request status %v\n\n%v", resp.StatusCode, string(errBody)), http.StatusInternalServerError)
} else {
refreshBufMu.Lock()
likes2, ok := refreshBuf[refreshSess]
refreshBufMu.Unlock()
if !ok {
http.Error(rw, fmt.Sprintf("refresh session %q is missing", refreshSess), http.StatusBadRequest)
return
}
var r likesResponse
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
http.Error(rw, fmt.Sprintf("decoding likes body as json: %v", err), http.StatusInternalServerError)
return
}
likes = append(likes, r.Response.LikedPosts...)
urlSuffix = r.Response.Links.Next.Href
if urlSuffix == "" {
break
}
likes = likes2
}
urlSuffix := r.FormValue("url_suffix")
if urlSuffix == "" {
urlSuffix = "/v2/user/likes"
}
req, err := http.NewRequestWithContext(ctx, "GET", urlPrefix+urlSuffix, nil)
if err != nil {
http.Error(rw, fmt.Sprintf("formulating likes request: %v", err), http.StatusInternalServerError)
return
}
fmt.Println(req.URL)
resp, err := client.Do(req)
if err != nil {
http.Error(rw, fmt.Sprintf("performing likes request: %v", err), http.StatusInternalServerError)
return
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
errBody, _ := io.ReadAll(resp.Body)
http.Error(rw, fmt.Sprintf("likes request status %v\n\n%v", resp.StatusCode, string(errBody)), http.StatusInternalServerError)
return
}
var lr likesResponse
if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil {
http.Error(rw, fmt.Sprintf("decoding likes body as json: %v", err), http.StatusInternalServerError)
return
}
likes = append(likes, lr.Response.LikedPosts...)
urlSuffix = lr.Response.Links.Next.Href
if urlSuffix != "" {
fmt.Fprintf(rw, `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<form method="POST" id="theForm">
<input type="hidden" name="url_suffix" value="%q">
<input type="hidden" name="refresh_session" value="%q">
<input type="submit" id="theSubmit">
</form>
<script>
document.querySelector('#theSubmit').disabled = true;
document.querySelector('#theForm').submit();
</script>
</body>
</html>
`, urlSuffix, refreshSess)
return
}
refreshBufMu.Lock()
delete(refreshBuf, refreshSess)
refreshBufMu.Unlock()
u.Likes = likes
if err := u.save(); err != nil {
http.Error(rw, fmt.Sprintf("saving likes: %v", err), http.StatusInternalServerError)