Improve application startup and restart. Fixes
MODIFY
app/app.go
app/app.go
@@ -17,40 +17,31 @@ import (
"github.com/Bios-Marcel/cordless/version"
)
-// RunWithAccount launches the whole application and might
+// SetupApplicationWithAccount launches the whole application and might
// abort in case it encounters an error. The login will attempt
// using the account specified, unless the argument is empty.
// If the account can't be found, the login page will be shown.
-func RunWithAccount(account string) {
- configDir, configErr := config.GetConfigDirectory()
+func SetupApplicationWithAccount(app *tview.Application, account string) {
+ configuration := config.Current
+
+ //We do this right after loading the configuration, as this might take
+ //longer than all following calls.
+ updateAvailableChannel := version.CheckForUpdate(configuration.DontShowUpdateNotificationFor)
+ configDir, configErr := config.GetConfigDirectory()
if configErr != nil {
log.Fatalf("Unable to determine configuration directory (%s)\n", configErr.Error())
}
- themeLoadingError := config.LoadTheme()
- if themeLoadingError == nil {
- tview.Styles = *config.GetTheme().Theme
- }
-
- app := tview.NewApplication()
loginScreen := ui.NewLogin(app, configDir)
app.SetRoot(loginScreen, true)
- runNext := make(chan bool, 1)
-
- configuration, configLoadError := config.LoadConfig()
- if configLoadError != nil {
- log.Fatalf("Error loading configuration file (%s).\n", configLoadError.Error())
- }
+ app.MouseEnabled = configuration.MouseEnabled
+ go func() {
if strings.TrimSpace(account) != "" {
configuration.Token = configuration.GetAccountToken(account)
}
- updateAvailableChannel := version.CheckForUpdate(configuration.DontShowUpdateNotificationFor)
- app.MouseEnabled = configuration.MouseEnabled
-
- go func() {
shortcutsLoadError := shortcuts.Load()
if shortcutsLoadError != nil {
panic(shortcutsLoadError)
@@ -100,7 +91,7 @@ func RunWithAccount(account string) {
}
app.QueueUpdateDraw(func() {
- window, createError := ui.NewWindow(runNext, app, discord, readyEvent)
+ window, createError := ui.NewWindow(app, discord, readyEvent)
if createError != nil {
app.Stop()
@@ -118,7 +109,7 @@ func RunWithAccount(account string) {
window.RegisterCommand(statusSetCustomCmd)
window.RegisterCommand(commandimpls.NewStatusCommand(statusGetCmd, statusSetCmd, statusSetCustomCmd))
window.RegisterCommand(commandimpls.NewFileSendCommand(discord, window))
- accountLogout := commandimpls.NewAccountLogout(runNext, window)
+ accountLogout := commandimpls.NewAccountLogout(func() { SetupApplication(app) }, window)
window.RegisterCommand(accountLogout)
window.RegisterCommand(commandimpls.NewAccount(accountLogout, window))
window.RegisterCommand(commandimpls.NewManualCommand(window))
@@ -149,22 +140,12 @@ func RunWithAccount(account string) {
window.RegisterCommand(commandimpls.NewDMOpenCmd(discord, window))
})
}()
-
- runError := app.Run()
- if runError != nil {
- log.Fatalf("Error launching View (%v).\n", runError)
- }
-
- run := <-runNext
- if run {
- Run()
- }
}
-// Run launches the whole application and might abort in case
+// SetupApplication launches the whole application and might abort in case
// it encounters an error.
-func Run() {
- RunWithAccount("")
+func SetupApplication(app *tview.Application) {
+ SetupApplicationWithAccount(app, "")
}
func attemptLogin(loginScreen *ui.Login, loginMessage string, configuration *config.Config) (*discordgo.Session, *discordgo.Ready) {

MODIFY
commands/commandimpls/account.go
commands/commandimpls/account.go
@@ -36,7 +36,7 @@ type Account struct {
// in the users folder.
type AccountLogout struct {
window *ui.Window
- runNext chan bool
+ restart func()
}
// NewAccount creates a ready-to-use Account command.
@@ -45,8 +45,8 @@ func NewAccount(accountLogout *AccountLogout, window *ui.Window) *Account {
}
// NewAccountLogout creates a ready-to-use Logout command.
-func NewAccountLogout(runNext chan bool, window *ui.Window) *AccountLogout {
- return &AccountLogout{window: window, runNext: runNext}
+func NewAccountLogout(restart func(), window *ui.Window) *AccountLogout {
+ return &AccountLogout{window: window, restart: restart}
}
// Execute runs the command piping its output into the supplied writer.
@@ -252,8 +252,8 @@ func (accountLogout *AccountLogout) saveAndRestart(writer io.Writer) error {
}
//Using a go routine, so this instance doesn't stay alive and pollutes the memory.
- accountLogout.runNext <- true
accountLogout.window.Shutdown()
+ accountLogout.restart()
return nil
}

MODIFY
config/config.go
config/config.go
@@ -330,21 +330,22 @@ func getAbsolutePath(directoryPath string) (string, error) {
return absolutePath, resolveError
}
-//LoadConfig loads the configuration initially and returns it.
-func LoadConfig() (*Config, error) {
+// LoadConfig loads the configuration. After loading the configuration, it can
+// be accessed via config.Current.
+func LoadConfig() error {
configFilePath, configError := GetConfigFile()
if configError != nil {
- return nil, configError
+ return configError
}
configFile, openError := os.Open(configFilePath)
if os.IsNotExist(openError) {
- return Current, nil
+ return nil
}
if openError != nil {
- return nil, openError
+ return openError
}
defer configFile.Close()
@@ -353,10 +354,10 @@ func LoadConfig() (*Config, error) {
//io.EOF would mean empty, therefore we use defaults.
if configLoadError != nil && configLoadError != io.EOF {
- return nil, configLoadError
+ return configLoadError
}
- return Current, nil
+ return nil
}
// UpdateCurrentToken updates the current token and all accounts where the

MODIFY
main.go
main.go
@@ -5,11 +5,13 @@ package main
import (
"flag"
"fmt"
+ "log"
"os"
"github.com/Bios-Marcel/cordless/app"
"github.com/Bios-Marcel/cordless/config"
"github.com/Bios-Marcel/cordless/logging"
+ "github.com/Bios-Marcel/cordless/tview"
"github.com/Bios-Marcel/cordless/ui/shortcutdialog"
"github.com/Bios-Marcel/cordless/version"
)
@@ -43,15 +45,35 @@ func main() {
config.SetConfigFile(*setConfigFilePath)
}
+ //Making sure both the main app and the shortcuts dialog have the
+ //correct theme and configuration files.
+ configLoadError := config.LoadConfig()
+ if configLoadError != nil {
+ log.Fatalf("Error loading configuration file (%s).\n", configLoadError.Error())
+ }
+ themeLoadingError := config.LoadTheme()
+ if themeLoadingError != nil {
+ panic(themeLoadingError)
+ }
+ tview.Styles = *config.GetTheme().Theme
+
if showShortcutsDialog != nil && *showShortcutsDialog {
shortcutdialog.RunShortcutsDialogStandalone()
} else if showVersion != nil && *showVersion {
fmt.Printf("You are running cordless version %s\nKeep in mind that this version might not be correct for manually built versions, as those can contain additional commits.\n", version.Version)
} else {
+ //App that will be reused throughout the process runtime.
+ tviewApp := tview.NewApplication()
+
if accountToUse != nil && *accountToUse != "" {
- app.RunWithAccount(*accountToUse)
+ app.SetupApplicationWithAccount(tviewApp, *accountToUse)
} else {
- app.Run()
+ app.SetupApplication(tviewApp)
+ }
+
+ runError := tviewApp.Run()
+ if runError != nil {
+ log.Fatalf("Error launching View (%v).\n", runError)
}
}
}

MODIFY
ui/window.go
ui/window.go
@@ -89,8 +89,6 @@ type Window struct {
userActive bool
userActiveTimer *time.Timer
- doRestart chan bool
-
bareChat bool
activeView ActiveView
}
@@ -103,9 +101,8 @@ const Dms ActiveView = false
//NewWindow constructs the whole application window and also registers all
//necessary handlers and functions. If this function returns an error, we can't
//start the application.
-func NewWindow(doRestart chan bool, app *tview.Application, session *discordgo.Session, readyEvent *discordgo.Ready) (*Window, error) {
+func NewWindow(app *tview.Application, session *discordgo.Session, readyEvent *discordgo.Ready) (*Window, error) {
window := &Window{
- doRestart: doRestart,
session: session,
app: app,
activeView: Guilds,
@@ -2102,7 +2099,7 @@ func (window *Window) SetCommandModeEnabled(enabled bool) {
func (window *Window) handleGlobalShortcuts(event *tcell.EventKey) *tcell.EventKey {
if shortcuts.ExitApplication.Equals(event) {
- window.doRestart <- false
+ //window#Shutdown unnecessary, as we shut the whole process down.
window.app.Stop()
return nil
}
@@ -2687,5 +2684,4 @@ func (window *Window) Shutdown() {
window.chatView.shortener.Close()
}
window.session.Close()
- window.app.Stop()
}

Improve application startup and restart. Fixes #268