refactor(app): internalize dispatch channel
Some checks are pending
Some checks are pending
This commit is contained in:
parent
caa543703e
commit
2f263b5725
@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -23,6 +24,7 @@ type App struct {
|
||||
cfg config.Config
|
||||
configService *config.Service
|
||||
eventBus *event.Bus
|
||||
dispatchC chan event.Command
|
||||
dockerClient container.DockerClient
|
||||
screen *terminal.Screen // Screen may be nil.
|
||||
clipboardAvailable bool
|
||||
@ -35,6 +37,7 @@ type App struct {
|
||||
type Params struct {
|
||||
ConfigService *config.Service
|
||||
DockerClient container.DockerClient
|
||||
ChanSize int
|
||||
Screen *terminal.Screen // Screen may be nil.
|
||||
ClipboardAvailable bool
|
||||
ConfigFilePath string
|
||||
@ -42,12 +45,16 @@ type Params struct {
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
// defaultChanSize is the default size of the dispatch channel.
|
||||
const defaultChanSize = 64
|
||||
|
||||
// New creates a new application instance.
|
||||
func New(params Params) *App {
|
||||
return &App{
|
||||
cfg: params.ConfigService.Current(),
|
||||
configService: params.ConfigService,
|
||||
eventBus: event.NewBus(params.Logger.With("component", "event_bus")),
|
||||
dispatchC: make(chan event.Command, cmp.Or(params.ChanSize, defaultChanSize)),
|
||||
dockerClient: params.DockerClient,
|
||||
screen: params.Screen,
|
||||
clipboardAvailable: params.ClipboardAvailable,
|
||||
@ -70,6 +77,7 @@ func (a *App) Run(ctx context.Context) error {
|
||||
|
||||
ui, err := terminal.StartUI(ctx, terminal.StartParams{
|
||||
EventBus: a.eventBus,
|
||||
Dispatcher: func(cmd event.Command) { a.dispatchC <- cmd },
|
||||
Screen: a.screen,
|
||||
ClipboardAvailable: a.clipboardAvailable,
|
||||
ConfigFilePath: a.configFilePath,
|
||||
@ -107,7 +115,7 @@ func (a *App) Run(ctx context.Context) error {
|
||||
a.eventBus.Send(event.FatalErrorOccurredEvent{Message: msg})
|
||||
|
||||
emptyUI()
|
||||
<-ui.C()
|
||||
<-a.dispatchC
|
||||
return err
|
||||
}
|
||||
defer containerClient.Close()
|
||||
@ -139,7 +147,7 @@ func (a *App) Run(ctx context.Context) error {
|
||||
err = fmt.Errorf("create mediaserver: %w", err)
|
||||
a.eventBus.Send(event.FatalErrorOccurredEvent{Message: err.Error()})
|
||||
emptyUI()
|
||||
<-ui.C()
|
||||
<-a.dispatchC
|
||||
return err
|
||||
}
|
||||
defer srv.Close()
|
||||
@ -159,7 +167,7 @@ func (a *App) Run(ctx context.Context) error {
|
||||
if ok, startupErr := doStartupCheck(ctx, containerClient, a.eventBus); startupErr != nil {
|
||||
startupErr = fmt.Errorf("startup check: %w", startupErr)
|
||||
a.eventBus.Send(event.FatalErrorOccurredEvent{Message: startupErr.Error()})
|
||||
<-ui.C()
|
||||
<-a.dispatchC
|
||||
return startupErr
|
||||
} else if ok {
|
||||
startMediaServerC <- struct{}{}
|
||||
@ -175,13 +183,7 @@ func (a *App) Run(ctx context.Context) error {
|
||||
a.eventBus.Send(event.MediaServerStartedEvent{RTMPURL: srv.RTMPURL(), RTMPSURL: srv.RTMPSURL()})
|
||||
case <-a.configService.C():
|
||||
// No-op, config updates are handled synchronously for now.
|
||||
case cmd, ok := <-ui.C():
|
||||
if !ok {
|
||||
// TODO: keep UI open until all containers have closed
|
||||
a.logger.Info("UI closed")
|
||||
return nil
|
||||
}
|
||||
|
||||
case cmd := <-a.dispatchC:
|
||||
if ok, err := a.handleCommand(ctx, cmd, state, repl, containerClient, startMediaServerC); err != nil {
|
||||
return fmt.Errorf("handle command: %w", err)
|
||||
} else if !ok {
|
||||
|
@ -42,7 +42,7 @@ const (
|
||||
// UI is responsible for managing the terminal user interface.
|
||||
type UI struct {
|
||||
eventBus *event.Bus
|
||||
commandC chan event.Command
|
||||
dispatch func(event.Command)
|
||||
clipboardAvailable bool
|
||||
configFilePath string
|
||||
rtmpURL, rtmpsURL string
|
||||
@ -96,7 +96,7 @@ type ScreenCapture struct {
|
||||
// interface.
|
||||
type StartParams struct {
|
||||
EventBus *event.Bus
|
||||
ChanSize int
|
||||
Dispatcher func(event.Command)
|
||||
Logger *slog.Logger
|
||||
ClipboardAvailable bool
|
||||
ConfigFilePath string
|
||||
@ -104,13 +104,8 @@ type StartParams struct {
|
||||
Screen *Screen // Screen may be nil.
|
||||
}
|
||||
|
||||
const defaultChanSize = 64
|
||||
|
||||
// StartUI starts the terminal user interface.
|
||||
func StartUI(ctx context.Context, params StartParams) (*UI, error) {
|
||||
chanSize := cmp.Or(params.ChanSize, defaultChanSize)
|
||||
commandCh := make(chan event.Command, chanSize)
|
||||
|
||||
app := tview.NewApplication()
|
||||
|
||||
var screen tcell.Screen
|
||||
@ -213,8 +208,8 @@ func StartUI(ctx context.Context, params StartParams) (*UI, error) {
|
||||
app.EnableMouse(false)
|
||||
|
||||
ui := &UI{
|
||||
commandC: commandCh,
|
||||
eventBus: params.EventBus,
|
||||
dispatch: params.Dispatcher,
|
||||
clipboardAvailable: params.ClipboardAvailable,
|
||||
configFilePath: params.ConfigFilePath,
|
||||
buildInfo: params.BuildInfo,
|
||||
@ -271,13 +266,11 @@ func (ui *UI) renderAboutView() {
|
||||
ui.aboutView.AddItem(tview.NewTextView().SetDynamicColors(true).SetText("[grey]?[-] About"), 1, 0, false)
|
||||
}
|
||||
|
||||
// C returns a channel that receives commands from the user interface.
|
||||
func (ui *UI) C() <-chan event.Command {
|
||||
return ui.commandC
|
||||
}
|
||||
|
||||
func (ui *UI) run(ctx context.Context) {
|
||||
defer close(ui.commandC)
|
||||
defer func() {
|
||||
// Ensure the application is stopped when the UI is closed.
|
||||
ui.dispatch(event.CommandQuit{})
|
||||
}()
|
||||
|
||||
eventC := ui.eventBus.Register()
|
||||
|
||||
@ -425,9 +418,9 @@ func (ui *UI) handleOtherInstanceDetected(event.OtherInstanceDetectedEvent) {
|
||||
false,
|
||||
func(buttonIndex int, _ string) {
|
||||
if buttonIndex == 0 {
|
||||
ui.commandC <- event.CommandCloseOtherInstance{}
|
||||
ui.dispatch(event.CommandCloseOtherInstance{})
|
||||
} else {
|
||||
ui.commandC <- event.CommandQuit{}
|
||||
ui.dispatch(event.CommandQuit{})
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -457,7 +450,7 @@ func (ui *UI) handleFatalErrorOccurred(evt event.FatalErrorOccurredEvent) {
|
||||
[]string{"Quit"},
|
||||
false,
|
||||
func(int, string) {
|
||||
ui.commandC <- event.CommandQuit{}
|
||||
ui.dispatch(event.CommandQuit{})
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -702,7 +695,7 @@ func (ui *UI) handleMediaServerClosed(exitReason string) {
|
||||
SetBackgroundColor(tcell.ColorBlack).
|
||||
SetTextColor(tcell.ColorWhite).
|
||||
SetDoneFunc(func(int, string) {
|
||||
ui.commandC <- event.CommandQuit{}
|
||||
ui.dispatch(event.CommandQuit{})
|
||||
})
|
||||
modal.SetBorderStyle(tcell.StyleDefault.Background(tcell.ColorBlack).Foreground(tcell.ColorWhite))
|
||||
|
||||
@ -873,10 +866,10 @@ func (ui *UI) addDestination() {
|
||||
AddInputField(inputLabelName, "My stream", inputLen, nil, nil).
|
||||
AddInputField(inputLabelURL, "rtmp://", inputLen, nil, nil).
|
||||
AddButton("Add", func() {
|
||||
ui.commandC <- event.CommandAddDestination{
|
||||
ui.dispatch(event.CommandAddDestination{
|
||||
DestinationName: form.GetFormItemByLabel(inputLabelName).(*tview.InputField).GetText(),
|
||||
URL: form.GetFormItemByLabel(inputLabelURL).(*tview.InputField).GetText(),
|
||||
}
|
||||
})
|
||||
}).
|
||||
AddButton("Cancel", func() {
|
||||
ui.closeAddDestinationForm()
|
||||
@ -931,7 +924,7 @@ func (ui *UI) removeDestination() {
|
||||
false,
|
||||
func(buttonIndex int, _ string) {
|
||||
if buttonIndex == 0 {
|
||||
ui.commandC <- event.CommandRemoveDestination{URL: url}
|
||||
ui.dispatch(event.CommandRemoveDestination{URL: url})
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -1007,12 +1000,12 @@ func (ui *UI) toggleDestination() {
|
||||
switch ss {
|
||||
case startStateNotStarted:
|
||||
ui.urlsToStartState[url] = startStateStarting
|
||||
ui.commandC <- event.CommandStartDestination{URL: url}
|
||||
ui.dispatch(event.CommandStartDestination{URL: url})
|
||||
case startStateStarting:
|
||||
// do nothing
|
||||
return
|
||||
case startStateStarted:
|
||||
ui.commandC <- event.CommandStopDestination{URL: url}
|
||||
ui.dispatch(event.CommandStopDestination{URL: url})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1065,7 +1058,7 @@ func (ui *UI) confirmQuit() {
|
||||
false,
|
||||
func(buttonIndex int, _ string) {
|
||||
if buttonIndex == 0 {
|
||||
ui.commandC <- event.CommandQuit{}
|
||||
ui.dispatch(event.CommandQuit{})
|
||||
}
|
||||
},
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user