diff --git a/TODO b/TODO index c9d23fe2..7c083330 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,6 @@ TODO - Move hardcoded addresses to opts -- Remove cleanup function from anvil (leaky abstraction) - Add unit tests to model - Add inspect API - Add graphql API diff --git a/internal/nonodo/anvil.go b/internal/nonodo/anvil.go index b57ced96..8b35a6c5 100644 --- a/internal/nonodo/anvil.go +++ b/internal/nonodo/anvil.go @@ -4,6 +4,7 @@ package nonodo import ( + "context" _ "embed" "fmt" "log" @@ -20,6 +21,47 @@ import ( //go:embed anvil_state.json var anvilState []byte +// Start the anvil process in the host machine. +type anvilService struct { + ready chan struct{} + command *supervisor.CommandService + cleanup func() +} + +func newAnvilService(opts opts.NonodoOpts) *anvilService { + stateFile, cleanup := loadStateFile() + args := []string{ + "--port", fmt.Sprint(opts.AnvilPort), + "--block-time", fmt.Sprint(opts.AnvilBlockTime), + "--load-state", stateFile, + } + if !opts.AnvilVerbose { + args = append(args, "--silent") + } + return &anvilService{ + ready: make(chan struct{}), + command: supervisor.NewCommandService("anvil", args, nil, opts.AnvilPort), + cleanup: cleanup, + } +} + +func (s *anvilService) Start(ctx context.Context) error { + go func() { + // cleanup after the internal service is ready + defer s.cleanup() + select { + case <-s.command.Ready(): + s.ready <- struct{}{} + case <-ctx.Done(): + } + }() + return s.command.Start(ctx) +} + +func (s *anvilService) Ready() <-chan struct{} { + return s.ready +} + // Create a temporary file with the anvil state. // Return a function to delete this file. func loadStateFile() (string, func()) { @@ -41,19 +83,3 @@ func loadStateFile() (string, func()) { } return path, cleanup } - -// Start the anvil process in the host machine. -// Return a close function that should be called when the program finishes. -func newAnvilService(opts opts.NonodoOpts) (supervisor.Service, func()) { - stateFile, cleanup := loadStateFile() - args := []string{ - "--port", fmt.Sprint(opts.AnvilPort), - "--block-time", fmt.Sprint(opts.AnvilBlockTime), - "--load-state", stateFile, - } - if !opts.AnvilVerbose { - args = append(args, "--silent") - } - service := supervisor.NewCommandService("anvil", args, nil, opts.AnvilPort) - return service, cleanup -} diff --git a/internal/nonodo/nonodo.go b/internal/nonodo/nonodo.go index e95eae54..f21bb1d1 100644 --- a/internal/nonodo/nonodo.go +++ b/internal/nonodo/nonodo.go @@ -15,19 +15,12 @@ import ( ) func Run(ctx context.Context, opts opts.NonodoOpts) { + model := model.NewNonodoModel() var services []supervisor.Service - services = append(services, supervisor.NewSignalListenerService()) - - anvil, cleanup := newAnvilService(opts) - defer cleanup() - services = append(services, anvil) - - model := model.NewNonodoModel() + services = append(services, newAnvilService(opts)) rpcEndpoint := fmt.Sprintf("ws://127.0.0.1:%v", opts.AnvilPort) services = append(services, newInputterService(model, rpcEndpoint)) - services = append(services, newEchoService(model, opts.HttpPort)) - supervisor.Start(ctx, services) }