raven/config.go

176 lines
3.9 KiB
Go

package main
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
)
func GetConfigLocation() string {
home := os.Getenv("HOME")
appdata := os.Getenv("APPDATA")
switch runtime.GOOS {
case "windows":
return filepath.Join(appdata, "raven")
case "darwin":
return filepath.Join(home, "Library", "Application Support", "raven")
case "plan9":
return filepath.Join(home, "lib", "raven")
default:
return filepath.Join(home, ".config", "raven")
}
}
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(), "raven.conf"))
}
func (self *Config) Write() error {
ensureConfigLocationExists()
return writeConfig(self, filepath.Join(GetConfigLocation(), "raven.conf"))
}
func (self *Config) IsNull() bool {
// zero-values for StaticShowHTML, StaticShowHidden, and StaticMaxUploadMB are valid
return len(self.Nick) == 0 || len(self.FeedFile) == 0 || len(self.FriendsFile) == 0
}
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("your nickname? ")
ensureNonEmptyOption(&inputBuf)
self.Nick = inputBuf
inputBuf = ""
fmt.Printf("your twtxt file location? ")
ensureNonEmptyOption(&inputBuf)
self.FeedFile = inputBuf
inputBuf = ""
fmt.Printf("your feed in ascending order? ")
self.FeedAscend = ensureBooleanOption(&inputBuf)
inputBuf = ""
fmt.Printf("file location containing your friends' feeds? ")
ensureNonEmptyOption(&inputBuf)
self.FriendsFile = inputBuf
inputBuf = ""
fmt.Printf("number of posts to store in memory? ")
self.MaxPosts = 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) 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 nonnegative integer")
}
}
func writeConfig(cfg *Config, configFile string) error {
f, err := os.Create(configFile)
if err != nil {
return err
}
defer f.Close()
f.WriteString("nick=" + cfg.Nick + "\n")
f.WriteString("feedfile=" + cfg.FeedFile + "\n")
f.WriteString("feed_ascend=" + strconv.FormatBool(cfg.FeedAscend) + "\n")
f.WriteString("friendsfile=" + cfg.FriendsFile + "\n")
f.WriteString("max_posts=" + strconv.FormatInt(cfg.MaxPosts, 10) + "\n")
return nil
}
func parseConfig(configFile string) *Config {
f, err := os.ReadFile(configFile)
cfg := &Config{}
if err != nil {
fmt.Println(err.Error())
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 "feedfile":
cfg.FeedFile = v
case "feed_ascend":
cfg.FeedAscend, _ = strconv.ParseBool(v)
case "friendsfile":
cfg.FriendsFile = v
case "max_posts":
cfg.MaxPosts, _ = strconv.ParseInt(v, 10, 64)
case "nick":
cfg.Nick = v
default:
panic("Unrecognized config option: " + k)
}
}
return cfg
}