140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
const (
|
|
AppConfigVersion = 1
|
|
ConfigDirName = "verstak"
|
|
AppConfigFileName = "config.json"
|
|
)
|
|
|
|
// AppConfig is the global application config stored at ~/.config/verstak/config.json.
|
|
type AppConfig struct {
|
|
Version int `json:"version"`
|
|
VaultPath string `json:"vault_path"`
|
|
Theme string `json:"theme"`
|
|
Language string `json:"language"`
|
|
EnabledTemplates []string `json:"enabled_templates"`
|
|
EnabledPlugins []string `json:"enabled_plugins"`
|
|
FirstRunCompleted bool `json:"first_run_completed"`
|
|
Window WindowConfig `json:"window,omitempty"`
|
|
Vault VaultAppConfig `json:"vault,omitempty"`
|
|
}
|
|
|
|
type WindowConfig struct {
|
|
Width int `json:"width,omitempty"`
|
|
Height int `json:"height,omitempty"`
|
|
}
|
|
|
|
// VaultAppConfig holds per-vault settings in the global config.
|
|
type VaultAppConfig struct {
|
|
VaultID string `json:"vault_id,omitempty"`
|
|
CreatedAt string `json:"created_at,omitempty"`
|
|
Sync SyncSettings `json:"sync,omitempty"`
|
|
}
|
|
|
|
// SyncSettings holds sync configuration for the current vault.
|
|
type SyncSettings struct {
|
|
Enabled bool `json:"enabled"`
|
|
ServerURL string `json:"server_url"`
|
|
DeviceID string `json:"device_id"`
|
|
DeviceName string `json:"device_name"`
|
|
SyncInterval int `json:"sync_interval"`
|
|
LastStatus string `json:"last_status"`
|
|
LastSyncAt string `json:"last_sync_at"`
|
|
LastError string `json:"last_error,omitempty"`
|
|
}
|
|
|
|
func DefaultAppConfig() *AppConfig {
|
|
return &AppConfig{
|
|
Version: AppConfigVersion,
|
|
Theme: "system",
|
|
Language: "ru",
|
|
EnabledTemplates: []string{"folder", "project", "client", "document", "recipe"},
|
|
EnabledPlugins: []string{},
|
|
}
|
|
}
|
|
|
|
// ConfigDir returns ~/.config/verstak (or platform equivalent).
|
|
func ConfigDir() (string, error) {
|
|
cfgDir, err := os.UserConfigDir()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return filepath.Join(cfgDir, ConfigDirName), nil
|
|
}
|
|
|
|
// AppConfigPath returns the path to config.json.
|
|
func AppConfigPath() (string, error) {
|
|
dir, err := ConfigDir()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return filepath.Join(dir, AppConfigFileName), nil
|
|
}
|
|
|
|
// EnsureConfigDir creates the config directory if it doesn't exist.
|
|
func EnsureConfigDir() (string, error) {
|
|
dir, err := ConfigDir()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if err := os.MkdirAll(dir, 0o750); err != nil {
|
|
return "", err
|
|
}
|
|
return dir, nil
|
|
}
|
|
|
|
// LoadAppConfig reads the global config from disk. Returns nil if the file doesn't exist.
|
|
func LoadAppConfig() (*AppConfig, error) {
|
|
path, err := AppConfigPath()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, nil
|
|
}
|
|
return nil, fmt.Errorf("read config: %w", err)
|
|
}
|
|
if len(data) == 0 {
|
|
return nil, nil
|
|
}
|
|
var cfg AppConfig
|
|
if err := json.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("parse config: %w", err)
|
|
}
|
|
return &cfg, nil
|
|
}
|
|
|
|
// SaveAppConfig writes the global config to disk.
|
|
func SaveAppConfig(cfg *AppConfig) error {
|
|
path, err := AppConfigPath()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := EnsureConfigDir(); err != nil {
|
|
return err
|
|
}
|
|
data, err := json.MarshalIndent(cfg, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(path, data, 0o640)
|
|
}
|
|
|
|
// DefaultVaultPath returns the default vault location.
|
|
func DefaultVaultPath() (string, error) {
|
|
dir, err := ConfigDir()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return filepath.Join(dir, "vault"), nil
|
|
}
|