add configand command line parsing

This commit is contained in:
Iris Lightshard 2023-02-26 14:22:18 -07:00
parent 4ea3e656d6
commit c6c68aa443
Signed by: nilix
GPG key ID: 3B7FBC22144E6398
5 changed files with 221 additions and 15 deletions

View file

@ -154,20 +154,28 @@ func apiUploadMapImg(next http.Handler, udb auth.UserStore, dbAdapter mongodb.Db
// respond with URL? // respond with URL?
} }
return handlerFunc return http.HandlerFunc(handlerFunc)
} }
func CreateAdminInterface(udb auth.UserStore, dbAdapter mongodb.DbAdapter) http.Handler { func CreateAdminInterface(udb auth.UserStore, dbAdapter mongodb.DbAdapter, uploads string, uploadMaxMB int) http.Handler {
// create quartzgun router // create quartzgun router
rtr := &router.Router{Fallback: *template.Must(template.ParseFiles("static/error.html"))} rtr := &router.Router{Fallback: *template.Must(template.ParseFiles("static/error.html"))}
scopes := map[string]string{} scopes := map[string]string{}
rtr.Post("/api/auth/", Provision(udb, 84)) rtr.Post("/api/auth/", Provision(udb, 84))
// table management
rtr.Get("/api/table/", Validate(apiGetTableList(renderer.JSON("tableList"), udb), udb, scopes)) rtr.Get("/api/table/", Validate(apiGetTableList(renderer.JSON("tableList"), udb), udb, scopes))
rtr.Get(`/api/table/(?P<Slug>\S+)`, Validate(apiGetTableData(renderer.JSON("tableData"), udb, dbAdapter), udb, scopes)) rtr.Get(`/api/table/(?P<Slug>\S+)`, Validate(apiGetTableData(renderer.JSON("tableData"), udb, dbAdapter), udb, scopes))
rtr.Post("/api/table/", Validate(apiCreateTable(renderer.JSON("result"), udb, dbAdapter), udb, scopes)) rtr.Post("/api/table/", Validate(apiCreateTable(renderer.JSON("result"), udb, dbAdapter), udb, scopes))
rtr.Delete(`/api/table/(?P<Slug>\S+)`, Validate(apiDestroyTable(renderer.JSON("result"), udb, dbAdapter), udb, scopes)) rtr.Delete(`/api/table/(?P<Slug>\S+)`, Validate(apiDestroyTable(renderer.JSON("result"), udb, dbAdapter), udb, scopes))
// asset management
// POST /api/upload/<table>/map/
// DELETE /api/upload/<table>/map/<map>
// POST /api/upload/<table>/token/
// DELETE /api/upload/<table>/token/<token>
return http.HandlerFunc(rtr.ServeHTTP) return http.HandlerFunc(rtr.ServeHTTP)
} }

View file

