amfora/config/config.go

284 lines
7.5 KiB
Go
Raw Normal View History

// Package config initializes all files required for Amfora, even those used by
// other packages. It also reads in the config file and initializes a Viper and
// the theme
2020-11-05 03:40:34 +03:00
//nolint:golint,goerr113
2020-06-18 23:54:48 +03:00
package config
import (
2020-07-10 02:28:39 +03:00
"fmt"
2020-06-18 23:54:48 +03:00
"os"
"path/filepath"
"runtime"
2020-06-22 18:56:55 +03:00
"strings"
2020-06-18 23:54:48 +03:00
2020-07-28 23:58:32 +03:00
"github.com/gdamore/tcell"
2020-06-18 23:54:48 +03:00
"github.com/makeworld-the-better-one/amfora/cache"
homedir "github.com/mitchellh/go-homedir"
"github.com/rkoesters/xdg/basedir"
"github.com/rkoesters/xdg/userdirs"
2020-06-18 23:54:48 +03:00
"github.com/spf13/viper"
2020-07-28 23:58:32 +03:00
"gitlab.com/tslocum/cview"
2020-06-18 23:54:48 +03:00
)
var amforaAppData string // Where amfora files are stored on Windows - cached here
var configDir string
var configPath string
2020-06-18 23:54:48 +03:00
2020-09-01 20:55:09 +03:00
var NewTabPath string
var CustomNewTab bool
2020-06-18 23:54:48 +03:00
var TofuStore = viper.New()
var tofuDBDir string
var tofuDBPath string
2020-06-18 23:54:48 +03:00
// Bookmarks
var BkmkStore = viper.New()
var bkmkDir string
var bkmkPath string
2020-07-10 02:28:39 +03:00
var DownloadsDir string
2020-11-28 01:01:29 +03:00
// Subscriptions
var subscriptionDir string
var SubscriptionPath string
2020-08-07 19:27:50 +03:00
2020-11-05 02:35:56 +03:00
// Command for opening HTTP(S) URLs in the browser, from "a-general.http" in config.
2020-11-05 02:47:27 +03:00
var HTTPCommand []string
2020-11-05 02:35:56 +03:00
2020-06-18 23:54:48 +03:00
func Init() error {
2020-08-07 19:27:50 +03:00
// *** Set paths ***
2020-06-18 23:54:48 +03:00
home, err := homedir.Dir()
if err != nil {
2020-07-10 02:28:39 +03:00
return err
2020-06-18 23:54:48 +03:00
}
// Store AppData path
if runtime.GOOS == "windows" { //nolint:goconst
2020-06-18 23:54:48 +03:00
appdata, ok := os.LookupEnv("APPDATA")
if ok {
amforaAppData = filepath.Join(appdata, "amfora")
} else {
amforaAppData = filepath.Join(home, filepath.FromSlash("AppData/Roaming/amfora/"))
}
}
// Store config directory and file paths
if runtime.GOOS == "windows" {
configDir = amforaAppData
} else {
// Unix / POSIX system
2020-10-12 21:48:21 +03:00
configDir = filepath.Join(basedir.ConfigHome, "amfora")
}
configPath = filepath.Join(configDir, "config.toml")
2020-09-01 20:55:09 +03:00
// Search for a custom new tab
NewTabPath = filepath.Join(configDir, "newtab.gmi")
CustomNewTab = false
if _, err := os.Stat(NewTabPath); err == nil {
CustomNewTab = true
}
// Store TOFU db directory and file paths
if runtime.GOOS == "windows" {
2020-06-22 18:56:55 +03:00
// Windows just stores it in APPDATA along with other stuff
tofuDBDir = amforaAppData
} else {
// XDG cache dir on POSIX systems
2020-10-12 21:48:21 +03:00
tofuDBDir = filepath.Join(basedir.CacheHome, "amfora")
}
tofuDBPath = filepath.Join(tofuDBDir, "tofu.toml")
2020-06-18 23:54:48 +03:00
// Store bookmarks dir and path
if runtime.GOOS == "windows" {
// Windows just keeps it in APPDATA along with other Amfora files
bkmkDir = amforaAppData
} else {
// XDG data dir on POSIX systems
2020-10-12 21:48:21 +03:00
bkmkDir = filepath.Join(basedir.DataHome, "amfora")
}
bkmkPath = filepath.Join(bkmkDir, "bookmarks.toml")
// Feeds dir and path
if runtime.GOOS == "windows" {
// In APPDATA beside other Amfora files
2020-11-28 01:01:29 +03:00
subscriptionDir = amforaAppData
} else {
// XDG data dir on POSIX systems
xdg_data, ok := os.LookupEnv("XDG_DATA_HOME")
if ok && strings.TrimSpace(xdg_data) != "" {
2020-11-28 01:01:29 +03:00
subscriptionDir = filepath.Join(xdg_data, "amfora")
} else {
// Default to ~/.local/share/amfora
2020-11-28 01:01:29 +03:00
subscriptionDir = filepath.Join(home, ".local", "share", "amfora")
}
}
2020-11-28 01:01:29 +03:00
SubscriptionPath = filepath.Join(subscriptionDir, "subscriptions.json")
2020-08-07 19:27:50 +03:00
// *** Create necessary files and folders ***
// Config
err = os.MkdirAll(configDir, 0755)
2020-06-18 23:54:48 +03:00
if err != nil {
return err
}
f, err := os.OpenFile(configPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
2020-06-18 23:54:48 +03:00
if err == nil {
// Config file doesn't exist yet, write the default one
_, err = f.Write(defaultConf)
if err != nil {
f.Close()
return err
}
f.Close()
}
// TOFU
err = os.MkdirAll(tofuDBDir, 0755)
2020-06-18 23:54:48 +03:00
if err != nil {
return err
}
2020-08-07 19:27:50 +03:00
f, err = os.OpenFile(tofuDBPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err == nil {
f.Close()
}
// Bookmarks
err = os.MkdirAll(bkmkDir, 0755)
if err != nil {
return err
}
2020-08-07 19:27:50 +03:00
f, err = os.OpenFile(bkmkPath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
if err == nil {
f.Close()
}
// Feeds
2020-11-28 01:01:29 +03:00
err = os.MkdirAll(subscriptionDir, 0755)
if err != nil {
return err
}
2020-08-07 19:27:50 +03:00
// *** Downloads paths, setup, and creation ***
// Setup downloads dir
if viper.GetString("a-general.downloads") == "" {
// Find default Downloads dir
// This seems to work for all OSes?
if userdirs.Download == "" {
DownloadsDir = filepath.Join(home, "Downloads")
} else {
DownloadsDir = userdirs.Download
}
2020-08-07 19:27:50 +03:00
// Create it just in case
err = os.MkdirAll(DownloadsDir, 0755)
if err != nil {
return fmt.Errorf("downloads path could not be created: %s", DownloadsDir)
}
} else {
// Validate path
dDir := viper.GetString("a-general.downloads")
di, err := os.Stat(dDir)
if err == nil {
if !di.IsDir() {
return fmt.Errorf("downloads path specified is not a directory: %s", dDir)
}
} else if os.IsNotExist(err) {
// Try to create path
err = os.MkdirAll(dDir, 0755)
if err != nil {
return fmt.Errorf("downloads path could not be created: %s", dDir)
}
} else {
// Some other error
return fmt.Errorf("couldn't access downloads directory: %s", dDir)
}
DownloadsDir = dDir
}
// *** Setup vipers ***
2020-06-18 23:54:48 +03:00
TofuStore.SetConfigFile(tofuDBPath)
2020-06-18 23:54:48 +03:00
TofuStore.SetConfigType("toml")
err = TofuStore.ReadInConfig()
if err != nil {
return err
}
BkmkStore.SetConfigFile(bkmkPath)
BkmkStore.SetConfigType("toml")
err = BkmkStore.ReadInConfig()
if err != nil {
return err
}
BkmkStore.Set("DO NOT TOUCH", true)
err = BkmkStore.WriteConfig()
if err != nil {
return err
}
2020-08-07 19:27:50 +03:00
// Setup main config
2020-06-18 23:54:48 +03:00
viper.SetDefault("a-general.home", "gemini.circumlunar.space")
viper.SetDefault("a-general.auto_redirect", false)
2020-06-18 23:54:48 +03:00
viper.SetDefault("a-general.http", "default")
viper.SetDefault("a-general.search", "gus.guru/search")
viper.SetDefault("a-general.color", true)
viper.SetDefault("a-general.ansi", true)
2020-06-18 23:54:48 +03:00
viper.SetDefault("a-general.bullets", true)
viper.SetDefault("a-general.show_link", false)
viper.SetDefault("a-general.left_margin", 0.15)
viper.SetDefault("a-general.max_width", 100)
2020-07-10 02:28:39 +03:00
viper.SetDefault("a-general.downloads", "")
viper.SetDefault("a-general.page_max_size", 2097152)
viper.SetDefault("a-general.page_max_time", 10)
2020-08-05 20:31:59 +03:00
viper.SetDefault("a-general.emoji_favicons", false)
2020-08-06 20:55:43 +03:00
viper.SetDefault("keybindings.shift_numbers", "!@#$%^&*()")
viper.SetDefault("url-handlers.other", "off")
2020-06-18 23:54:48 +03:00
viper.SetDefault("cache.max_size", 0)
viper.SetDefault("cache.max_pages", 20)
2020-11-28 01:01:29 +03:00
viper.SetDefault("subscriptions.popup", true)
viper.SetDefault("subscriptions.update_interval", 1800)
viper.SetDefault("subscriptions.workers", 3)
2020-12-07 04:57:57 +03:00
viper.SetDefault("subscriptions.entries_per_page", 20)
2020-06-18 23:54:48 +03:00
viper.SetConfigFile(configPath)
2020-06-18 23:54:48 +03:00
viper.SetConfigType("toml")
err = viper.ReadInConfig()
if err != nil {
return err
}
// Setup cache from config
cache.SetMaxSize(viper.GetInt("cache.max_size"))
cache.SetMaxPages(viper.GetInt("cache.max_pages"))
2020-08-07 19:27:50 +03:00
// Setup theme
2020-07-28 23:58:32 +03:00
configTheme := viper.Sub("theme")
if configTheme != nil {
for k, v := range configTheme.AllSettings() {
colorStr, ok := v.(string)
if !ok {
return fmt.Errorf(`value for "%s" is not a string: %v`, k, v)
}
color := tcell.GetColor(strings.ToLower(colorStr))
if color == tcell.ColorDefault {
return fmt.Errorf(`invalid color format for "%s": %s`, k, colorStr)
}
SetColor(k, color)
}
}
if viper.GetBool("a-general.color") {
cview.Styles.PrimitiveBackgroundColor = GetColor("bg")
} // Otherwise it's black by default
2020-11-05 02:35:56 +03:00
// Parse HTTP command
2020-11-05 02:47:27 +03:00
HTTPCommand = viper.GetStringSlice("a-general.http")
if len(HTTPCommand) == 0 {
2020-11-05 02:35:56 +03:00
// Not a string array, interpret as a string instead
// Split on spaces to maintain compatibility with old versions
// The new better way to is to just define a string array in config
2020-11-05 02:47:27 +03:00
HTTPCommand = strings.Fields(viper.GetString("a-general.http"))
2020-11-05 02:35:56 +03:00
}
2020-06-18 23:54:48 +03:00
return nil
}