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" "context"
"crypto/rand" "crypto/rand"
"crypto/sha256" "crypto/sha256"
"encoding/base64"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
@ -19,6 +20,7 @@ import (
"os/signal" "os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
@ -202,6 +204,11 @@ type likesResponse struct {
} `json:"response"` } `json:"response"`
} }
var (
refreshBuf map[string][]Post
refreshBufMu sync.Mutex
)
func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) { func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()
u, ok := user(ctx) u, ok := user(ctx)
@ -214,8 +221,37 @@ func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) {
var likes []Post var likes []Post
const urlPrefix = "https://api.tumblr.com" const urlPrefix = "https://api.tumblr.com"
urlSuffix := "/v2/user/likes" refreshSess := r.FormValue("refresh_session")
for { 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
}
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
}
} 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
}
likes = likes2
}
urlSuffix := r.FormValue("url_suffix")
if urlSuffix == "" {
urlSuffix = "/v2/user/likes"
}
req, err := http.NewRequestWithContext(ctx, "GET", urlPrefix+urlSuffix, nil) req, err := http.NewRequestWithContext(ctx, "GET", urlPrefix+urlSuffix, nil)
if err != nil { if err != nil {
http.Error(rw, fmt.Sprintf("formulating likes request: %v", err), http.StatusInternalServerError) http.Error(rw, fmt.Sprintf("formulating likes request: %v", err), http.StatusInternalServerError)
@ -234,18 +270,38 @@ func (a *app) refreshLikes(rw http.ResponseWriter, r *http.Request) {
return return
} }
var r likesResponse var lr likesResponse
if err := json.NewDecoder(resp.Body).Decode(&r); err != nil { if err := json.NewDecoder(resp.Body).Decode(&lr); err != nil {
http.Error(rw, fmt.Sprintf("decoding likes body as json: %v", err), http.StatusInternalServerError) http.Error(rw, fmt.Sprintf("decoding likes body as json: %v", err), http.StatusInternalServerError)
return return
} }
likes = append(likes, r.Response.LikedPosts...) likes = append(likes, lr.Response.LikedPosts...)
urlSuffix = r.Response.Links.Next.Href urlSuffix = lr.Response.Links.Next.Href
if urlSuffix == "" { if urlSuffix != "" {
break 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 u.Likes = likes
if err := u.save(); err != nil { if err := u.save(); err != nil {