@ -1,12 +1,12 @@
package cmd package cmd
import ( import (
"fmt" _ "fmt"
"hacklab.nilfm.cc/quartzgun/auth" "hacklab.nilfm.cc/quartzgun/auth"
"strings" _ "strings"
) )
func ProcessCmd(args []string, userStore auth.UserStore, cfg *Config) bool { func ProcessCmd(args []string, userStore auth.UserStore) bool {
if len(args) == 1 { if len(args) == 1 {
return false return false
} }

187
config/config.go Normal file
View file

@ -0,0 +1,187 @@
package config
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
type Config struct {
Port int
Uploads string
UploadMaxMB int
MongoURI string
}
func GetConfigLocation() string {
home := os.Getenv("HOME")
appdata := os.Getenv("APPDATA")
switch runtime.GOOS {
case "windows":
return filepath.Join(appdata, "felt")
case "darwin":
return filepath.Join(home, "Library", "Application Support", "felt")
case "plan9":
return filepath.Join(home, "lib", "felt")
default:
return filepath.Join(home, ".config", "felt")
}
}
func ensureConfigLocationExists() {
fileInfo, err := os.Stat(GetConfigLocation())
if os.IsNotExist(err) {
os.MkdirAll(GetConfigLocation(), os.ModePerm)
} else if !fileInfo.IsDir() {
panic("Config location is not a directory!")
}
}
func ReadConfig() *Config {
ensureConfigLocationExists()
return parseConfig(filepath.Join(GetConfigLocation(), "felt.conf"))
}
func (self *Config) Write() error {
ensureConfigLocationExists()
return writeConfig(self, filepath.Join(GetConfigLocation(), "felt.conf"))
}
func (self *Config) IsNull() bool {
return self.Port == 0 || self.UploadMaxMB == 0 || self.Uploads == ""
}
func (self *Config) RunWizard() {
fmt.Printf("All options are required.\n")
defer func(cfg *Config) {
if r := recover(); r != nil {
fmt.Printf("Invalid selection, starting over...")
cfg.RunWizard()
}
}(self)
inputBuf := ""
fmt.Printf("MongoDB URI? ")
ensureNonEmptyOption(&inputBuf)
self.MongoURI = inputBuf
inputBuf = ""
fmt.Printf("TCP port? ")
self.Port = ensurePortOption(&inputBuf)
fmt.Printf("file uploads location? ")
ensureNonEmptyOption(&inputBuf)
self.Uploads = inputBuf
inputBuf = ""
fmt.Printf("Max file upload size (MB)? ")
self.UploadMaxMB = ensureNumberOption(&inputBuf)
fmt.Printf("Configuration complete!\n")
self.Write()
}
func ensureNonEmptyOption(buffer *string) {
for {
fmt.Scanln(buffer)
if len(strings.TrimSpace(*buffer)) != 0 {
break
}
fmt.Println("Please enter a nonempty value")
}
}
func ensureBooleanOption(buffer *string) bool {
for {
fmt.Scanln(buffer)
trimmedBuf := strings.TrimSpace(*buffer)
v, err := strconv.ParseBool(trimmedBuf)
if err == nil {
return v
}
fmt.Println("Please enter a true or false value")
}
}
func ensureNumberOption(buffer *string) int {
for {
fmt.Scanln(buffer)
trimmedBuf := strings.TrimSpace(*buffer)
v, err := strconv.ParseInt(trimmedBuf, 10, 32)
if err == nil && v > 0 {
return int(v)
}
fmt.Println("Please enter a positive integer")
}
}
func ensurePortOption(buffer *string) int {
for {
fmt.Scanln(buffer)
trimmedBuf := strings.TrimSpace(*buffer)
v, err := strconv.ParseInt(trimmedBuf, 10, 32)
if err == nil && v > 0 && v <= 65536 {
return int(v)
}
fmt.Println("Please enter a valid port [1, 65536]")
}
}
func writeConfig(cfg *Config, configFile string) error {
f, err := os.Create(configFile)
if err != nil {
return err
}
defer f.Close()
f.WriteString("mongoURI=" + cfg.MongoURI + "\n")
f.WriteString("uploads=" + cfg.Uploads + "\n")
f.WriteString("uploadMaxMB=" + strconv.FormatInt(int64(cfg.UploadMaxMB), 10) + "\n")
f.WriteString("port=" + strconv.FormatInt(int64(cfg.Port), 10) + "\n")
return nil
}
func parseConfig(configFile string) *Config {
f, err := os.ReadFile(configFile)
cfg := &Config{}
if err != nil {
return cfg
}
fileData := string(f[:])
lines := strings.Split(fileData, "\n")
for _, l := range lines {
if len(l) == 0 {
continue
}
if !strings.Contains(l, "=") {
panic("Malformed config not in INI format")
}
kvp := strings.Split(l, "=")
k := strings.TrimSpace(kvp[0])
v := strings.TrimSpace(kvp[1])
switch k {
case "mongoURI":
cfg.MongoURI = v
case "uploads":
cfg.Uploads = v
case "port":
port, _ := strconv.ParseInt(v, 10, 32)
cfg.Port = int(port)
case "uploadMaxMB":
maxUpload, _ := strconv.ParseInt(v, 10, 32)
cfg.UploadMaxMB = int(maxUpload)
default:
panic("Unrecognized config option: " + k)
}
}
return cfg
}

View file

@ -36,7 +36,7 @@ type GameTableServer struct {
dbAdapter mongodb.DbAdapter dbAdapter mongodb.DbAdapter
} }
func New(adapter mongodb.DbAdapter, udb auth.UserStore) *GameTableServer { func New(adapter mongodb.DbAdapter, udb auth.UserStore, uploads string, uploadMaxMB int) *GameTableServer {
srvr := &GameTableServer{ srvr := &GameTableServer{
subscribeMessageBuffer: 16, subscribeMessageBuffer: 16,
logf: log.Printf, logf: log.Printf,
@ -45,7 +45,7 @@ func New(adapter mongodb.DbAdapter, udb auth.UserStore) *GameTableServer {
dbAdapter: adapter, dbAdapter: adapter,
} }
srvr.serveMux.Handle("/table/", http.StripPrefix("/table/", renderer.Subtree("./static"))) srvr.serveMux.Handle("/table/", http.StripPrefix("/table/", renderer.Subtree("./static")))
srvr.serveMux.Handle("/admin/", http.StripPrefix("/admin", admin.CreateAdminInterface(udb, adapter))) srvr.serveMux.Handle("/admin/", http.StripPrefix("/admin", admin.CreateAdminInterface(udb, adapter, uploads, uploadMaxMB)))
srvr.serveMux.HandleFunc("/subscribe", srvr.subscribeHandler) srvr.serveMux.HandleFunc("/subscribe", srvr.subscribeHandler)
srvr.serveMux.HandleFunc("/publish", srvr.publishHandler) srvr.serveMux.HandleFunc("/publish", srvr.publishHandler)

27
main.go
View file

@ -2,6 +2,8 @@ package main
import ( import (
"context" "context"
"hacklab.nilfm.cc/felt/cmd"
"hacklab.nilfm.cc/felt/config"
"hacklab.nilfm.cc/felt/gametable" "hacklab.nilfm.cc/felt/gametable"
"hacklab.nilfm.cc/felt/mongodb" "hacklab.nilfm.cc/felt/mongodb"
"hacklab.nilfm.cc/quartzgun/indentalUserDB" "hacklab.nilfm.cc/quartzgun/indentalUserDB"
@ -10,6 +12,8 @@ import (
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
"path/filepath"
"strconv"
"time" "time"
) )
@ -21,23 +25,30 @@ func main() {
} }
func run() error { func run() error {
l, err := net.Listen("tcp", os.Args[1]) cfg := config.ReadConfig()
if cfg.IsNull() {
cfg.RunWizard()
}
udb := indentalUserDB.CreateIndentalUserDB(
filepath.Join(config.GetConfigLocation(), "user.db"))
if cmd.ProcessCmd(os.Args, udb) {
os.Exit(0)
}
l, err := net.Listen("tcp", ":"+strconv.FormatInt(int64(cfg.Port), 10))
if err != nil { if err != nil {
return err return err
} }
dbEngine := &mongodb.DbEngine{} dbEngine := &mongodb.DbEngine{}
err = dbEngine.Init(os.Args[2]) err = dbEngine.Init(cfg.MongoURI)
if err != nil { if err != nil {
return err return err
} }
udb := indentalUserDB.CreateIndentalUserDB( gt := gametable.New(dbEngine, udb, cfg.Uploads, cfg.UploadMaxMB)
"./user.db")
udb.AddUser("nilix", "questing")
gt := gametable.New(dbEngine, udb)
s := &http.Server{ s := &http.Server{
Handler: gt, Handler: gt,
ReadTimeout: time.Second * 10, ReadTimeout: time.Second * 10,