2022-05-31 05:38:51 +00:00
|
|
|
package archetype
|
2022-05-29 04:45:44 +00:00
|
|
|
|
|
|
|
import (
|
2022-05-29 06:26:36 +00:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
2022-06-15 07:33:56 +00:00
|
|
|
"strconv"
|
2022-05-29 06:26:36 +00:00
|
|
|
"strings"
|
2022-05-29 04:45:44 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Config struct {
|
2022-06-15 07:33:56 +00:00
|
|
|
Adapter Adapter // adapter for this instance
|
|
|
|
Root string // root of the site data
|
|
|
|
StaticRoot string // root of static files for StaticFileManager
|
|
|
|
StaticShowHidden bool // whether to show hidden files in the FileManager
|
|
|
|
StaticShowHTML bool // whether to show html files in the FileManager
|
|
|
|
StaticMaxUploadMB int64 // max size in MB of files uploaded via FileManager
|
|
|
|
AssetRoot string // root of Nirvash dist files (CSS, images)
|
2024-10-27 19:30:20 +00:00
|
|
|
ListenAddress string // address the webserver listens on
|
2022-06-15 07:33:56 +00:00
|
|
|
Plugins map[string]interface{}
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetConfigLocation() string {
|
2022-05-29 06:26:36 +00:00
|
|
|
home := os.Getenv("HOME")
|
|
|
|
appdata := os.Getenv("APPDATA")
|
|
|
|
switch runtime.GOOS {
|
|
|
|
case "windows":
|
|
|
|
return filepath.Join(appdata, "nirvash")
|
|
|
|
case "darwin":
|
|
|
|
return filepath.Join(home, "Library", "Application Support", "nirvash")
|
|
|
|
case "plan9":
|
|
|
|
return filepath.Join(home, "lib", "nirvash")
|
|
|
|
default:
|
|
|
|
return filepath.Join(home, ".config", "nirvash")
|
|
|
|
}
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ensureConfigLocationExists() {
|
2022-05-31 05:38:51 +00:00
|
|
|
fileInfo, err := os.Stat(GetConfigLocation())
|
2022-05-29 06:26:36 +00:00
|
|
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
os.MkdirAll(GetConfigLocation(), os.ModePerm)
|
2022-05-31 05:38:51 +00:00
|
|
|
} else if !fileInfo.IsDir() {
|
|
|
|
panic("Config location is not a directory!")
|
2022-05-29 06:26:36 +00:00
|
|
|
}
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 05:38:51 +00:00
|
|
|
func ReadConfig() *Config {
|
2022-05-29 06:26:36 +00:00
|
|
|
ensureConfigLocationExists()
|
2022-05-29 04:45:44 +00:00
|
|
|
return parseConfig(filepath.Join(GetConfigLocation(), "nirvash.conf"))
|
|
|
|
}
|
|
|
|
|
2022-05-31 05:38:51 +00:00
|
|
|
func (self *Config) Write() error {
|
2022-05-29 06:26:36 +00:00
|
|
|
ensureConfigLocationExists()
|
2022-05-31 05:38:51 +00:00
|
|
|
return writeConfig(self, filepath.Join(GetConfigLocation(), "nirvash.conf"))
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 05:38:51 +00:00
|
|
|
func (self *Config) SetAdapter(adapter string) {
|
|
|
|
switch adapter {
|
2022-05-29 06:26:36 +00:00
|
|
|
case "eureka":
|
2022-05-31 05:38:51 +00:00
|
|
|
self.Adapter = &EurekaAdapter{}
|
2022-05-29 06:26:36 +00:00
|
|
|
default:
|
|
|
|
panic("Unsupported adapter! Try one of [ eureka ]")
|
|
|
|
}
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 05:38:51 +00:00
|
|
|
func (self *Config) IsNull() bool {
|
2022-06-15 07:33:56 +00:00
|
|
|
// zero-values for StaticShowHTML, StaticShowHidden, and StaticMaxUploadMB are valid
|
2024-10-27 19:30:20 +00:00
|
|
|
// zero-value for ListenAddress is also OK, falls back on 127.0.0.1:8080
|
2022-05-31 05:38:51 +00:00
|
|
|
return self.Adapter == nil || len(self.Root) == 0 || len(self.StaticRoot) == 0 || len(self.AssetRoot) == 0
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
2022-05-31 05:38:51 +00:00
|
|
|
func (self *Config) RunWizard() {
|
2022-05-29 06:26:36 +00:00
|
|
|
fmt.Printf("All options are required.\n")
|
|
|
|
defer func(cfg *Config) {
|
|
|
|
if r := recover(); r != nil {
|
|
|
|
fmt.Printf("Invalid selection, starting over...")
|
2022-05-31 05:38:51 +00:00
|
|
|
cfg.RunWizard()
|
2022-05-29 06:26:36 +00:00
|
|
|
}
|
2022-05-31 05:38:51 +00:00
|
|
|
}(self)
|
2022-05-29 06:26:36 +00:00
|
|
|
inputBuf := ""
|
|
|
|
fmt.Printf("adapter? (eureka) [eureka] ")
|
|
|
|
fmt.Scanln(&inputBuf)
|
|
|
|
if len(strings.TrimSpace(inputBuf)) == 0 {
|
|
|
|
inputBuf = "eureka"
|
|
|
|
}
|
2022-05-31 05:38:51 +00:00
|
|
|
self.SetAdapter(inputBuf)
|
2022-05-29 06:26:36 +00:00
|
|
|
|
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("site data root? ")
|
|
|
|
ensureNonEmptyOption(&inputBuf)
|
2022-05-31 05:38:51 +00:00
|
|
|
self.Root = inputBuf
|
2022-05-29 06:26:36 +00:00
|
|
|
|
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("static file root? ")
|
|
|
|
ensureNonEmptyOption(&inputBuf)
|
2022-05-31 05:38:51 +00:00
|
|
|
self.StaticRoot = inputBuf
|
2022-05-29 06:26:36 +00:00
|
|
|
|
2022-06-15 07:33:56 +00:00
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("show HTML files in file manager? ")
|
|
|
|
self.StaticShowHTML = ensureBooleanOption(&inputBuf)
|
|
|
|
|
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("show hidden files in file manager? ")
|
|
|
|
self.StaticShowHidden = ensureBooleanOption(&inputBuf)
|
|
|
|
|
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("max upload size (MB)? ")
|
|
|
|
self.StaticMaxUploadMB = ensureNumberOption(&inputBuf)
|
|
|
|
|
2022-05-29 06:26:36 +00:00
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("nirvash asset root? ")
|
|
|
|
ensureNonEmptyOption(&inputBuf)
|
2022-05-31 05:38:51 +00:00
|
|
|
self.AssetRoot = inputBuf
|
2022-05-29 06:26:36 +00:00
|
|
|
|
2024-10-27 19:30:20 +00:00
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("nirvash listen address? ")
|
|
|
|
ensureNonEmptyOption(&inputBuf)
|
|
|
|
self.ListenAddress = inputBuf
|
|
|
|
|
2022-05-29 06:26:36 +00:00
|
|
|
inputBuf = ""
|
|
|
|
fmt.Printf("plugins? (not implemented yet) ")
|
|
|
|
ensureNonEmptyOption(&inputBuf)
|
2022-05-31 05:38:51 +00:00
|
|
|
//self.Plugins = processPlugins(inputBuf)
|
2022-05-29 06:26:36 +00:00
|
|
|
|
|
|
|
fmt.Printf("Configuration complete!\n")
|
2022-05-31 05:38:51 +00:00
|
|
|
self.Write()
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func ensureNonEmptyOption(buffer *string) {
|
2022-05-29 06:26:36 +00:00
|
|
|
for {
|
|
|
|
fmt.Scanln(buffer)
|
|
|
|
if len(strings.TrimSpace(*buffer)) != 0 {
|
|
|
|
break
|
|
|
|
}
|
2022-06-15 07:33:56 +00:00
|
|
|
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) int64 {
|
|
|
|
for {
|
|
|
|
fmt.Scanln(buffer)
|
|
|
|
trimmedBuf := strings.TrimSpace(*buffer)
|
|
|
|
v, err := strconv.ParseInt(trimmedBuf, 10, 64)
|
|
|
|
if err == nil && v > 0 {
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
fmt.Println("Please enter a positive integer")
|
2022-05-29 06:26:36 +00:00
|
|
|
}
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func writeConfig(cfg *Config, configFile string) error {
|
2022-05-29 06:26:36 +00:00
|
|
|
f, err := os.Create(configFile)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
f.WriteString("root=" + cfg.Root + "\n")
|
|
|
|
f.WriteString("staticRoot=" + cfg.StaticRoot + "\n")
|
2022-06-15 07:33:56 +00:00
|
|
|
f.WriteString("staticShowHTML=" + strconv.FormatBool(cfg.StaticShowHTML) + "\n")
|
|
|
|
f.WriteString("staticShowHidden=" + strconv.FormatBool(cfg.StaticShowHidden) + "\n")
|
|
|
|
f.WriteString("staticMaxUploadMB=" + strconv.FormatInt(cfg.StaticMaxUploadMB, 10) + "\n")
|
2022-05-29 06:26:36 +00:00
|
|
|
f.WriteString("assetRoot=" + cfg.AssetRoot + "\n")
|
2024-10-27 19:30:20 +00:00
|
|
|
f.WriteString("listenAddress=" + cfg.ListenAddress + "\n")
|
2022-05-29 06:26:36 +00:00
|
|
|
f.WriteString("adapter=" + cfg.Adapter.Name() + "\n")
|
|
|
|
f.WriteString("plugins=\n")
|
|
|
|
return nil
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func parseConfig(configFile string) *Config {
|
2022-05-29 06:26:36 +00:00
|
|
|
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 "root":
|
|
|
|
cfg.Root = v
|
|
|
|
case "staticRoot":
|
|
|
|
cfg.StaticRoot = v
|
2022-06-15 07:33:56 +00:00
|
|
|
case "staticShowHTML":
|
|
|
|
cfg.StaticShowHTML, _ = strconv.ParseBool(v)
|
|
|
|
case "staticShowHidden":
|
|
|
|
cfg.StaticShowHidden, _ = strconv.ParseBool(v)
|
|
|
|
case "staticMaxUploadMB":
|
|
|
|
cfg.StaticMaxUploadMB, _ = strconv.ParseInt(v, 10, 64)
|
2022-05-29 06:26:36 +00:00
|
|
|
case "assetRoot":
|
|
|
|
cfg.AssetRoot = v
|
2024-10-27 19:30:20 +00:00
|
|
|
case "listenAddress":
|
|
|
|
cfg.ListenAddress = v
|
2022-05-29 06:26:36 +00:00
|
|
|
case "plugins":
|
|
|
|
// not implemented
|
|
|
|
case "adapter":
|
2022-05-31 05:38:51 +00:00
|
|
|
cfg.SetAdapter(v)
|
2022-05-29 06:26:36 +00:00
|
|
|
default:
|
|
|
|
panic("Unrecognized config option: " + k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cfg
|
2022-05-29 04:45:44 +00:00
|
|
|
}
|