refactor!: cleaning up messages

This commit is contained in:
decentral1se 2023-07-27 23:41:59 +02:00
parent 2fbc7c42aa
commit 105ee428a6
Signed by: decentral1se
GPG Key ID: 03789458B3D0C410
4 changed files with 126 additions and 111 deletions

66
acn.go
View File

@ -23,34 +23,29 @@ const (
connected connected
) )
func ensureConnected(m model) (bool, tea.Msg) { func isConnected(m model) (bool, tea.Msg) {
switch m.connState { switch m.acnState {
case offline: case offline:
return false, offlineMsg{} return false, acnOfflineMsg{}
case connecting: case connecting:
return false, stillConnectingMsg{} return false, acnConnectingMsg{}
default: default:
return true, nil return true, acnAlreadyOnlineMsg{}
} }
} }
func attemptShutdown(m *model) tea.Msg { func turnAcnOn(m *model) tea.Msg {
switch m.connState { if ok, msg := isConnected(*m); !ok {
case offline: switch msg.(type) {
close(m.statusBuffer) case acnConnectingMsg:
return shutdownMsg{quit: true} return msg
case connecting: case acnAlreadyOnlineMsg:
return stillConnectingMsg{} return msg
}
} }
m.app.Shutdown() m.acnState = connecting
m.acn.Close()
close(m.statusBuffer)
return shutdownMsg{quit: true}
}
func acnOn(m *model) tea.Msg {
mrand.Seed(int64(time.Now().Nanosecond())) mrand.Seed(int64(time.Now().Nanosecond()))
port := mrand.Intn(1000) + 9600 port := mrand.Intn(1000) + 9600
controlPort := port + 1 controlPort := port + 1
@ -58,15 +53,15 @@ func acnOn(m *model) tea.Msg {
key := make([]byte, 64) key := make([]byte, 64)
_, err := rand.Read(key) _, err := rand.Read(key)
if err != nil { if err != nil {
return errMsg{Err: fmt.Errorf("unable to generate control port password: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to generate control port password: %s", err)}
} }
if err := os.MkdirAll(path.Join(m.userDir, "/.tor", "tor"), 0700); err != nil { if err := os.MkdirAll(path.Join(m.userDir, "/.tor", "tor"), 0700); err != nil {
return errMsg{Err: fmt.Errorf("unable to create tor directory: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to create tor directory: %s", err)}
} }
if err := os.MkdirAll(path.Join(m.userDir, "profiles"), 0700); err != nil { if err := os.MkdirAll(path.Join(m.userDir, "profiles"), 0700); err != nil {
return errMsg{Err: fmt.Errorf("unable to create profiles directory: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to create profiles directory: %s", err)}
} }
if err := tor.NewTorrc(). if err := tor.NewTorrc().
@ -75,7 +70,7 @@ func acnOn(m *model) tea.Msg {
WithControlPort(controlPort). WithControlPort(controlPort).
WithHashedPassword(base64.StdEncoding.EncodeToString(key)). WithHashedPassword(base64.StdEncoding.EncodeToString(key)).
Build(filepath.Join(m.userDir, ".tor", "tor", "torrc")); err != nil { Build(filepath.Join(m.userDir, ".tor", "tor", "torrc")); err != nil {
return errMsg{Err: fmt.Errorf("unable to initialise torrc builder: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to initialise torrc builder: %s", err)}
} }
m.sendStatus("Initialising Tor ACN...") m.sendStatus("Initialising Tor ACN...")
@ -90,18 +85,18 @@ func acnOn(m *model) tea.Msg {
}, },
) )
if err != nil { if err != nil {
return errMsg{Err: fmt.Errorf("unable to bootstrap tor: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to bootstrap tor: %s", err)}
} }
m.sendStatus("Waiting for ACN to bootstrap...") m.sendStatus("Waiting for ACN to bootstrap...")
if err := acn.WaitTillBootstrapped(); err != nil { if err := acn.WaitTillBootstrapped(); err != nil {
return errMsg{Err: fmt.Errorf("unable to initialise tor: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to initialise tor: %s", err)}
} }
settingsFile, err := settings.InitGlobalSettingsFile(m.userDir, "") settingsFile, err := settings.InitGlobalSettingsFile(m.userDir, "")
if err != nil { if err != nil {
return errMsg{Err: fmt.Errorf("unable to initialise settings: %s", err)} return acnErrMsg{err: fmt.Errorf("unable to initialise settings: %s", err)}
} }
gSettings := settingsFile.ReadGlobalSettings() gSettings := settingsFile.ReadGlobalSettings()
gSettings.ExperimentsEnabled = false gSettings.ExperimentsEnabled = false
@ -111,27 +106,24 @@ func acnOn(m *model) tea.Msg {
app := app.NewApp(acn, m.userDir, settingsFile) app := app.NewApp(acn, m.userDir, settingsFile)
app.InstallEngineHooks(connections.DefaultEngineHooks{}) app.InstallEngineHooks(connections.DefaultEngineHooks{})
m.sendStatus("Tor ACN is up and running, all engines go") return acnOnMsg{
return appInitialisedMsg{
app: app, app: app,
acn: acn, acn: acn,
} }
} }
func acnOff(m *model) tea.Msg { func turnAcnOff(m *model, quitProgram bool) tea.Msg {
switch m.connState { switch m.acnState {
case offline: case offline:
return offlineMsg{} if !quitProgram {
return acnOfflineMsg{}
}
case connecting: case connecting:
return stillConnectingMsg{} return acnConnectingMsg{}
} }
m.app.Shutdown() m.app.Shutdown()
m.acn.Close() m.acn.Close()
return shutdownMsg{ return acnOffMsg{quitProgram: quitProgram}
quit: false,
status: "ACN successfully turned off",
}
} }

