command line arguments
This commit is contained in:
parent
aed21a1e95
commit
375eab8e22
21 changed files with 183 additions and 111 deletions
1
backend/cmd/root.go
Normal file
1
backend/cmd/root.go
Normal file
|
@ -0,0 +1 @@
|
|||
package cmd
|
|
@ -9,6 +9,7 @@ require (
|
|||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/pkg/profile v1.6.0
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/spf13/cobra v1.4.0
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171
|
||||
golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9
|
||||
)
|
||||
|
@ -17,10 +18,12 @@ require (
|
|||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
github.com/fatih/color v1.10.0 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 // indirect
|
||||
)
|
||||
|
|
|
@ -2,6 +2,7 @@ github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdc
|
|||
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
|
||||
github.com/cheggaaa/pb/v3 v3.0.8 h1:bC8oemdChbke2FHIIGy9mn4DPJ2caZYQnfbRqwmdCoA=
|
||||
github.com/cheggaaa/pb/v3 v3.0.8/go.mod h1:UICbiLec/XO6Hw6k+BHEtHeQFzzBH4i2/qk/ow1EJTA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||
|
@ -12,6 +13,8 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
|
@ -23,8 +26,13 @@ github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdL
|
|||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
|
||||
|
@ -39,3 +47,5 @@ golang.org/x/sys v0.0.0-20220422013727-9388b58f7150 h1:xHms4gcpe1YE7A3yIllJXP16C
|
|||
golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
|
105
backend/main.go
105
backend/main.go
|
@ -2,62 +2,89 @@ package main
|
|||
|
||||
import (
|
||||
"embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/pkg/profile"
|
||||
"github.com/robertjanetzko/LegendsBrowser2/backend/model"
|
||||
"github.com/robertjanetzko/LegendsBrowser2/backend/server"
|
||||
"github.com/robertjanetzko/LegendsBrowser2/backend/templates"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
//go:embed static
|
||||
var static embed.FS
|
||||
|
||||
func main() {
|
||||
f := flag.String("f", "", "open a file")
|
||||
p := flag.Bool("p", false, "start profiling")
|
||||
c := flag.String("c", "", "config file")
|
||||
l := flag.Bool("l", false, "open last file")
|
||||
flag.Parse()
|
||||
var (
|
||||
f, c, subUri string
|
||||
l, p, d, s *bool
|
||||
port *int
|
||||
)
|
||||
|
||||
if *p {
|
||||
defer profile.Start(profile.ProfilePath(".")).Stop()
|
||||
go func() {
|
||||
http.ListenAndServe(":8081", nil)
|
||||
}()
|
||||
}
|
||||
|
||||
config, err := server.LoadConfig(*c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
server.DebugJSON = config.DebugJSON
|
||||
templates.DebugTemplates = config.DebugTemplates
|
||||
|
||||
var world *model.DfWorld
|
||||
|
||||
if *l {
|
||||
*f = config.LastFile
|
||||
}
|
||||
|
||||
if len(*f) > 0 {
|
||||
w, err := model.Parse(*f, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
runtime.GC()
|
||||
world = w
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "legendsbrowser",
|
||||
Short: "A Legends Browser for Dwarf Fortress",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if *p {
|
||||
defer profile.Start(profile.ProfilePath(".")).Stop()
|
||||
go func() {
|
||||
http.ListenAndServe(":8081", nil)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
err = server.StartServer(config, world, static)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
config, err := server.LoadConfig(c)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
templates.DebugTemplates = config.DebugTemplates
|
||||
|
||||
server.DebugJSON = *d
|
||||
config.Port = *port
|
||||
config.ServerMode = *s
|
||||
config.SubUri = subUri
|
||||
|
||||
var world *model.DfWorld
|
||||
|
||||
if *l {
|
||||
f = config.LastFile
|
||||
}
|
||||
|
||||
if len(f) > 0 {
|
||||
w, err := model.Parse(f, nil)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
runtime.GC()
|
||||
world = w
|
||||
}
|
||||
}
|
||||
|
||||
err = server.StartServer(config, world, static)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.PersistentFlags().StringVarP(&f, "world", "w", "", "path to legends.xml")
|
||||
rootCmd.PersistentFlags().StringVarP(&c, "config", "c", "", "config file")
|
||||
rootCmd.PersistentFlags().StringVarP(&subUri, "subUri", "u", "", "run on /<subUri>")
|
||||
l = rootCmd.PersistentFlags().BoolP("last", "l", false, "open last file")
|
||||
p = rootCmd.PersistentFlags().BoolP("profile", "P", false, "start profiling")
|
||||
d = rootCmd.PersistentFlags().BoolP("debug", "d", false, "show debug data")
|
||||
s = rootCmd.PersistentFlags().BoolP("serverMode", "s", false, "run in server mode (disables file chooser)")
|
||||
port = rootCmd.PersistentFlags().IntP("port", "p", 58881, "use specific port")
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
func (x *HistoricalEventCollection) Link(s string) string {
|
||||
return fmt.Sprintf(`<a class="collection %s" href="/collection/%d">%s</a>`, strcase.ToKebab(x.Details.Type()), x.Id_, util.Title(s))
|
||||
return fmt.Sprintf(`<a class="collection %s" href="./collection/%d">%s</a>`, strcase.ToKebab(x.Details.Type()), x.Id_, util.Title(s))
|
||||
}
|
||||
|
||||
func (x *HistoricalEventCollection) ParentId() int {
|
||||
|
|
|
@ -57,7 +57,7 @@ func (c *Context) hfUnrelated(id int) string {
|
|||
|
||||
func (c *Context) hfShort(id int) string {
|
||||
if x, ok := c.World.HistoricalFigures[id]; ok {
|
||||
return fmt.Sprintf(`<a class="hf" href="/hf/%d">%s%s</a>`, x.Id(), hfIcon(x), util.Title(x.FirstName()))
|
||||
return fmt.Sprintf(`<a class="hf" href="./hf/%d">%s%s</a>`, x.Id(), hfIcon(x), util.Title(x.FirstName()))
|
||||
}
|
||||
return "UNKNOWN HISTORICAL FIGURE"
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ func (c *Context) hfRelated(id, to int) string {
|
|||
if x, ok := c.World.HistoricalFigures[id]; ok {
|
||||
if t, ok := c.World.HistoricalFigures[to]; ok {
|
||||
if y, ok := util.Find(t.HfLink, func(l *HfLink) bool { return l.Hfid == id }); ok {
|
||||
return fmt.Sprintf(`%s %s <a class="hf" href="/hf/%d">%s%s</a>`, t.PossesivePronoun(), y.LinkType, x.Id(), hfIcon(x), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`%s %s <a class="hf" href="./hf/%d">%s%s</a>`, t.PossesivePronoun(), y.LinkType, x.Id(), hfIcon(x), util.Title(x.Name()))
|
||||
}
|
||||
}
|
||||
return hf(x)
|
||||
|
@ -121,7 +121,7 @@ func hf(x *HistoricalFigure) string {
|
|||
if x.Vampire {
|
||||
r += " vampire"
|
||||
}
|
||||
return fmt.Sprintf(`the %s <a class="hf" href="/hf/%d">%s%s</a>`, r, x.Id(), hfIcon(x), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`the %s <a class="hf" href="./hf/%d">%s%s</a>`, r, x.Id(), hfIcon(x), util.Title(x.Name()))
|
||||
}
|
||||
|
||||
func (c *Context) hfList(ids []int) string {
|
||||
|
@ -134,7 +134,7 @@ func (c *Context) hfListRelated(ids []int, to int) string {
|
|||
|
||||
func (c *Context) artifact(id int) string {
|
||||
if x, ok := c.World.Artifacts[id]; ok {
|
||||
return fmt.Sprintf(`<a class="artifact" href="/artifact/%d"><i class="%s fa-xs"></i> %s</a>`, x.Id(), x.Icon(), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="artifact" href="./artifact/%d"><i class="%s fa-xs"></i> %s</a>`, x.Id(), x.Icon(), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN ARTIFACT"
|
||||
}
|
||||
|
@ -145,7 +145,7 @@ func (c *Context) entity(id int) string {
|
|||
if c != "" {
|
||||
c = fmt.Sprintf(` style="color:%s"`, c)
|
||||
}
|
||||
return fmt.Sprintf(`<a class="entity" href="/entity/%d"><i class="%s fa-xs" %s></i> %s</a>`, x.Id(), x.Icon(), c, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="entity" href="./entity/%d"><i class="%s fa-xs" %s></i> %s</a>`, x.Id(), x.Icon(), c, util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN ENTITY"
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ func (c *Context) siteStructure(siteId, structureId int, prefix string) string {
|
|||
|
||||
func (c *Context) site(id int, prefix string) string {
|
||||
if x, ok := c.World.Sites[id]; ok {
|
||||
return fmt.Sprintf(`%s <a class="site" href="/site/%d"><i class="%s fa-xs%s"></i> %s</a>`, prefix, x.Id(), x.Icon(), util.If(x.Ruin, " ruin", ""), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`%s <a class="site" href="./site/%d"><i class="%s fa-xs%s"></i> %s</a>`, prefix, x.Id(), x.Icon(), util.If(x.Ruin, " ruin", ""), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN SITE"
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (c *Context) site(id int, prefix string) string {
|
|||
func (c *Context) structure(siteId, structureId int) string {
|
||||
if x, ok := c.World.Sites[siteId]; ok {
|
||||
if y, ok := x.Structures[structureId]; ok {
|
||||
return fmt.Sprintf(`<a class="structure" href="/site/%d/structure/%d"><i class="%s fa-xs%s"></i> %s</a>`, siteId, structureId, y.Icon(), util.If(y.Ruin, " ruin", ""), util.Title(y.Name()))
|
||||
return fmt.Sprintf(`<a class="structure" href="./site/%d/structure/%d"><i class="%s fa-xs%s"></i> %s</a>`, siteId, structureId, y.Icon(), util.If(y.Ruin, " ruin", ""), util.Title(y.Name()))
|
||||
}
|
||||
}
|
||||
return "UNKNOWN STRUCTURE"
|
||||
|
@ -207,7 +207,7 @@ func (c *Context) property(siteId, propertyId int) string {
|
|||
|
||||
func (c *Context) region(id int) string {
|
||||
if x, ok := c.World.Regions[id]; ok {
|
||||
return fmt.Sprintf(`<a class="region" href="/region/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="region" href="./region/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN REGION"
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ func (c *Context) place(structureId, siteId int, sitePrefix string, regionId int
|
|||
|
||||
func (c *Context) mountain(id int) string {
|
||||
if x, ok := c.World.MountainPeaks[id]; ok {
|
||||
return fmt.Sprintf(`<a class="mountain" href="/mountain/%d"><i class="fa-solid %s"></i> %s</a>`,
|
||||
return fmt.Sprintf(`<a class="mountain" href="./mountain/%d"><i class="fa-solid %s"></i> %s</a>`,
|
||||
x.Id(), util.If(x.IsVolcano, "fa-volcano", "fa-mountain"), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN MOUNTAIN"
|
||||
|
@ -242,61 +242,61 @@ func (c *Context) mountain(id int) string {
|
|||
|
||||
func (c *Context) landmass(id int) string {
|
||||
if x, ok := c.World.Landmasses[id]; ok {
|
||||
return fmt.Sprintf(`<a class="landmass" href="/landmass/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="landmass" href="./landmass/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN LANDMASS"
|
||||
}
|
||||
|
||||
func (c *Context) river(id int) string {
|
||||
x := c.World.Rivers[id]
|
||||
return fmt.Sprintf(`<a class="river" href="/river/%d">%s</a>`, id, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="river" href="./river/%d">%s</a>`, id, util.Title(x.Name()))
|
||||
}
|
||||
|
||||
func (c *Context) identity(id int) string {
|
||||
if x, ok := c.World.Identities[id]; ok {
|
||||
return fmt.Sprintf(`<a class="identity" href="/identity/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="identity" href="./identity/%d">%s</a>`, x.Id(), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN IDENTITY"
|
||||
}
|
||||
|
||||
func (c *Context) fullIdentity(id int) string {
|
||||
if x, ok := c.World.Identities[id]; ok {
|
||||
return fmt.Sprintf(`"the %s <a class="identity" href="/identity/%d">%s</a> of %s"`, x.Profession.String(), x.Id(), util.Title(x.Name()), c.entity(x.EntityId))
|
||||
return fmt.Sprintf(`"the %s <a class="identity" href="./identity/%d">%s</a> of %s"`, x.Profession.String(), x.Id(), util.Title(x.Name()), c.entity(x.EntityId))
|
||||
}
|
||||
return "UNKNOWN IDENTITY"
|
||||
}
|
||||
|
||||
func (c *Context) danceForm(id int) string {
|
||||
if x, ok := c.World.DanceForms[id]; ok {
|
||||
return fmt.Sprintf(`<a class="artform" href="/danceform/%d"><i class="fa-solid fa-shoe-prints fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="artform" href="./danceform/%d"><i class="fa-solid fa-shoe-prints fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN DANCE FORM"
|
||||
}
|
||||
|
||||
func (c *Context) musicalForm(id int) string {
|
||||
if x, ok := c.World.MusicalForms[id]; ok {
|
||||
return fmt.Sprintf(`<a class="artform" href="/musicalform/%d"><i class="fa-solid fa-music fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="artform" href="./musicalform/%d"><i class="fa-solid fa-music fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN MUSICAL FORM"
|
||||
}
|
||||
|
||||
func (c *Context) poeticForm(id int) string {
|
||||
if x, ok := c.World.PoeticForms[id]; ok {
|
||||
return fmt.Sprintf(`<a class="artform" href="/poeticform/%d"><i class="fa-solid fa-comment-dots fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="artform" href="./poeticform/%d"><i class="fa-solid fa-comment-dots fa-xs"></i> %s</a>`, id, util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN POETIC FORM"
|
||||
}
|
||||
|
||||
func (c *Context) worldConstruction(id int) string {
|
||||
if x, ok := c.World.WorldConstructions[id]; ok {
|
||||
return fmt.Sprintf(`<a class="worldconstruction" href="/worldconstruction/%d"><i class="%s fa-xs"></i> %s</a>`, id, x.Icon(), util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="worldconstruction" href="./worldconstruction/%d"><i class="%s fa-xs"></i> %s</a>`, id, x.Icon(), util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN WORLD CONSTRUCTION"
|
||||
}
|
||||
|
||||
func (c *Context) writtenContent(id int) string {
|
||||
if x, ok := c.World.WrittenContents[id]; ok {
|
||||
return fmt.Sprintf(`<a class="writtencontent" href="/writtencontent/%d">%s</a>`, id, util.Title(x.Name()))
|
||||
return fmt.Sprintf(`<a class="writtencontent" href="./writtencontent/%d">%s</a>`, id, util.Title(x.Name()))
|
||||
}
|
||||
return "UNKNOWN WORLD CONSTRUCTION"
|
||||
}
|
||||
|
|
|
@ -12,8 +12,11 @@ type Config struct {
|
|||
path string
|
||||
LastPath string
|
||||
LastFile string
|
||||
DebugTemplates bool `json:"DebugTemplates,omitempty"`
|
||||
DebugJSON bool `json:"DebugJSON,omitempty"`
|
||||
Port int `json:"-"`
|
||||
ServerMode bool `json:"-"`
|
||||
SubUri string `json:"-"`
|
||||
DebugTemplates bool `json:"DebugTemplates,omitempty"`
|
||||
DebugJSON bool `json:"DebugJSON,omitempty"`
|
||||
}
|
||||
|
||||
func LoadConfig(path string) (*Config, error) {
|
||||
|
|
|
@ -48,6 +48,14 @@ func (h loadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if h.server.context.config.ServerMode {
|
||||
err := h.server.templates.Render(w, "serverMode.html", nil)
|
||||
if err != nil {
|
||||
httpError(w, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var partitions []string
|
||||
if runtime.GOOS == "windows" {
|
||||
ps, _ := disk.Partitions(false)
|
||||
|
@ -95,11 +103,11 @@ func (h loadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
h.server.context.isLoading = true
|
||||
h.server.context.world = nil
|
||||
go loadWorld(h.server, p.Current)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
http.Redirect(w, r, h.server.context.config.SubUri+"/", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
}
|
||||
http.Redirect(w, r, "/load", http.StatusSeeOther)
|
||||
http.Redirect(w, r, h.server.context.config.SubUri+"/load", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func isLegendsXml(f fs.FileInfo) bool {
|
||||
|
@ -126,6 +134,6 @@ func (srv *DfServer) renderLoading(w http.ResponseWriter, r *http.Request) {
|
|||
httpError(w, err)
|
||||
}
|
||||
} else {
|
||||
http.Redirect(w, r, "/load", http.StatusSeeOther)
|
||||
http.Redirect(w, r, srv.context.config.SubUri+"/load", http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,12 @@ func StartServer(config *Config, world *model.DfWorld, static embed.FS) error {
|
|||
progress: &model.LoadProgress{},
|
||||
},
|
||||
}
|
||||
|
||||
root := srv.router
|
||||
if srv.context.config.SubUri != "" {
|
||||
srv.router = srv.router.PathPrefix("/legends").Subrouter()
|
||||
}
|
||||
|
||||
srv.loader = &loadHandler{server: srv}
|
||||
srv.LoadTemplates()
|
||||
|
||||
|
@ -196,10 +202,8 @@ func StartServer(config *Config, world *model.DfWorld, static embed.FS) error {
|
|||
}
|
||||
srv.router.PathPrefix("/").Handler(spa)
|
||||
|
||||
OpenBrowser("http://localhost:8080")
|
||||
|
||||
fmt.Println("Serving at :8080")
|
||||
http.ListenAndServe(":8080", srv.router)
|
||||
OpenBrowser(fmt.Sprintf("http://localhost:%d", config.Port))
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", config.Port), root)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type spaHandler struct {
|
||||
|
@ -18,6 +19,7 @@ type spaHandler struct {
|
|||
func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// get the absolute path to prevent directory traversal
|
||||
path := r.URL.Path
|
||||
path = strings.TrimPrefix(path, h.server.context.config.SubUri)
|
||||
// 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)
|
||||
|
@ -26,8 +28,11 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
// prepend the path with the path to the static directory
|
||||
path = h.staticPath + path
|
||||
|
||||
fmt.Println(path)
|
||||
|
||||
_, err := h.staticFS.Open(path)
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println("ERR")
|
||||
// file does not exist, serve index.html
|
||||
fmt.Println(path)
|
||||
file, err := h.staticFS.Open(h.staticPath + "/" + h.indexPath)
|
||||
|
@ -57,5 +62,5 @@ func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
// otherwise, use http.FileServer to serve the static dir
|
||||
http.FileServer(http.FS(statics)).ServeHTTP(w, r)
|
||||
http.StripPrefix(h.server.context.config.SubUri, http.FileServer(http.FS(statics))).ServeHTTP(w, r)
|
||||
}
|
||||
|
|
|
@ -32,10 +32,11 @@ func (srv *DfServer) LoadTemplates() {
|
|||
"title": util.Title,
|
||||
"kebab": func(s string) string { return strcase.ToKebab(s) },
|
||||
"andList": model.AndList,
|
||||
"suburi": func() string { return srv.context.config.SubUri },
|
||||
"world": func() *model.DfWorld { return srv.context.world },
|
||||
"context": func(r any) *model.Context { return model.NewContext(srv.context.world, r) },
|
||||
"initMap": func() template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<script>var worldWidth = %d, worldHeight = %d;</script><script src="/js/map.js"></script>`,
|
||||
return template.HTML(fmt.Sprintf(`<script>var worldWidth = %d, worldHeight = %d;</script><script src="./js/map.js"></script>`,
|
||||
srv.context.world.Width, srv.context.world.Height))
|
||||
},
|
||||
"hf": func(id int) template.HTML { return model.LinkHf(srv.context.world, id) },
|
||||
|
|
|
@ -21,7 +21,7 @@ func OpenBrowser(url string) {
|
|||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
fmt.Println("navigate to http://localhost:8080 in your browser")
|
||||
fmt.Println("navigate to " + url + " in your browser")
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ map.fitBounds(bounds);
|
|||
|
||||
map.options.minZoom = map.getZoom();
|
||||
|
||||
var imageUrl = '/map'
|
||||
var imageUrl = './map'
|
||||
var imageBounds = [[0, 0],
|
||||
[worldWidth, worldHeight]];
|
||||
|
||||
|
@ -106,7 +106,7 @@ function attachTooltip(layer, tip) {
|
|||
function urlToolTip(type, id) {
|
||||
return function (layer) {
|
||||
return $.ajax({
|
||||
url: "/popover/" + type + "/" + id,
|
||||
url: "./popover/" + type + "/" + id,
|
||||
async: false
|
||||
}).responseText;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
{{define "content"}}
|
||||
<ul>
|
||||
{{- range $t := . }}
|
||||
<li><a href="/events/{{ $t }}">{{ $t }}</a></li>
|
||||
<li><a href="./events/{{ $t }}">{{ $t }}</a></li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
{{- end }}
|
|
@ -3,7 +3,7 @@
|
|||
<li data-event-id="{{ $event.Id }}">
|
||||
In {{ time $event.Year $event.Seconds72 }},
|
||||
{{ html ($event.Details.Html ($.Context.WithEvent $event)) }}
|
||||
{{ if ne .Collection -1 }} <a class="collection" href="/collection/{{.Collection}}"><i
|
||||
{{ if ne .Collection -1 }} <a class="collection" href="./collection/{{.Collection}}"><i
|
||||
class="fa-solid fa-magnifying-glass fa-xs"></i></a>{{end}}
|
||||
{{ json $event.Details }}
|
||||
</li>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</tr>
|
||||
{{- range .Hfs }}{{- if not (eq .Name "") }}
|
||||
<tr>
|
||||
<td><a class="hf" href="/hf/{{.Id}}">{{ title .Name }}</a></td>
|
||||
<td><a class="hf" href="./hf/{{.Id}}">{{ title .Name }}</a></td>
|
||||
<td>{{ .Race }}</td>
|
||||
<td>
|
||||
{{- if eq .DeathYear -1 }}
|
||||
|
@ -34,7 +34,7 @@
|
|||
</div>
|
||||
<div class="col-md-2">
|
||||
<h5>Filter</h5>
|
||||
<form action="/hfs" method="GET">
|
||||
<form action="./hfs" method="GET">
|
||||
<div class="checkbox"><label><input class="filter" type="checkbox" name="leader" value="1" {{if eq .Params.leader "1"
|
||||
}}checked{{end}}> Leader</label></div>
|
||||
<div class="checkbox"><label><input class="filter" type="checkbox" name="deity" value="1" {{if eq .Params.deity "1"
|
||||
|
|
|
@ -2,21 +2,23 @@
|
|||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<base href="{{suburi}}/">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{block "title" .}}{{end}}</title>
|
||||
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="/css/bootstrap-dark.css" rel="stylesheet">
|
||||
<link href="/css/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="/css/all.min.css" rel="stylesheet">
|
||||
<link href="/css/legends.css" rel="stylesheet">
|
||||
<script src="/js/jquery-3.6.0.min.js"></script>
|
||||
<script src="/js/popper.min.js"></script>
|
||||
<script src="/js/bootstrap.min.js"></script>
|
||||
<script src="/js/autocomplete.js"></script>
|
||||
<link href="/leaflet/leaflet.css" rel="stylesheet">
|
||||
<script src="/leaflet/leaflet.js"></script>
|
||||
<link href="./css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="./css/bootstrap-dark.css" rel="stylesheet">
|
||||
<link href="./css/bootstrap-icons.css" rel="stylesheet">
|
||||
<link href="./css/all.min.css" rel="stylesheet">
|
||||
<link href="./css/legends.css" rel="stylesheet">
|
||||
<script src="./js/jquery-3.6.0.min.js"></script>
|
||||
<script src="./js/popper.min.js"></script>
|
||||
<script src="./js/bootstrap.min.js"></script>
|
||||
<script src="./js/autocomplete.js"></script>
|
||||
<link href="./leaflet/leaflet.css" rel="stylesheet">
|
||||
<script src="./leaflet/leaflet.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -30,10 +32,10 @@
|
|||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Civilizations</a>
|
||||
<a class="nav-link" href="./">Civilizations</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/worldmap">World Map</a>
|
||||
<a class="nav-link" href="./worldmap">World Map</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown"
|
||||
|
@ -41,26 +43,26 @@
|
|||
Objects
|
||||
</a>
|
||||
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<li><a class="dropdown-item" href="/geography">Geography</a></li>
|
||||
<li><a class="dropdown-item" href="/entities">Entities</a></li>
|
||||
<li><a class="dropdown-item" href="/sites">Sites</a></li>
|
||||
<li><a class="dropdown-item" href="/structures">Structures</a></li>
|
||||
<li><a class="dropdown-item" href="/hfs">Historical Figures</a></li>
|
||||
<li><a class="dropdown-item" href="/identities">Identities</a></li>
|
||||
<li><a class="dropdown-item" href="/worldconstructions">World Constructions</a></li>
|
||||
<li><a class="dropdown-item" href="/artifacts">Artifacts</a></li>
|
||||
<li><a class="dropdown-item" href="/artforms">Art Forms</a></li>
|
||||
<li><a class="dropdown-item" href="/writtencontents">Written Contents</a></li>
|
||||
<li><a class="dropdown-item" href="./geography">Geography</a></li>
|
||||
<li><a class="dropdown-item" href="./entities">Entities</a></li>
|
||||
<li><a class="dropdown-item" href="./sites">Sites</a></li>
|
||||
<li><a class="dropdown-item" href="./structures">Structures</a></li>
|
||||
<li><a class="dropdown-item" href="./hfs">Historical Figures</a></li>
|
||||
<li><a class="dropdown-item" href="./identities">Identities</a></li>
|
||||
<li><a class="dropdown-item" href="./worldconstructions">World Constructions</a></li>
|
||||
<li><a class="dropdown-item" href="./artifacts">Artifacts</a></li>
|
||||
<li><a class="dropdown-item" href="./artforms">Art Forms</a></li>
|
||||
<li><a class="dropdown-item" href="./writtencontents">Written Contents</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/years">Years</a>
|
||||
<a class="nav-link" href="./years">Years</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/collections">Collections</a>
|
||||
<a class="nav-link" href="./collections">Collections</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="d-flex" action="/search" method="get">
|
||||
<form class="d-flex" action="./search" method="get">
|
||||
<div class="input-group">
|
||||
<input id="search" class="form-control" name="search" type="search" placeholder="Search" aria-label="Search"
|
||||
autocomplete="off">
|
||||
|
@ -71,8 +73,8 @@
|
|||
const ac = new Autocomplete(document.getElementById("search"), {
|
||||
data: [{ label: "I'm a label", value: 42 }],
|
||||
maximumItems: 50,
|
||||
onInput: value => $.get("/search?term=" + value, data => ac.setData(data)),
|
||||
onSelectItem: ({ label, value }) => window.location = value
|
||||
onInput: value => $.get("./search?term=" + value, data => ac.setData(data)),
|
||||
onSelectItem: ({ label, value }) => window.location = "." + value
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
|
@ -96,7 +98,7 @@
|
|||
|
||||
function loadLinkPopoverData() {
|
||||
return $.ajax({
|
||||
url: "/popover" + this.getAttribute("href"),
|
||||
url: "./popover" + this.getAttribute("href").substring(1),
|
||||
async: false
|
||||
}).responseText;
|
||||
}
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
{{- range .Partitions }}
|
||||
<tr>
|
||||
<td><a href="/load?p={{ . }}"><i class="bi bi-hdd"></i> {{ . }}</a></td>
|
||||
<td><a href="./load?p={{ . }}"><i class="bi bi-hdd"></i> {{ . }}</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
{{- end }}
|
||||
|
||||
<tr>
|
||||
<td><a href="/load?p={{ (printf `%s/..` $.Current) }}&x=1"><i class="bi bi-folder2"></i> ..</a></td>
|
||||
<td><a href="./load?p={{ (printf `%s/..` $.Current) }}&x=1"><i class="bi bi-folder2"></i> ..</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
@ -29,7 +29,7 @@
|
|||
{{- range $f := .List }}{{- if $f.IsDir }}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/load?p={{ (printf `%s/%s` $.Current $f.Name) }}"><i class="bi bi-folder2"></i> {{$f.Name}}</a>
|
||||
<a href="./load?p={{ (printf `%s/%s` $.Current $f.Name) }}"><i class="bi bi-folder2"></i> {{$f.Name}}</a>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
|
@ -39,7 +39,7 @@
|
|||
{{- range $f := .List }}{{- if isLegendsXml $f }}
|
||||
<tr>
|
||||
<td>
|
||||
<a class="loadable" href="/load?p={{ (printf `%s/%s` $.Current $f.Name) }}"><i class="bi bi-filetype-xml"></i> {{$f.Name}}</a>
|
||||
<a class="loadable" href="./load?p={{ (printf `%s/%s` $.Current $f.Name) }}"><i class="bi bi-filetype-xml"></i> {{$f.Name}}</a>
|
||||
</td>
|
||||
<td>{{ bytes $f.Size }}</td>
|
||||
<td>{{ $f.ModTime.Format "02 Jan 06 15:04" }}</td>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<script>
|
||||
setInterval(() => {
|
||||
$.ajax({
|
||||
url: "/load/progress",
|
||||
url: "./load/progress",
|
||||
context: document.body,
|
||||
success: function (data) {
|
||||
$("#msg").text(data.msg);
|
||||
|
|
8
backend/templates/serverMode.html
Normal file
8
backend/templates/serverMode.html
Normal file
|
@ -0,0 +1,8 @@
|
|||
{{template "layout.html" .}}
|
||||
|
||||
{{define "title"}}Not available{{end}}
|
||||
|
||||
{{define "content"}}
|
||||
Not available in server mode
|
||||
|
||||
{{- end }}
|
|
@ -16,7 +16,7 @@
|
|||
<div class="col-md-3">
|
||||
<ul>
|
||||
{{end}}
|
||||
<li><a href="/year/{{ $y }}">Year {{ $y }}</a> ({{len $e}} events)</li>
|
||||
<li><a href="./year/{{ $y }}">Year {{ $y }}</a> ({{len $e}} events)</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue