2022-04-09 12:01:04 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2022-04-15 17:46:51 +03:00
|
|
|
"embed"
|
2022-04-16 21:34:19 +03:00
|
|
|
"encoding/json"
|
2022-04-13 08:28:07 +03:00
|
|
|
"flag"
|
2022-04-09 12:01:04 +03:00
|
|
|
"fmt"
|
2022-04-16 21:34:19 +03:00
|
|
|
"html/template"
|
2022-04-15 17:46:51 +03:00
|
|
|
"io/fs"
|
2022-04-09 12:01:04 +03:00
|
|
|
"net/http"
|
2022-04-11 00:27:37 +03:00
|
|
|
_ "net/http/pprof"
|
2022-04-14 16:49:09 +03:00
|
|
|
"os"
|
2022-04-11 00:27:37 +03:00
|
|
|
"runtime"
|
2022-04-18 11:36:29 +03:00
|
|
|
"sort"
|
2022-04-16 21:34:19 +03:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2022-04-09 12:01:04 +03:00
|
|
|
|
|
|
|
"github.com/gorilla/mux"
|
2022-04-13 08:28:07 +03:00
|
|
|
"github.com/pkg/profile"
|
2022-04-14 18:39:18 +03:00
|
|
|
"github.com/robertjanetzko/LegendsBrowser2/backend/model"
|
2022-04-16 21:34:19 +03:00
|
|
|
"github.com/robertjanetzko/LegendsBrowser2/backend/templates"
|
2022-04-19 18:46:11 +03:00
|
|
|
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
2022-04-09 12:01:04 +03:00
|
|
|
)
|
|
|
|
|
2022-04-14 18:39:18 +03:00
|
|
|
var world *model.DfWorld
|
2022-04-09 12:01:04 +03:00
|
|
|
|
2022-04-19 12:46:43 +03:00
|
|
|
//go:embed static
|
|
|
|
var static embed.FS
|
2022-04-15 17:46:51 +03:00
|
|
|
|
2022-04-09 12:01:04 +03:00
|
|
|
func main() {
|
2022-04-13 15:01:20 +03:00
|
|
|
f := flag.String("f", "", "open a file")
|
|
|
|
flag.Parse()
|
|
|
|
|
2022-04-15 17:46:51 +03:00
|
|
|
router := mux.NewRouter().StrictSlash(true)
|
|
|
|
|
2022-04-16 21:34:19 +03:00
|
|
|
functions := template.FuncMap{
|
|
|
|
"json": func(obj any) string {
|
|
|
|
b, err := json.MarshalIndent(obj, "", " ")
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return string(b)
|
|
|
|
},
|
|
|
|
"check": func(condition bool, v any) any {
|
|
|
|
if condition {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
"title": func(input string) string {
|
|
|
|
words := strings.Split(input, " ")
|
|
|
|
smallwords := " a an on the to of "
|
|
|
|
|
|
|
|
for index, word := range words {
|
|
|
|
if strings.Contains(smallwords, " "+word+" ") && index > 0 {
|
|
|
|
words[index] = word
|
|
|
|
} else {
|
|
|
|
words[index] = strings.Title(word)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return strings.Join(words, " ")
|
|
|
|
},
|
|
|
|
"getHf": func(id int) *model.HistoricalFigure { return world.HistoricalFigures[id] },
|
|
|
|
"getEntity": func(id int) *model.Entity { return world.Entities[id] },
|
2022-04-16 23:12:23 +03:00
|
|
|
"events": func(obj model.Identifiable) []*model.HistoricalEvent {
|
|
|
|
id := obj.Id()
|
|
|
|
var list []*model.HistoricalEvent
|
|
|
|
switch obj.(type) {
|
2022-04-18 11:36:29 +03:00
|
|
|
case *model.Entity:
|
|
|
|
for _, e := range world.HistoricalEvents {
|
|
|
|
if e.Details.RelatedToEntity(id) {
|
|
|
|
list = append(list, e)
|
|
|
|
}
|
|
|
|
}
|
2022-04-16 23:12:23 +03:00
|
|
|
case *model.HistoricalFigure:
|
|
|
|
for _, e := range world.HistoricalEvents {
|
|
|
|
if e.Details.RelatedToHf(id) {
|
|
|
|
list = append(list, e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
fmt.Printf("unknown type %T\n", obj)
|
|
|
|
}
|
2022-04-18 11:36:29 +03:00
|
|
|
sort.Slice(list, func(a, b int) bool { return list[a].Id_ < list[b].Id_ })
|
2022-04-16 23:12:23 +03:00
|
|
|
return list
|
|
|
|
},
|
2022-04-18 11:36:29 +03:00
|
|
|
"season": func(seconds int) string {
|
|
|
|
r := ""
|
|
|
|
month := seconds % 100800
|
|
|
|
if month <= 33600 {
|
|
|
|
r += "early "
|
|
|
|
} else if month <= 67200 {
|
|
|
|
r += "mid"
|
|
|
|
} else if month <= 100800 {
|
|
|
|
r += "late "
|
|
|
|
}
|
|
|
|
|
|
|
|
season := seconds % 403200
|
|
|
|
if season < 100800 {
|
|
|
|
r += "spring"
|
|
|
|
} else if season < 201600 {
|
|
|
|
r += "summer"
|
|
|
|
} else if season < 302400 {
|
|
|
|
r += "autumn"
|
|
|
|
} else if season < 403200 {
|
|
|
|
r += "winter"
|
|
|
|
}
|
|
|
|
|
|
|
|
return r
|
|
|
|
},
|
2022-04-19 12:46:43 +03:00
|
|
|
"html": func(value any) template.HTML {
|
|
|
|
return template.HTML(fmt.Sprint(value))
|
|
|
|
},
|
2022-04-16 21:34:19 +03:00
|
|
|
}
|
|
|
|
t := templates.New(functions)
|
|
|
|
|
2022-04-13 15:01:20 +03:00
|
|
|
if len(*f) > 0 {
|
2022-04-14 16:49:09 +03:00
|
|
|
defer profile.Start(profile.MemProfile).Stop()
|
|
|
|
go func() {
|
|
|
|
http.ListenAndServe(":8081", nil)
|
|
|
|
}()
|
|
|
|
|
2022-04-14 18:39:18 +03:00
|
|
|
w, err := model.Parse(*f)
|
2022-04-13 15:01:20 +03:00
|
|
|
if err != nil {
|
|
|
|
fmt.Println(err)
|
2022-04-14 16:49:09 +03:00
|
|
|
os.Exit(1)
|
2022-04-13 15:01:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
world = w
|
2022-04-09 12:01:04 +03:00
|
|
|
|
2022-04-14 16:49:09 +03:00
|
|
|
fmt.Println("Hallo Welt!")
|
|
|
|
runtime.GC()
|
|
|
|
// world.Process()
|
|
|
|
|
|
|
|
// model.ListOtherElements("world", &[]*model.World{&world})
|
|
|
|
// model.ListOtherElements("region", &world.Regions)
|
|
|
|
// model.ListOtherElements("underground regions", &world.UndergroundRegions)
|
|
|
|
// model.ListOtherElements("landmasses", &world.Landmasses)
|
|
|
|
// model.ListOtherElements("sites", &world.Sites)
|
|
|
|
// model.ListOtherElements("world constructions", &world.WorldConstructions)
|
|
|
|
// model.ListOtherElements("artifacts", &world.Artifacts)
|
|
|
|
// model.ListOtherElements("entities", &world.Entities)
|
|
|
|
// model.ListOtherElements("hf", &world.HistoricalFigures)
|
|
|
|
// model.ListOtherElements("events", &world.HistoricalEvents)
|
|
|
|
// model.ListOtherElements("collections", &world.HistoricalEventCollections)
|
|
|
|
// model.ListOtherElements("era", &world.HistoricalEras)
|
|
|
|
// model.ListOtherElements("danceForm", &world.DanceForms)
|
|
|
|
// model.ListOtherElements("musicalForm", &world.MusicalForms)
|
|
|
|
// model.ListOtherElements("poeticForm", &world.PoeticForms)
|
|
|
|
// model.ListOtherElements("written", &world.WrittenContents)
|
|
|
|
|
2022-04-16 23:12:23 +03:00
|
|
|
// server.RegisterResource(router, "region", world.Regions)
|
|
|
|
// // server.RegisterResource(router, "undergroundRegion", world.UndergroundRegions)
|
|
|
|
// server.RegisterResource(router, "landmass", world.Landmasses)
|
|
|
|
// server.RegisterResource(router, "site", world.Sites)
|
|
|
|
// server.RegisterResource(router, "worldConstruction", world.WorldConstructions)
|
|
|
|
// server.RegisterResource(router, "artifact", world.Artifacts)
|
|
|
|
// server.RegisterResource(router, "hf", world.HistoricalFigures)
|
|
|
|
// server.RegisterResource(router, "collection", world.HistoricalEventCollections)
|
|
|
|
// server.RegisterResource(router, "entity", world.Entities)
|
|
|
|
// server.RegisterResource(router, "event", world.HistoricalEvents)
|
|
|
|
// // server.RegisterResource(router, "era", world.HistoricalEras)
|
|
|
|
// server.RegisterResource(router, "danceForm", world.DanceForms)
|
|
|
|
// server.RegisterResource(router, "musicalForm", world.MusicalForms)
|
|
|
|
// server.RegisterResource(router, "poeticForm", world.PoeticForms)
|
2022-04-14 16:49:09 +03:00
|
|
|
// server.RegisterResource(router, "written", world.WrittenContents)
|
2022-04-16 21:34:19 +03:00
|
|
|
|
2022-04-19 18:46:11 +03:00
|
|
|
RegisterResourcePage(router, "/entity/{id}", t, "entity.html", func(id int) any { return world.Entities[id] })
|
|
|
|
RegisterResourcePage(router, "/hf/{id}", t, "hf.html", func(id int) any { return world.HistoricalFigures[id] })
|
|
|
|
RegisterPage(router, "/events", t, "eventTypes.html", func(p Parms) any { return allEventTypes() })
|
|
|
|
RegisterPage(router, "/events/{type}", t, "eventType.html", func(p Parms) any { return eventsOfType(p["type"]) })
|
2022-04-15 17:46:51 +03:00
|
|
|
}
|
|
|
|
|
2022-04-19 12:46:43 +03:00
|
|
|
spa := spaHandler{staticFS: static, staticPath: "static", indexPath: "index.html"}
|
2022-04-15 17:46:51 +03:00
|
|
|
router.PathPrefix("/").Handler(spa)
|
|
|
|
|
|
|
|
fmt.Println("Serving at :8080")
|
|
|
|
http.ListenAndServe(":8080", router)
|
2022-04-19 18:46:11 +03:00
|
|
|
}
|
2022-04-14 16:49:09 +03:00
|
|
|
|
2022-04-19 18:46:11 +03:00
|
|
|
func allEventTypes() []string {
|
|
|
|
types := make(map[string]bool)
|
|
|
|
for _, e := range world.HistoricalEvents {
|
|
|
|
types[e.Details.Type()] = true
|
|
|
|
}
|
|
|
|
var list = util.Keys(types)
|
|
|
|
sort.Strings(list)
|
|
|
|
return list
|
2022-04-15 17:46:51 +03:00
|
|
|
}
|
|
|
|
|
2022-04-19 18:46:11 +03:00
|
|
|
func eventsOfType(t string) any {
|
|
|
|
var list []*model.HistoricalEvent
|
|
|
|
for _, e := range world.HistoricalEvents {
|
|
|
|
if e.Details.Type() == t {
|
|
|
|
list = append(list, e)
|
2022-04-16 21:34:19 +03:00
|
|
|
}
|
2022-04-19 18:46:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
sort.Slice(list, func(i, j int) bool { return list[i].Id_ < list[j].Id_ })
|
|
|
|
|
|
|
|
return struct {
|
|
|
|
Type string
|
|
|
|
Events []*model.HistoricalEvent
|
|
|
|
}{
|
|
|
|
Type: t,
|
|
|
|
Events: list,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type Parms map[string]string
|
|
|
|
|
|
|
|
func RegisterPage(router *mux.Router, path string, templates *templates.Template, template string, accessor func(Parms) any) {
|
|
|
|
get := func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
err := templates.Render(w, template, accessor(mux.Vars(r)))
|
2022-04-16 21:34:19 +03:00
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintln(w, err)
|
|
|
|
fmt.Println(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
router.HandleFunc(path, get).Methods("GET")
|
|
|
|
}
|
|
|
|
|
2022-04-19 18:46:11 +03:00
|
|
|
func RegisterResourcePage(router *mux.Router, path string, templates *templates.Template, template string, accessor func(int) any) {
|
|
|
|
RegisterPage(router, path, templates, template, func(params Parms) any {
|
|
|
|
id, _ := strconv.Atoi(params["id"])
|
|
|
|
return accessor(id)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-15 17:46:51 +03:00
|
|
|
type spaHandler struct {
|
|
|
|
staticFS embed.FS
|
|
|
|
staticPath string
|
|
|
|
indexPath string
|
|
|
|
}
|
2022-04-14 16:49:09 +03:00
|
|
|
|
2022-04-15 17:46:51 +03:00
|
|
|
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// get the absolute path to prevent directory traversal
|
|
|
|
path := r.URL.Path
|
|
|
|
// if err != nil {
|
|
|
|
// // if we failed to get the absolute path respond with a 400 bad request and stop
|
|
|
|
// http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
// prepend the path with the path to the static directory
|
|
|
|
path = h.staticPath + path
|
2022-04-19 12:46:43 +03:00
|
|
|
fmt.Println(r.URL, "->", path)
|
2022-04-15 17:46:51 +03:00
|
|
|
|
|
|
|
_, err := h.staticFS.Open(path)
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
// file does not exist, serve index.html
|
|
|
|
fmt.Println(path)
|
|
|
|
index, err := h.staticFS.ReadFile(h.staticPath + "/" + h.indexPath)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
|
|
w.WriteHeader(http.StatusAccepted)
|
|
|
|
w.Write(index)
|
|
|
|
return
|
|
|
|
} else if err != nil {
|
|
|
|
// if we got an error (that wasn't that the file doesn't exist) stating the
|
|
|
|
// file, return a 500 internal server error and stop
|
|
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
|
|
return
|
2022-04-14 16:49:09 +03:00
|
|
|
}
|
2022-04-09 19:37:44 +03:00
|
|
|
|
2022-04-15 17:46:51 +03:00
|
|
|
// get the subdirectory of the static dir
|
|
|
|
statics, err := fs.Sub(h.staticFS, h.staticPath)
|
|
|
|
// otherwise, use http.FileServer to serve the static dir
|
|
|
|
http.FileServer(http.FS(statics)).ServeHTTP(w, r)
|
2022-04-09 12:01:04 +03:00
|
|
|
}
|