logging, config file managment, writing library dir
This commit is contained in:
@@ -3,48 +3,66 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"yellowjacket/backend"
|
"log/slog"
|
||||||
|
"yellowjacket/backend/config"
|
||||||
|
"yellowjacket/backend/library"
|
||||||
|
"yellowjacket/backend/logging"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2/pkg/runtime"
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// App struct
|
// App struct
|
||||||
type App struct {
|
type App struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
config *backend.Config
|
config *config.Config
|
||||||
|
library *library.Library
|
||||||
|
logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApp creates a new App application struct
|
// NewApp creates a new App application struct
|
||||||
func NewApp() *App {
|
func NewApp(conf *config.Config) *App {
|
||||||
return &App{}
|
if conf == nil {
|
||||||
|
// TODO proper error handling
|
||||||
|
panic(fmt.Errorf("conf was nil"))
|
||||||
|
}
|
||||||
|
return &App{
|
||||||
|
config: conf,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// startup is called when the app starts. The context is saved
|
// startup is called when the app starts. The context is saved
|
||||||
// so we can call the runtime methods
|
// so we can call the runtime methods
|
||||||
func (a *App) startup(ctx context.Context) {
|
func (a *App) startup(ctx context.Context) {
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
|
runtime.LogInfo(a.ctx, fmt.Sprintf("starting app with config %s", logging.PrettyJSON(*a.config)))
|
||||||
|
|
||||||
conf, err := backend.GetConfig()
|
musicLib, err := library.GetNewLibrary(ctx, a.config.Library)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("could not get config: %w", err))
|
panic(fmt.Errorf("could not initialize library: %w", err))
|
||||||
}
|
}
|
||||||
a.config = conf
|
// config might have been updated, so lets propogate that to the app
|
||||||
|
a.config.Library = musicLib.Conf
|
||||||
|
|
||||||
|
runtime.LogInfo(a.ctx, fmt.Sprintf("using library %s", logging.PrettyJSON(musicLib)))
|
||||||
|
a.library = musicLib
|
||||||
}
|
}
|
||||||
|
|
||||||
// trying to make a function
|
// trying to make a function
|
||||||
func (a *App) DirectoryPicker() (string, error) {
|
func (a *App) DirectoryPicker() (string, error) {
|
||||||
|
runtime.LogInfo(a.ctx, "selecting a directory")
|
||||||
dir, err := runtime.OpenDirectoryDialog(
|
dir, err := runtime.OpenDirectoryDialog(
|
||||||
a.ctx,
|
a.ctx,
|
||||||
runtime.OpenDialogOptions{
|
runtime.OpenDialogOptions{})
|
||||||
ShowHiddenFiles: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("could not open directory dialog\n%w", err)
|
return "", fmt.Errorf("could not open directory dialog\n%w", err)
|
||||||
}
|
}
|
||||||
if dir == "" {
|
if dir == "" {
|
||||||
return "No Library Directory Selected", nil
|
return "No Library Directory Selected", nil
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("Library Directory: %s", dir), nil
|
|
||||||
|
|
||||||
|
// we got a directory, lets do something with it
|
||||||
|
runtime.LogInfo(a.ctx, fmt.Sprintf("got directory %s assigning to library directory config %s", dir, logging.PrettyJSON(*a.config)))
|
||||||
|
a.config.Library.DirectoryPath = dir
|
||||||
|
a.config.WriteConfig()
|
||||||
|
return dir, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package backend
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
LibraryDirPath string
|
|
||||||
MyConfigValue string
|
|
||||||
}
|
|
||||||
|
|
||||||
var defaultConfig *Config = &Config{
|
|
||||||
LibraryDirPath: "",
|
|
||||||
MyConfigValue: "testtesttest",
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetConfig() (*Config, error) {
|
|
||||||
|
|
||||||
configDir, err := GetUserConfigDirPath()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not get user config directory path: %w", err)
|
|
||||||
}
|
|
||||||
configFilePath := path.Join(configDir, "config.toml")
|
|
||||||
// create the config file and load defaults if it doesn't exist
|
|
||||||
_, err = os.Stat(configFilePath)
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
defaultConfig.WriteConfig(configFilePath)
|
|
||||||
}
|
|
||||||
conf, err := LoadConfig(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("could not load config file %s: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
return conf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadConfig(configFilePath string) (*Config, error) {
|
|
||||||
// read in the file
|
|
||||||
confFileData, err := os.ReadFile(configFilePath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("problem reading config file %s: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse it into the config struct
|
|
||||||
var conf Config
|
|
||||||
_, err = toml.Decode(string(confFileData), &conf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("problem parsing config file %s: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the config
|
|
||||||
if err = conf.validate(); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid config file at %s: %w", configFilePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &conf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WriteConfig(configFileWritePath string) error {
|
|
||||||
confFileData, err := toml.Marshal(c)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not marshal config struct: %w", err)
|
|
||||||
}
|
|
||||||
err = os.WriteFile(configFileWritePath, confFileData, os.FileMode(int(0666)))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("could not write config file: %w", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// return errors if there is a *breaking* issue with the config
|
|
||||||
func (c *Config) validate() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"yellowjacket/backend/library"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
filePath string // required
|
||||||
|
*configData
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConfig(filePath string, data *configData) (*Config, error) {
|
||||||
|
// TODO make sure required fields have SOMETHING in them
|
||||||
|
// TODO Merge existing config with read in config
|
||||||
|
if data == nil {
|
||||||
|
data = defaultConfigData
|
||||||
|
}
|
||||||
|
return &Config{
|
||||||
|
filePath: filePath,
|
||||||
|
configData: data,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type configData struct {
|
||||||
|
Library *library.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// return errors if there is a *breaking* issue with the config
|
||||||
|
func (d *configData) validate() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultConfigData *configData = &configData{
|
||||||
|
Library: library.DefaultConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCurrentConfig will load and return the config
|
||||||
|
// reading the config file in the user's config directory
|
||||||
|
func GetCurrentConfig() (*Config, error) {
|
||||||
|
// get the config file location
|
||||||
|
configDir, err := GetUserConfigDirPath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not get user config directory path: %w", err)
|
||||||
|
}
|
||||||
|
configFilePath := path.Join(configDir, "config.toml")
|
||||||
|
config, err := newConfig(configFilePath, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not create new config: %w", err)
|
||||||
|
}
|
||||||
|
config.filePath = configFilePath
|
||||||
|
|
||||||
|
_, err = os.Stat(configFilePath)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
config.WriteConfig()
|
||||||
|
}
|
||||||
|
config, err = config.loadConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not load config file %s: %w", configFilePath, err)
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) loadConfig() (*Config, error) {
|
||||||
|
// read in the file
|
||||||
|
confFileData, err := os.ReadFile(c.filePath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("problem reading config file %s: %w", c.filePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse it into the config struct
|
||||||
|
var confData configData
|
||||||
|
_, err = toml.Decode(string(confFileData), &confData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("problem parsing config file %s: %w", c.filePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate the config
|
||||||
|
if err = confData.validate(); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid config file at %s: %w", c.filePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := newConfig(c.filePath, &confData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not create config from config file data at %s: %w", c.filePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) WriteConfig() error {
|
||||||
|
confFileData, err := toml.Marshal(c)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not marshal config struct: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(c.filePath, confFileData, os.FileMode(int(0666)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not write config file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package backend
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package library
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"yellowjacket/backend/logging"
|
||||||
|
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DirectoryPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
var DefaultConfig *Config = &Config{
|
||||||
|
DirectoryPath: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
type Library struct {
|
||||||
|
ctx context.Context
|
||||||
|
Conf *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNewLibrary(ctx context.Context, conf *Config) (*Library, error) {
|
||||||
|
if conf == nil {
|
||||||
|
runtime.LogInfo(ctx, fmt.Sprintf("library config is nil, using default config: %s", logging.PrettyJSON(DefaultConfig)))
|
||||||
|
conf = DefaultConfig
|
||||||
|
}
|
||||||
|
runtime.LogInfo(ctx, fmt.Sprintf("creating new library with config: %#v", conf))
|
||||||
|
return &Library{
|
||||||
|
ctx: ctx,
|
||||||
|
Conf: conf,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO check that error
|
||||||
|
func PrettyJSON(obj interface{}) string {
|
||||||
|
bytes, _ := json.MarshalIndent(obj, "\t", "\t")
|
||||||
|
return string(bytes)
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"yellowjacket/backend/config"
|
||||||
|
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
|
||||||
)
|
)
|
||||||
@@ -12,24 +17,30 @@ import (
|
|||||||
var assets embed.FS
|
var assets embed.FS
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Create an instance of the app structure
|
config, err := config.GetCurrentConfig()
|
||||||
app := NewApp()
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("could not get config: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
app := NewApp(config)
|
||||||
|
|
||||||
// Create application with options
|
// Create application with options
|
||||||
err := wails.Run(&options.App{
|
err = wails.Run(&options.App{
|
||||||
Title: "yellowjacket",
|
Title: "yellowjacket",
|
||||||
Width: 1024,
|
Width: 512,
|
||||||
Height: 768,
|
Height: 384,
|
||||||
AssetServer: &assetserver.Options{
|
AssetServer: &assetserver.Options{
|
||||||
Assets: assets,
|
Assets: assets,
|
||||||
},
|
},
|
||||||
|
LogLevel: logger.INFO,
|
||||||
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
|
||||||
OnStartup: app.startup,
|
OnStartup: func(ctx context.Context) {
|
||||||
|
app.startup(ctx)
|
||||||
|
},
|
||||||
Bind: []interface{}{
|
Bind: []interface{}{
|
||||||
app,
|
app,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("Error:", err.Error())
|
println("Error:", err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user