112 lines
2.7 KiB
Go
112 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"html/template"
|
|
"net/http"
|
|
"waifu_gallery/s3"
|
|
|
|
_ "embed"
|
|
)
|
|
|
|
type LoadingPageContent struct {
|
|
Query string
|
|
GenerationEndpoint string
|
|
}
|
|
|
|
//go:embed loading.html
|
|
var loadingTmpl string
|
|
|
|
// You really wanna serve this endpoint behind WAF / Captcha or whatever and rate limit it to protect your precious tokens
|
|
func serveGenerationEndpoint(w http.ResponseWriter, r *http.Request) {
|
|
// HACK: Making this a /GET route to serve a CF challenge
|
|
|
|
// Validate user input
|
|
input, err := handleSubdomain(w, r)
|
|
if err != nil {
|
|
serveBadSubdomainError(w)
|
|
return
|
|
}
|
|
|
|
_, err = s3.GetMetadata(S3MetadataPrefix + input)
|
|
// We want an error to happen here actually
|
|
if err == nil {
|
|
// Image already generated, bai bai
|
|
http.Redirect(w, r, "/", http.StatusMovedPermanently)
|
|
return
|
|
} else {
|
|
switch s3.ToErrorResponse(err).Code {
|
|
|
|
// Check that we error'd because the image doesn't exist
|
|
case "NoSuchKey":
|
|
// Generate picture or wait on existing generation job
|
|
// Probably not the best way but... if it works?
|
|
if ch, ok := generationQueue.Load(input); !ok {
|
|
// Check number of job requests
|
|
// TODO make this less horribly inefficient (lol)
|
|
var jobNbr int
|
|
generationQueue.Range(func(k, v interface{}) bool {
|
|
jobNbr++
|
|
return true
|
|
})
|
|
if config.MaxConcurrentJobs > 0 && jobNbr >= config.MaxConcurrentJobs {
|
|
w.WriteHeader(http.StatusTooManyRequests)
|
|
w.Write([]byte("Too many images currently being generated, please try again in a few minutes."))
|
|
return
|
|
}
|
|
|
|
// Create channel
|
|
generationQueue.Store(input, make(chan string))
|
|
|
|
// Generate new picture
|
|
InfoLogger.Printf("generating with input '%s'\n", input)
|
|
err := createPicture(input) // where the magic happens
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
ErrorLogger.Println(err)
|
|
return
|
|
}
|
|
|
|
val, _ := generationQueue.Load(input)
|
|
generationQueue.Delete(input)
|
|
if c, ok := val.(chan string); ok {
|
|
// Non-blocking send to queue
|
|
select {
|
|
case c <- input:
|
|
default:
|
|
}
|
|
}
|
|
} else {
|
|
// Wait for job to finish if there's already a generation with the same input going on
|
|
if c, ok := ch.(chan string); ok {
|
|
<-c
|
|
}
|
|
}
|
|
default:
|
|
ErrorLogger.Println(err)
|
|
serveInternalError(w)
|
|
}
|
|
}
|
|
|
|
// Generation succeeded
|
|
w.Write([]byte("picture generated!"))
|
|
}
|
|
|
|
func writeWaitingPage(w http.ResponseWriter, input string) (err error) {
|
|
tmpl, err := template.New("loading").Parse(loadingTmpl)
|
|
if err != nil {
|
|
ErrorLogger.Println(err)
|
|
return
|
|
}
|
|
|
|
tmppData := LoadingPageContent{
|
|
Query: input,
|
|
GenerationEndpoint: "/generate",
|
|
}
|
|
err = tmpl.Execute(w, tmppData)
|
|
if err != nil {
|
|
ErrorLogger.Println(err)
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|