Refactor 1/2 + new stuff

* Refactor CLI
* Add config:print command
* Add diagnose command
* Allow including other files in config
* Watch for file changes and automatically restart server
This commit is contained in:
Svilen Markov
2024-11-24 15:39:14 +00:00
parent 7e345dd1f9
commit 2b0dd3ab99
8 changed files with 573 additions and 75 deletions

View File

@@ -2,45 +2,120 @@ package glance
import (
"fmt"
"os"
"log"
)
func Main() int {
options, err := ParseCliOptions()
options, err := parseCliOptions()
if err != nil {
fmt.Println(err)
return 1
}
configFile, err := os.Open(options.ConfigPath)
if err != nil {
fmt.Printf("failed opening config file: %v\n", err)
return 1
}
config, err := NewConfigFromYml(configFile)
configFile.Close()
if err != nil {
fmt.Printf("failed parsing config file: %v\n", err)
return 1
}
if options.Intent == CliIntentServe {
app, err := NewApplication(config)
switch options.intent {
case cliIntentServe:
if err := serveApp(options.configPath); err != nil {
fmt.Println(err)
return 1
}
case cliIntentConfigValidate:
contents, _, err := parseYAMLIncludes(options.configPath)
if err != nil {
fmt.Printf("failed creating application: %v\n", err)
fmt.Printf("failed to parse config file: %v\n", err)
return 1
}
if err := app.Serve(); err != nil {
fmt.Printf("http server error: %v\n", err)
if _, err := newConfigFromYAML(contents); err != nil {
fmt.Printf("config file is invalid: %v\n", err)
return 1
}
case cliIntentConfigPrint:
contents, _, err := parseYAMLIncludes(options.configPath)
if err != nil {
fmt.Printf("failed to parse config file: %v\n", err)
return 1
}
fmt.Println(string(contents))
case cliIntentDiagnose:
runDiagnostic()
}
return 0
}
func serveApp(configPath string) error {
exitChannel := make(chan struct{})
// the onChange method gets called at most once per 500ms due to debouncing so we shouldn't
// need to use atomic.Bool here unless newConfigFromYAML is very slow for some reason
hadValidConfigOnStartup := false
var stopServer func() error
onChange := func(newContents []byte) {
if stopServer != nil {
log.Println("Config file changed, attempting to restart server")
}
config, err := newConfigFromYAML(newContents)
if err != nil {
log.Printf("Config file is invalid: %v", err)
if !hadValidConfigOnStartup {
close(exitChannel)
}
return
} else if !hadValidConfigOnStartup {
hadValidConfigOnStartup = true
}
app := newApplication(config)
if stopServer != nil {
if err := stopServer(); err != nil {
log.Printf("Error while trying to stop server: %v", err)
}
}
go func() {
var startServer func() error
startServer, stopServer = app.Server()
if err := startServer(); err != nil {
log.Printf("Failed to start server: %v", err)
}
}()
}
onErr := func(err error) {
log.Printf("Error watching config files: %v", err)
}
configContents, configIncludes, err := parseYAMLIncludes(configPath)
if err != nil {
return fmt.Errorf("failed to parse config file: %w", err)
}
stopWatching, err := configFilesWatcher(configPath, configContents, configIncludes, onChange, onErr)
if err == nil {
defer stopWatching()
} else {
log.Printf("Error starting file watcher, config file changes will require a manual restart. (%v)", err)
config, err := newConfigFromYAML(configContents)
if err != nil {
return fmt.Errorf("could not parse config file: %w", err)
}
app := newApplication(config)
startServer, _ := app.Server()
if err := startServer(); err != nil {
return fmt.Errorf("failed to start server: %w", err)
}
}
<-exitChannel
return nil
}