Adding avatar image caching and serving from local honk
1 files changed, 84 insertions(+), 40 deletions(-)

M web.go
M web.go +84 -40
@@ 2157,11 2157,60 @@ func somedays() string {
 	return fmt.Sprintf("%d", secs)
 }
 
+type avaKey struct {
+	uid int64
+	url string
+}
+
+var avacache = cache.New(cache.Options{Filler: func(key avaKey) (string, bool) {
+	j, err := GetJunkFast(key.uid, key.url)
+	if err != nil {
+		dlog.Println("avatating: getting junk:", err)
+		return "", false
+	}
+	pfpurl, _ := j.GetString("icon", "url")
+	res, err := http.Get(pfpurl)
+	if res.StatusCode != 200 {
+		dlog.Printf("avatating: %s: not ok: %d", key.url, res.StatusCode)
+		return "", false
+	}
+	if err != nil {
+		dlog.Println("avatating: getting pfp url:", err)
+		return "", false
+	}
+	defer res.Body.Close()
+
+	data, err := io.ReadAll(res.Body)
+	if err != nil {
+		dlog.Println("avatating: io.ReadAll(), whoops:", err)
+		return "", false
+	}
+
+	img, err := shrinkit(data)
+	if err != nil {
+		return "", false
+	}
+	data = img.Data
+	format := img.Format
+	desc := fmt.Sprintf("avatar for %s", key.url)
+	media := "image/" + format
+	if format == "jpeg" {
+		format = "jpg"
+	}
+	name := xfiltrate() + "." + format
+	_, xid, err := savefileandxid(name, desc, "", media, true, data)
+	if err != nil {
+		elog.Printf("avatate: unable to save image: %s", err)
+		return "", false
+	}
+	return xid, true
+}, Reducer: func(key avaKey) string {
+	return key.url
+}, Duration: 24 * 7 * time.Hour})
+
 func isURL(s string) bool {
-	return false
-	// XXX Temporarily disable avatar fetching. It's too slow as it is now
-	// u, err := url.Parse(s)
-	// return err == nil && u.Scheme != "" && u.Host != ""
+	u, err := url.Parse(s)
+	return err == nil && u.Scheme != "" && u.Host != ""
 }
 
 func avatateautogen(r *http.Request) []byte {

          
@@ 2174,43 2223,29 @@ func avatate(w http.ResponseWriter, r *h
 	if develMode {
 		loadAvatarColors()
 	}
-	var a []byte
+	var (
+		xid string
+		uid int64
+	)
 	n := r.FormValue("a")
 
 	if isURL(n) {
 		uinfo := login.GetUserInfo(r)
-		j, err := GetJunkFast(uinfo.UserID, n)
-		if err != nil {
-			dlog.Println("avatating: getting junk:", err)
-			a = avatateautogen(r)
-			goto nope
-		}
-		pfpurl, _ := j.GetString("icon", "url")
-		res, err := http.Get(pfpurl)
-		if res.StatusCode != 200 {
-			dlog.Printf("avatating: %s: not ok: %d", n, res.StatusCode)
-			a = avatateautogen(r)
-			goto nope
+		if uinfo != nil {
+			uid = uinfo.UserID
+		} else {
+			uid = 0
 		}
-		if err != nil {
-			dlog.Println("avatating: getting pfp url:", err)
-			a = avatateautogen(r)
-			goto nope
+		avacache.Get(avaKey{uid, n}, &xid)
+		if xid != "" {
+			err := reallyservefile(xid, w)
+			if err == nil {
+				return
+			}
 		}
-		defer res.Body.Close()
-
-		pfpbytes, err := io.ReadAll(res.Body)
-		if err != nil {
-			dlog.Println("avatating: io.ReadAll(), whoops:", err)
-			a = avatateautogen(r)
-			goto nope
-		}
-		a = pfpbytes
-	} else {
-		a = avatateautogen(r)
 	}
 
-nope:
+	a := avatateautogen(r)
 	if !develMode {
 		w.Header().Set("Cache-Control", "max-age="+somedays())
 	}

          
@@ 2271,23 2306,32 @@ func servememe(w http.ResponseWriter, r 
 	http.ServeFile(w, r, dataDir+"/memes/"+meme)
 }
 
-func servefile(w http.ResponseWriter, r *http.Request) {
-	xid := mux.Vars(r)["xid"]
+func reallyservefile(xid string, w http.ResponseWriter) error {
 	var media string
 	var data []byte
 	row := stmtGetFileData.QueryRow(xid)
 	err := row.Scan(&media, &data)
 	if err != nil {
 		elog.Printf("error loading file: %s", err)
-		http.NotFound(w, r)
-		return
+		return err
 	}
-	w.Header().Set("Content-Type", media)
-	w.Header().Set("X-Content-Type-Options", "nosniff")
-	w.Header().Set("Cache-Control", "max-age="+somedays())
+
+	if !develMode {
+		w.Header().Set("Content-Type", media)
+		w.Header().Set("X-Content-Type-Options", "nosniff")
+		w.Header().Set("Cache-Control", "max-age="+somedays())
+	}
 	w.Write(data)
+	return nil
 }
 
+func servefile(w http.ResponseWriter, r *http.Request) {
+	xid := mux.Vars(r)["xid"]
+	err := reallyservefile(xid, w)
+	if err != nil {
+		http.NotFound(w, r)
+	}
+}
 func nomoroboto(w http.ResponseWriter, r *http.Request) {
 	io.WriteString(w, "User-agent: *\n")
 	io.WriteString(w, "Disallow: /a\n")