2023-10-08 15:05:12 +01:00
|
|
|
package wordsearch
|
2023-10-08 14:25:57 +01:00
|
|
|
|
|
|
|
import (
|
2023-10-09 09:09:28 +01:00
|
|
|
"embed"
|
|
|
|
"encoding/gob"
|
2023-10-08 14:25:57 +01:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"sort"
|
|
|
|
"text/template"
|
|
|
|
|
|
|
|
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
|
2023-10-08 15:05:12 +01:00
|
|
|
"github.com/ray1729/wordsearch/anagram"
|
|
|
|
"github.com/ray1729/wordsearch/match"
|
2023-10-08 14:25:57 +01:00
|
|
|
"github.com/rs/cors"
|
|
|
|
)
|
|
|
|
|
|
|
|
var anagramDB anagram.DB
|
|
|
|
var matchDB match.DB
|
|
|
|
|
2023-10-09 09:09:28 +01:00
|
|
|
func initializeDB() error {
|
|
|
|
anagrams, err := fs.Open("data/anagram.bin")
|
2023-10-08 14:25:57 +01:00
|
|
|
if err != nil {
|
2023-10-09 09:09:28 +01:00
|
|
|
return err
|
2023-10-08 14:25:57 +01:00
|
|
|
}
|
2023-10-09 09:09:28 +01:00
|
|
|
defer anagrams.Close()
|
|
|
|
if err := gob.NewDecoder(anagrams).Decode(&anagramDB); err != nil {
|
|
|
|
return err
|
2023-10-08 14:25:57 +01:00
|
|
|
}
|
2023-10-09 09:09:28 +01:00
|
|
|
matches, err := fs.Open("data/match.bin")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
2023-10-08 14:25:57 +01:00
|
|
|
}
|
2023-10-09 09:09:28 +01:00
|
|
|
defer matches.Close()
|
|
|
|
if err := gob.NewDecoder(matches).Decode(&matchDB); err != nil {
|
|
|
|
return err
|
2023-10-08 14:25:57 +01:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
log.Println("Initializing databases")
|
2023-10-09 09:09:28 +01:00
|
|
|
if err := initializeDB(); err != nil {
|
|
|
|
log.Fatal(err)
|
2023-10-08 14:25:57 +01:00
|
|
|
}
|
2023-10-08 16:39:55 +01:00
|
|
|
corsHandler := cors.New(cors.Options{
|
|
|
|
AllowedOrigins: []string{"*"},
|
|
|
|
AllowedHeaders: []string{"*"},
|
|
|
|
AllowedMethods: []string{http.MethodPost},
|
|
|
|
AllowCredentials: false,
|
|
|
|
MaxAge: 3600,
|
|
|
|
})
|
2023-10-08 14:25:57 +01:00
|
|
|
log.Println("Registering HTTP function with the Functions Framework")
|
|
|
|
functions.HTTP("WordSearch", func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
corsHandler.ServeHTTP(w, r, handleFormSubmission)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleFormSubmission(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if err := r.ParseForm(); err != nil {
|
|
|
|
log.Printf("error parsing form: %v", err)
|
|
|
|
http.Error(w, "error parsing form", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
mode := r.Form.Get("mode")
|
|
|
|
pattern := r.Form.Get("pattern")
|
|
|
|
if len(pattern) == 0 {
|
|
|
|
http.Error(w, "Missing pattern", http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch mode {
|
|
|
|
case "match":
|
|
|
|
results := matchResults(matchDB, pattern)
|
|
|
|
renderTemplate(w, resultsTmpl, results)
|
|
|
|
case "anagrams":
|
|
|
|
results := anagramResults(anagramDB, pattern)
|
|
|
|
renderTemplate(w, resultsTmpl, results)
|
|
|
|
default:
|
|
|
|
log.Printf("invalid mode: %s", mode)
|
|
|
|
http.Error(w, fmt.Sprintf("Invalid mode: %s", mode), http.StatusBadRequest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func anagramResults(db anagram.DB, pattern string) ResultParams {
|
|
|
|
var params ResultParams
|
|
|
|
params.Results = db.FindAnagrams(pattern)
|
|
|
|
if len(params.Results) > 0 {
|
|
|
|
params.Preamble = fmt.Sprintf("Anagrams of %q:", pattern)
|
|
|
|
} else {
|
|
|
|
params.Preamble = fmt.Sprintf("Found no anagrams of %q", pattern)
|
|
|
|
}
|
|
|
|
sort.Slice(params.Results, func(i, j int) bool { return params.Results[i] < params.Results[j] })
|
|
|
|
return params
|
|
|
|
}
|
|
|
|
|
|
|
|
func matchResults(db match.DB, pattern string) ResultParams {
|
|
|
|
var params ResultParams
|
|
|
|
params.Results = db.FindMatches(pattern)
|
|
|
|
if len(params.Results) > 0 {
|
|
|
|
params.Preamble = fmt.Sprintf("Matches for %q:", pattern)
|
|
|
|
} else {
|
|
|
|
params.Preamble = fmt.Sprintf("Found no matches for %q", pattern)
|
|
|
|
}
|
|
|
|
sort.Slice(params.Results, func(i, j int) bool { return params.Results[i] < params.Results[j] })
|
|
|
|
return params
|
|
|
|
}
|
|
|
|
|
|
|
|
func renderTemplate(w http.ResponseWriter, t *template.Template, params any) {
|
|
|
|
err := t.Execute(w, params)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("Error rendering template %s: %v", t.Name(), err)
|
|
|
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type ResultParams struct {
|
|
|
|
Preamble string
|
|
|
|
Results []string
|
|
|
|
}
|
|
|
|
|
|
|
|
var resultsTmpl = template.Must(template.New("results").Parse(`
|
|
|
|
{{ with .Preamble }}
|
|
|
|
<p>{{ . }}</p>
|
|
|
|
{{ end }}
|
|
|
|
<ul>
|
|
|
|
{{ range .Results }}
|
2024-04-20 15:16:07 +01:00
|
|
|
<li>
|
|
|
|
{{.}}
|
|
|
|
<a href="https://dicoweb.gnu.org.ua/?q={{.}}&db=gcide&define=1" target="defn">GCIDE</a>
|
|
|
|
<a href="https://dicoweb.gnu.org.ua/?q={{.}}&db=WordNet&define=1" target="defn">WordNet</a>
|
|
|
|
<a href="https://dictionary.cambridge.org/dictionary/english/{{.}}" target="defn">Cambridge</a>
|
|
|
|
</li>
|
2023-10-08 14:25:57 +01:00
|
|
|
{{ end }}
|
|
|
|
</ul>
|
|
|
|
`))
|
2023-10-09 09:09:28 +01:00
|
|
|
|
|
|
|
//go:embed data/*
|
|
|
|
var fs embed.FS
|