diff --git a/Makefile b/Makefile index ac96c30..b6ecc72 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ compile: go1.16rc1 mod download $(info Building) mkdir -p build - CGO_ENABLED=0 go1.16rc1 build -o build/jfa-go *.go + cd build && CGO_ENABLED=0 go1.16rc1 build -o ./jfa-go ../*.go compress: upx --lzma build/jfa-go @@ -67,5 +67,5 @@ copy: install: cp -r build $(DESTDIR)/jfa-go -all: configuration npm email version typescript bundle-css swagger compile copy -debug: configuration npm email version ts-debug bundle-css swagger compile copy +all: configuration npm email version typescript bundle-css swagger copy compile +debug: configuration npm email version ts-debug bundle-css swagger copy compile diff --git a/config.go b/config.go index 51120e6..07e2830 100644 --- a/config.go +++ b/config.go @@ -15,7 +15,7 @@ var emailEnabled = false func (app *appContext) GetPath(sect, key string) (fs.FS, string) { val := app.config.Section(sect).Key(key).MustString("") if strings.HasPrefix(val, "jfa-go:") { - return app.localFS, strings.TrimPrefix(val, "jfa-go:") + return localFS, "build/data/" + strings.TrimPrefix(val, "jfa-go:") } return app.systemFS, val } diff --git a/config/config-base.json b/config/config-base.json index 6731a6e..0547651 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -867,7 +867,7 @@ "requires_restart": true, "type": "text", "value": "", - "description": "Useful if you want to customize the text in jfa-go. Should follow the same structure as the 'lang' directory, which you can see on GitHub." + "description": "The path to a directory CONTAINING a 'lang/' directory, which follow the same form as the internal one. See GitHub for more info." } } } diff --git a/go.mod b/go.mod index 26bd75f..a822fcf 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/hrfee/jfa-go -go 1.14 +go 1.16 replace github.com/hrfee/jfa-go/docs => ./docs @@ -50,8 +50,6 @@ require ( golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect golang.org/x/sys v0.0.0-20210123111255-9b0068b26619 // indirect golang.org/x/text v0.3.5 // indirect - golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 // indirect - golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 // indirect google.golang.org/protobuf v1.25.0 // indirect gopkg.in/ini.v1 v1.62.0 ) diff --git a/go.sum b/go.sum index 2c16804..b183c0f 100644 --- a/go.sum +++ b/go.sum @@ -448,40 +448,10 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190611222205-d73e1c7e250b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 h1:QjA/9ArTfVTLfEhClDCG7SGrZkZixxWpwNCDiwJfh88= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200923182640-463111b69878 h1:VUw1+Jf6KJPf82mbTQMia6HCnNMv2BbAipkEZ4KTcqQ= -golang.org/x/tools v0.0.0-20200923182640-463111b69878/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78 h1:3JUoxVhcskhsIDEc7vg0MUUEpmPPN5TfG+E97z/Fn90= -golang.org/x/tools v0.0.0-20200924182824-0f1c53950d78/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437 h1:XSFqH8m531iIGazX5lrUC9j3slbwsZ1GFByqdUrLqmI= -golang.org/x/tools v0.0.0-20200929191002-f1e51e6b9437/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06 h1:w9ail9jFLaySAm61Zjhciu0LQ5i8YTy2pimlNLx4uuk= -golang.org/x/tools v0.0.0-20201008184944-d01b322e6f06/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201017001424-6003fad69a88 h1:ZB1XYzdDo7c/O48jzjMkvIjnC120Z9/CwgDWhePjQdQ= -golang.org/x/tools v0.0.0-20201017001424-6003fad69a88/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201103235415-b653051172e4 h1:Qe0EMgvVYb6tmJhJHljCj3gS96hvSTkGNaIzp/ivq10= -golang.org/x/tools v0.0.0-20201103235415-b653051172e4/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201113202037-1643af1435f3 h1:7R7+wzd5VuLvCNyHZ/MG511kkoP/DBEzkbh8qUsFbY8= -golang.org/x/tools v0.0.0-20201113202037-1643af1435f3/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b h1:Ych5r0Z6MLML1fgf5hTg9p5bV56Xqx9xv9hLgMBATWs= -golang.org/x/tools v0.0.0-20201114224030-61ea331ec02b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0= golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210101214203-2dba1e4ea05c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee h1:5xKxdl/RhlelmSPaxyVeq5PYSmJ4H14yeQT58qP1F6o= -golang.org/x/tools v0.0.0-20210104081019-d8d6ddbec6ee/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584 h1:JAI5SUo/oOtQXK4jvtjJMlwF5opt8qBUpxGa86SJ6zU= -golang.org/x/tools v0.1.1-0.20210129181147-0cef57b5b584/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1 h1:YRvjnCA/wBOOkQAEKC5ts16/1IJ+NEO9eevhfDF5ues= -golang.org/x/tools/gopls v0.0.0-20210201165201-19db92ec3be1/go.mod h1:DWl5nefYvX46i2mLQVu6Ud0ycJQ3HNPbQKzUHT3VUek= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go index e67e177..7791c6d 100644 --- a/main.go +++ b/main.go @@ -3,6 +3,7 @@ package main import ( "context" "crypto/rand" + "embed" "encoding/base64" "encoding/json" "flag" @@ -50,6 +51,12 @@ type User struct { Password string `json:"password"` } +//go:embed build/data build/data/html build/data/web build/data/web/css build/data/web/js build/data/web/js/ts +var localFS embed.FS + +//go:embed lang/common lang/admin lang/email lang/form lang/setup +var langFS embed.FS + // contains everything the application needs, essentially. Wouldn't do this in the future. type appContext struct { // defaults *Config @@ -59,8 +66,6 @@ type appContext struct { configBase settings dataPath string systemFS fs.FS - localFS fs.FS - langFS fs.FS webFS httpFS cssClass string jellyfinLogin bool @@ -85,8 +90,8 @@ type appContext struct { func (app *appContext) loadHTML(router *gin.Engine) { customPath := app.config.Section("files").Key("html_templates").MustString("") - templatePath := "html" - htmlFiles, err := fs.ReadDir(app.localFS, templatePath) + templatePath := "build/data/html" + htmlFiles, err := fs.ReadDir(localFS, templatePath) if err != nil { app.err.Fatalf("Couldn't access template directory: \"%s\"", templatePath) return @@ -101,7 +106,7 @@ func (app *appContext) loadHTML(router *gin.Engine) { loadFiles[i] = filepath.Join(filepath.Join(customPath, f.Name())) } } - tmpl, err := template.ParseFS(app.localFS, loadFiles...) + tmpl, err := template.ParseFS(localFS, loadFiles...) if err != nil { app.err.Fatalf("Failed to load templates: %v", err) } @@ -200,16 +205,15 @@ func start(asDaemon, firstCall bool) { userConfigDir, _ := os.UserConfigDir() app.dataPath = filepath.Join(userConfigDir, "jfa-go") app.configPath = filepath.Join(app.dataPath, "config.ini") - executable, _ := os.Executable() - app.localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data")) - app.langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang")) + // executable, _ := os.Executable() + // localFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data")) + // langFS = os.DirFS(filepath.Join(filepath.Dir(executable), "data", "lang")) app.systemFS = os.DirFS("/") - wfs := os.DirFS(filepath.Join(filepath.Dir(executable), "data", "web")) + // wfs := os.DirFS(filepath.Join(filepath.Dir(executable), "data", "web")) app.webFS = httpFS{ - hfs: http.FS(wfs), - fs: wfs, + hfs: http.FS(localFS), + fs: localFS, } - app.webFS.fs = wfs app.info = log.New(os.Stdout, "[INFO] ", log.Ltime) app.err = log.New(os.Stdout, "[ERROR] ", log.Ltime|log.Lshortfile) @@ -266,7 +270,7 @@ func start(asDaemon, firstCall bool) { } if _, err := os.Stat(app.configPath); os.IsNotExist(err) { firstRun = true - dConfig, err := fs.ReadFile(app.localFS, "config-default.ini") + dConfig, err := fs.ReadFile(localFS, "build/data/config-default.ini") if err != nil { app.err.Fatalf("Couldn't find default config file") } @@ -341,16 +345,16 @@ func start(asDaemon, firstCall bool) { }() } - app.storage.lang.CommonPath = "common" - app.storage.lang.FormPath = "form" - app.storage.lang.AdminPath = "admin" - app.storage.lang.EmailPath = "email" + app.storage.lang.CommonPath = "lang/common" + app.storage.lang.FormPath = "lang/form" + app.storage.lang.AdminPath = "lang/admin" + app.storage.lang.EmailPath = "lang/email" externalLang := app.config.Section("files").Key("lang_files").MustString("") var err error if externalLang == "" { - err = app.storage.loadLang(app.langFS) + err = app.storage.loadLang(langFS) } else { - err = app.storage.loadLang(app.langFS, os.DirFS(externalLang)) + err = app.storage.loadLang(langFS, os.DirFS(externalLang)) } if err != nil { app.info.Fatalf("Failed to load language files: %+v\n", err) @@ -430,8 +434,8 @@ func start(asDaemon, firstCall bool) { } - app.configBasePath = "config-base.json" - configBase, _ := fs.ReadFile(app.localFS, app.configBasePath) + app.configBasePath = "build/data/config-base.json" + configBase, _ := fs.ReadFile(localFS, app.configBasePath) json.Unmarshal(configBase, &app.configBase) themes := map[string]string{ @@ -579,8 +583,8 @@ func start(asDaemon, firstCall bool) { } else { debugMode = false address = "0.0.0.0:8056" - app.storage.lang.SetupPath = filepath.Join("lang", "setup") - err := app.storage.loadLangSetup() + app.storage.lang.SetupPath = "lang/setup" + err := app.storage.loadLangSetup(langFS) if err != nil { app.info.Fatalf("Failed to load language files: %+v\n", err) } diff --git a/setup.go b/setup.go index 307ca1f..a1771f8 100644 --- a/setup.go +++ b/setup.go @@ -120,6 +120,7 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error { return err } english = st.lang.Setup["en-us"] + setupLoaded := false for _, filesystem := range filesystems { files, err := fs.ReadDir(filesystem, st.lang.SetupPath) if err != nil { @@ -128,11 +129,14 @@ func (st *Storage) loadLangSetup(filesystems ...fs.FS) error { for _, f := range files { if f.Name() != "en-us.json" { err = load(filesystem, f.Name()) - if err != nil { - return err + if err == nil { + setupLoaded = true } } } } + if !setupLoaded { + return err + } return nil } diff --git a/static.go b/static.go index 346eef5..ea620f5 100644 --- a/static.go +++ b/static.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "io/fs" "net/http" "strings" @@ -14,12 +15,13 @@ type httpFS struct { } func (f httpFS) Open(name string) (http.File, error) { - return f.hfs.Open(name) + fmt.Println("build/data/web" + name) + return f.hfs.Open("build/data/web" + name) } func (f httpFS) Exists(prefix string, filepath string) bool { if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) { - stats, err := fs.Stat(f.fs, p) + stats, err := fs.Stat(f.fs, "build/data/web/"+p) if err != nil { return false }