Cosmos-Server/src/icons.go
2023-04-27 19:29:26 +01:00

200 lines
4.4 KiB
Go

package main
import (
"net/http"
"net/url"
// "fmt"
"os"
"io/ioutil"
"encoding/json"
"strconv"
"github.com/azukaar/cosmos-server/src/utils"
"go.deanishe.net/favicon"
)
type CachedImage struct {
ContentType string
ETag string
Body []byte
}
var cache = make(map[string]CachedImage)
func sendImage(w http.ResponseWriter, image CachedImage) {
// Copy the response to the output
w.Header().Set("Content-Type", image.ContentType)
w.Header().Set("ETag", image.ETag)
w.Header().Set("Cache-Control", "max-age=86400")
w.WriteHeader(http.StatusOK)
w.Write(image.Body)
}
func sendFallback(w http.ResponseWriter) {
// Send the fallback image
pwd,_ := os.Getwd()
imgsrc := "cosmos_gray.png"
fallback, err := ioutil.ReadFile(pwd + "/" + imgsrc)
if err != nil {
utils.Error("Favicon: fallback", err)
utils.HTTPError(w, "Favicon", http.StatusInternalServerError, "FA003")
return
}
w.Header().Set("Content-Type", "image/png")
w.Header().Set("Cache-Control", "max-age=5")
w.WriteHeader(http.StatusOK)
w.Write(fallback)
}
func GetFavicon(w http.ResponseWriter, req *http.Request) {
if utils.LoggedInOnly(w, req) != nil {
return
}
// get url from query string
escsiteurl := req.URL.Query().Get("q")
// URL decode
siteurl, err := url.QueryUnescape(escsiteurl)
if err != nil {
utils.Error("Favicon: URL decode", err)
utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "FA002")
return
}
if(req.Method == "GET") {
utils.Log("Fetch favicon for " + siteurl)
// Check if we have the favicon in cache
if _, ok := cache[siteurl]; ok {
utils.Debug("Favicon in cache")
resp := cache[siteurl]
sendImage(w, resp)
return
}
icons, err := favicon.Find(siteurl)
utils.Debug("Found Favicon: " + strconv.Itoa(len(icons)))
if err != nil {
utils.Error("FaviconFetch", err)
sendFallback(w)
return
}
if len(icons) == 0 {
utils.Error("FaviconFetch", err)
sendFallback(w)
return
}
iconIndex := len(icons)-1
iconChanged := false
for i, icon := range icons {
utils.Debug("Favicon Width: " + icon.URL + " " + strconv.Itoa(icon.Width))
if icon.Width <= 256 {
iconIndex = i
iconChanged = true
break
}
}
if !iconChanged {
iconIndex = 0
}
icon := icons[iconIndex]
utils.Log("Favicon: " + icon.URL)
// Fetch the favicon
resp, err := http.Get(icon.URL)
if err != nil {
utils.Error("FaviconFetch", err)
sendFallback(w)
return
}
// save the body to a file
// out, err := os.Create("favicon.ico")
// if err != nil {
// utils.Error("FaviconFetch", err)
// utils.HTTPError(w, "Favicon Fetch", http.StatusInternalServerError, "FA001")
// return
// }
// defer out.Close()
// _, err = io.Copy(out, resp.Body)
// if err != nil {
// utils.Error("FaviconFetch", err)
// utils.HTTPError(w, "Favicon Fetch", http.StatusInternalServerError, "FA001")
// return
// }
// Cache the response
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
utils.Error("FaviconFetch", err)
sendFallback(w)
return
}
finalImage := CachedImage{
ContentType: resp.Header.Get("Content-Type"),
ETag: resp.Header.Get("ETag"),
Body: body,
}
cache[siteurl] = finalImage
sendImage(w, cache[siteurl])
} else {
utils.Error("Favicon: Method not allowed" + req.Method, nil)
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
return
}
}
func PingURL(w http.ResponseWriter, req *http.Request) {
if utils.LoggedInOnly(w, req) != nil {
return
}
// get url from query string
escsiteurl := req.URL.Query().Get("q")
// URL decode
siteurl, err := url.QueryUnescape(escsiteurl)
if err != nil {
utils.Error("Ping: URL decode", err)
utils.HTTPError(w, "Ping URL decode", http.StatusInternalServerError, "FA002")
return
}
if(req.Method == "GET") {
utils.Log("Ping for " + siteurl)
resp, err := http.Get(siteurl)
if err != nil {
utils.Error("Ping", err)
utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "PI0001")
return
}
if resp.StatusCode >= 500 {
utils.Error("Ping", err)
utils.HTTPError(w, "URL decode", http.StatusInternalServerError, "PI0002")
return
}
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK",
"data": map[string]interface{}{
},
})
} else {
utils.Error("Favicon: Method not allowed" + req.Method, nil)
utils.HTTPError(w, "Method not allowed", http.StatusMethodNotAllowed, "HTTP001")
return
}
}