View File

@ -87,10 +87,10 @@ func handleCommand(cmd, hiddenInput string) tea.Msg {
return cmdMsg{output: strings.Split(cmdHelp, "\n")} return cmdMsg{output: strings.Split(cmdHelp, "\n")}
case isQuitCmd(cmds): case isQuitCmd(cmds):
return shutdownMsg{quit: true} return turnAcnOffMsg{quitProgram: true}
case isStartCmd(cmds): case isStartCmd(cmds):
return startMsg{} return showGettingStartedGuideMsg{}
case isProfileCreateCmd(cmds): case isProfileCreateCmd(cmds):
if len(cmds) != 5 { if len(cmds) != 5 {
@ -120,13 +120,13 @@ func handleCommand(cmd, hiddenInput string) tea.Msg {
return profileInfoMsg{} return profileInfoMsg{}
case isAcnOnCmd(cmds): case isAcnOnCmd(cmds):
return acnOnMsg{} return turnAcnOnMsg{}
case isAcnOffCmd(cmds): case isAcnOffCmd(cmds):
return acnOffMsg{} return turnAcnOffMsg{}
case isClearCmd(cmds): case isClearCmd(cmds):
return clearMsg{} return clearScreenMsg{}
default: default:
return cmdMsg{output: []string{"unknown command"}} return cmdMsg{output: []string{"unknown command"}}

View File

@ -5,34 +5,50 @@ import (
"git.openprivacy.ca/openprivacy/connectivity" "git.openprivacy.ca/openprivacy/connectivity"
) )
type sendStatusMsg struct{ lines []string } // ---------------------------------------------------------------------------
// ACN messages
// ---------------------------------------------------------------------------
type turnAcnOnMsg struct{}
type renderStatusMsg struct{ line string } type acnOnMsg struct {
type errMsg struct{ Err error }
func (e errMsg) Error() string {
return e.Err.Error()
}
type appInitialisedMsg struct {
app app.Application app app.Application
acn connectivity.ACN acn connectivity.ACN
} }
type cmdMsg struct{ output []string } type turnAcnOffMsg struct {
quitProgram bool
type offlineMsg struct{}
type startMsg struct{}
type stillConnectingMsg struct{}
type shutdownMsg struct {
quit bool
status string
} }
type acnOffMsg struct {
quitProgram bool
}
type acnAlreadyOnlineMsg struct{}
type acnOfflineMsg struct{}
type acnConnectingMsg struct{}
type acnErrMsg struct {
err error
}
func (e acnErrMsg) Error() string {
return e.err.Error()
}
// ---------------------------------------------------------------------------
// help messages
// ---------------------------------------------------------------------------
type showGettingStartedGuideMsg struct{}
// ---------------------------------------------------------------------------
// profile messages
// ---------------------------------------------------------------------------
type profileInfoMsg struct{}
type startProfileQueuePollMsg struct{ onion string }
type createProfileMsg struct { type createProfileMsg struct {
name string name string
password string password string
@ -42,12 +58,13 @@ type profileUnlockMsg struct {
password string password string
} }
type acnOffMsg struct{} // ---------------------------------------------------------------------------
// TODO: categorize messages below
// ---------------------------------------------------------------------------
type sendStatusMsg struct{ lines []string }
type acnOnMsg struct{} type renderStatusMsg struct{ line string }
type clearMsg struct{} type cmdMsg struct{ output []string }
type profileInfoMsg struct{} type clearScreenMsg struct{}
type startProfileQueuePollMsg struct{ onion string }

View File

@ -58,7 +58,7 @@ type model struct {
username string username string
userDir string userDir string
connState int acnState int
menuState int menuState int
menuBar []string menuBar []string
@ -99,7 +99,7 @@ func newModel(username, homeDir string, debug bool) model {
username: username, username: username,
userDir: path.Join(homeDir, "/.cairde/"), userDir: path.Join(homeDir, "/.cairde/"),
connState: offline, acnState: offline,
menuBar: []string{"STATUS"}, menuBar: []string{"STATUS"},
menuState: 0, menuState: 0,
@ -224,7 +224,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg.String() { switch msg.String() {
case "ctrl+c": case "ctrl+c":
cmds = append(cmds, func() tea.Msg { cmds = append(cmds, func() tea.Msg {
return attemptShutdown(&m) return turnAcnOff(&m, true)
}) })
case "enter": case "enter":
@ -249,7 +249,9 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
} }
case "ctrl+l": case "ctrl+l":
cmds = append(cmds, func() tea.Msg { return clearMsg{} }) cmds = append(cmds, func() tea.Msg {
return clearScreenMsg{}
})
default: default:
hidePasswordInput(&m) hidePasswordInput(&m)
@ -259,34 +261,59 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.input.Reset() m.input.Reset()
cmds = append(cmds, m.sendStatusCmd(msg.output...)) cmds = append(cmds, m.sendStatusCmd(msg.output...))
case offlineMsg: case turnAcnOffMsg:
m.input.Reset()
cmds = append(cmds, func() tea.Msg {
return turnAcnOff(&m, msg.quitProgram)
})
case acnOffMsg:
if msg.quitProgram {
return m, tea.Quit
}
cmds = append(cmds, m.sendStatusCmd("ACN successfully turned off"))
m.acnState = offline
case turnAcnOnMsg:
m.input.Reset()
cmds = append(cmds, func() tea.Msg {
return turnAcnOn(&m)
})
case acnOnMsg:
m.app = msg.app
m.acn = msg.acn
m.app.ActivateEngines(true, true, true)
m.acnState = connected
cmds = append(cmds, m.sendStatusCmd("ACN is up and running, all engines go"))
case acnAlreadyOnlineMsg:
m.input.Reset()
cmds = append(cmds, m.sendStatusCmd("ACN is already online"))
case acnOfflineMsg:
m.input.Reset() m.input.Reset()
cmds = append(cmds, m.sendStatusCmd("ACN is currently offline")) cmds = append(cmds, m.sendStatusCmd("ACN is currently offline"))
case stillConnectingMsg: case acnConnectingMsg:
m.input.Reset() m.input.Reset()
cmds = append(cmds, m.sendStatusCmd("Still initialising ACN, please hold")) cmds = append(cmds, m.sendStatusCmd("ACN still initialising, please hold"))
case startMsg: case acnErrMsg:
m.acnState = offline
cmds = append(cmds, m.sendStatusCmd(msg.Error()))
case showGettingStartedGuideMsg:
cmds = append(cmds, m.sendStatusCmd( cmds = append(cmds, m.sendStatusCmd(
strings.Split(gettingStartedMessage, "\n")..., strings.Split(gettingStartedMessage, "\n")...,
)) ))
m.input.Reset() m.input.Reset()
case shutdownMsg:
m.input.Reset()
if msg.quit {
return m, tea.Quit
}
if msg.status != "" {
cmds = append(cmds, m.sendStatusCmd(msg.status))
}
case createProfileMsg: case createProfileMsg:
m.hiddenInput = "" m.hiddenInput = ""
m.input.Reset() m.input.Reset()
if isConnected, msg := ensureConnected(m); !isConnected { if ok, msg := isConnected(m); !ok {
cmds = append(cmds, func() tea.Msg { return msg }) cmds = append(cmds, func() tea.Msg { return msg })
break break
} }
@ -315,7 +342,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.hiddenInput = "" m.hiddenInput = ""
m.input.Reset() m.input.Reset()
if isConnected, msg := ensureConnected(m); !isConnected { if ok, msg := isConnected(m); !ok {
cmds = append(cmds, func() tea.Msg { return msg }) cmds = append(cmds, func() tea.Msg { return msg })
break break
} }
@ -339,7 +366,7 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case profileInfoMsg: case profileInfoMsg:
m.input.Reset() m.input.Reset()
if isConnected, msg := ensureConnected(m); !isConnected { if ok, msg := isConnected(m); !ok {
cmds = append(cmds, func() tea.Msg { return msg }) cmds = append(cmds, func() tea.Msg { return msg })
break break
} }
@ -373,32 +400,11 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
m.statusViewport.GotoBottom() m.statusViewport.GotoBottom()
cmds = append(cmds, m.receiveStatusCmd) cmds = append(cmds, m.receiveStatusCmd)
case clearMsg: case clearScreenMsg:
m.input.Reset() m.input.Reset()
m.statusViewportLines = []string{} m.statusViewportLines = []string{}
m.statusViewport.SetContent("") m.statusViewport.SetContent("")
m.statusViewport.GotoTop() m.statusViewport.GotoTop()
case acnOffMsg:
m.input.Reset()
cmds = append(cmds, func() tea.Msg {
return acnOff(&m)
})
case acnOnMsg:
m.input.Reset()
cmds = append(cmds, func() tea.Msg {
return acnOn(&m)
})
case appInitialisedMsg:
m.app = msg.app
m.acn = msg.acn
m.connState = connected
m.app.ActivateEngines(true, true, true)
case errMsg:
cmds = append(cmds, m.sendStatusCmd(msg.Error()))
} }
return m, tea.Batch(cmds...) return m, tea.Batch(cmds...)