tumblrandom: do some redirect-based stuff to avoid timeouts while fetching
This commit is contained in:
parent
8c75a20274
commit
93efb988cb
1 changed files with 81 additions and 25 deletions
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue