refactor: project structure, makefile
This commit is contained in:
224
internal/config/config.go
Normal file
224
internal/config/config.go
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) 2025 Nikolai Papin
|
||||
//
|
||||
// This file is part of the Auto Attendance app that looks for
|
||||
// self-attend QR-codes during lectures and opens their URLs in your
|
||||
// browser.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
// the GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.weirdcat.su/weirdcat/auto-attendance/internal/constants"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
App AppConfig `mapstructure:"app"`
|
||||
Screenshot ScreenshotConfig `mapstructure:"screenshot"`
|
||||
Communication CommunicationConfig `mapstructure:"communication"`
|
||||
Telemetry TelemetryConfig `mapstructure:"telemetry"`
|
||||
Logging LoggingConfig `mapstructure:"logging"`
|
||||
}
|
||||
|
||||
type AppConfig struct {
|
||||
SettingsReviewed bool `mapstructure:"settings_reviewed"`
|
||||
EnableAlarm bool `mapstructure:"enable_alarm"`
|
||||
EnableLinkOpening bool `mapstructure:"enable_link_opening"`
|
||||
UseAttendanceJounralApi bool `mapstructure:"use_attendance_journal_api"`
|
||||
UseCustomBrowserCommand bool `mapstructure:"use_custom_browser_command"`
|
||||
BrowserOpenCommand string `mapstructure:"browser_open_command"`
|
||||
EnableCheckingUpdates bool `mapstructure:"enable_checking_updates"`
|
||||
}
|
||||
|
||||
type ScreenshotConfig struct {
|
||||
ScreenIndex int `mapstructure:"screen_index"`
|
||||
Interval int `mapstructure:"interval"`
|
||||
Directory string `mapstructure:"directory"`
|
||||
BufferCount int `mapstructure:"buffer_count"`
|
||||
}
|
||||
|
||||
type CommunicationConfig struct {
|
||||
QrUrl string `mapstructure:"self_approve_url"`
|
||||
QrQueryToken string `mapstructure:"qr_query_token"`
|
||||
ApiSelfApproveMethod string `mapstructure:"api_self_approve_method"`
|
||||
}
|
||||
|
||||
type TelemetryConfig struct {
|
||||
EnableStatisticsCollection bool `mapstructure:"enable_anonymous_statistics_collection"`
|
||||
EnableAnonymousErrorReports bool `mapstructure:"enable_anonymous_error_reports"`
|
||||
}
|
||||
|
||||
type LoggingConfig struct {
|
||||
Level string `mapstructure:"level"`
|
||||
Output string `mapstructure:"output"`
|
||||
}
|
||||
|
||||
func getTempDirectoryPath() string {
|
||||
return os.TempDir()
|
||||
}
|
||||
|
||||
func getDefaultConfig() Config {
|
||||
return Config{
|
||||
App: AppConfig{
|
||||
SettingsReviewed: false,
|
||||
EnableAlarm: false,
|
||||
EnableLinkOpening: true,
|
||||
UseAttendanceJounralApi: false,
|
||||
UseCustomBrowserCommand: false,
|
||||
BrowserOpenCommand: "firefox %s",
|
||||
EnableCheckingUpdates: true,
|
||||
},
|
||||
Screenshot: ScreenshotConfig{
|
||||
ScreenIndex: 0,
|
||||
Interval: 5,
|
||||
Directory: getTempDirectoryPath(),
|
||||
BufferCount: 5,
|
||||
},
|
||||
Logging: LoggingConfig{
|
||||
Level: "info",
|
||||
Output: "stdout",
|
||||
},
|
||||
Telemetry: TelemetryConfig{
|
||||
EnableStatisticsCollection: true,
|
||||
EnableAnonymousErrorReports: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getConfigDir(appName string) (string, error) {
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to get user config directory: %w", err)
|
||||
}
|
||||
|
||||
appConfigDir := filepath.Join(configDir, appName)
|
||||
|
||||
if err := os.MkdirAll(appConfigDir, 0755); err != nil {
|
||||
return "", fmt.Errorf("failed to create config directory: %w", err)
|
||||
}
|
||||
|
||||
return appConfigDir, nil
|
||||
}
|
||||
|
||||
func initializeViper(appName string) (*viper.Viper, string, error) {
|
||||
configDir, err := getConfigDir(appName)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
configFile := filepath.Join(configDir, appName+".toml")
|
||||
|
||||
v := viper.New()
|
||||
v.SetConfigFile(configFile)
|
||||
v.SetConfigType("toml")
|
||||
|
||||
defaults := getDefaultConfig()
|
||||
|
||||
v.SetDefault("app.settings_reviewed", defaults.App.SettingsReviewed)
|
||||
v.SetDefault("app.enable_alarm", defaults.App.EnableAlarm)
|
||||
v.SetDefault("app.enable_link_opening", defaults.App.EnableLinkOpening)
|
||||
v.SetDefault("app.use_attendance_journal_api", defaults.App.UseAttendanceJounralApi)
|
||||
v.SetDefault("app.use_custom_browser_command", defaults.App.UseCustomBrowserCommand)
|
||||
v.SetDefault("app.browser_open_command", defaults.App.BrowserOpenCommand)
|
||||
v.SetDefault("app.enable_checking_updates", defaults.App.EnableCheckingUpdates)
|
||||
|
||||
v.SetDefault("screenshot.screen_index", defaults.Screenshot.ScreenIndex)
|
||||
v.SetDefault("screenshot.interval", defaults.Screenshot.Interval)
|
||||
v.SetDefault("screenshot.directory", defaults.Screenshot.Directory)
|
||||
v.SetDefault("screenshot.buffer_count", defaults.Screenshot.BufferCount)
|
||||
|
||||
v.SetDefault("logging.level", defaults.Logging.Level)
|
||||
v.SetDefault("logging.output", defaults.Logging.Output)
|
||||
|
||||
v.SetDefault("telemetry.enable_statistics_collection", defaults.Telemetry.EnableStatisticsCollection)
|
||||
v.SetDefault("telemetry.enable_anonymous_error_reports", defaults.Telemetry.EnableAnonymousErrorReports)
|
||||
|
||||
return v, configFile, nil
|
||||
}
|
||||
|
||||
func (c *Config) Save() error {
|
||||
v, _, err := initializeViper(constants.AppName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize viper: %w", err)
|
||||
}
|
||||
|
||||
v.Set("app.settings_reviewed", c.App.SettingsReviewed)
|
||||
v.Set("app.enable_alarm", c.App.EnableAlarm)
|
||||
v.Set("app.enable_link_opening", c.App.EnableLinkOpening)
|
||||
v.Set("app.use_attendance_journal_api", c.App.UseAttendanceJounralApi)
|
||||
v.Set("app.use_custom_browser_command", c.App.UseCustomBrowserCommand)
|
||||
v.Set("app.browser_open_command", c.App.BrowserOpenCommand)
|
||||
v.Set("app.enable_checking_updates", c.App.EnableCheckingUpdates)
|
||||
|
||||
v.Set("screenshot.screen_index", c.Screenshot.ScreenIndex)
|
||||
v.Set("screenshot.interval", c.Screenshot.Interval)
|
||||
v.Set("screenshot.directory", c.Screenshot.Directory)
|
||||
v.Set("screenshot.buffer_count", c.Screenshot.BufferCount)
|
||||
|
||||
v.Set("logging.level", c.Logging.Level)
|
||||
v.Set("logging.output", c.Logging.Output)
|
||||
|
||||
v.Set("telemetry.enable_statistics_collection", c.Telemetry.EnableStatisticsCollection)
|
||||
v.Set("telemetry.enable_anonymous_error_reports", c.Telemetry.EnableAnonymousErrorReports)
|
||||
|
||||
if c.Communication.QrUrl != "" {
|
||||
v.Set("communication.self_approve_url", c.Communication.QrUrl)
|
||||
}
|
||||
if c.Communication.QrQueryToken != "" {
|
||||
v.Set("communication.qr_query_token", c.Communication.QrQueryToken)
|
||||
}
|
||||
if c.Communication.ApiSelfApproveMethod != "" {
|
||||
v.Set("communication.api_self_approve_method", c.Communication.ApiSelfApproveMethod)
|
||||
}
|
||||
|
||||
return v.WriteConfig()
|
||||
}
|
||||
|
||||
func NewConfig() (*Config, error) {
|
||||
v, configFile, err := initializeViper(constants.AppName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize viper: %w", err)
|
||||
}
|
||||
|
||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||
file, err := os.Create(configFile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create config file: %w", err)
|
||||
}
|
||||
file.Close()
|
||||
|
||||
if err := v.WriteConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to write default config: %w", err)
|
||||
}
|
||||
fmt.Printf("Created new config file at: %s\n", configFile)
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("failed to check config file: %w", err)
|
||||
}
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
return nil, fmt.Errorf("failed to read config file: %w", err)
|
||||
}
|
||||
|
||||
var config Config
|
||||
if err := v.Unmarshal(&config); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
Reference in New Issue
Block a user