diff --git a/internal/bot/bot.go b/internal/bot/bot.go index d3b4ec5..e0d3738 100644 --- a/internal/bot/bot.go +++ b/internal/bot/bot.go @@ -28,11 +28,11 @@ const DisplayName = "calc" const Welcome = "Send me arithmetic, such as 2 + 2 or 5 * 5/2, " + "and I will reply with the result." -const ( - // chatPort is where the chat client serves its API, on localhost - // inside the bot's own container. - chatPort = 5225 +// ChatPort is where the chat client serves its API, on localhost inside +// the bot's own container. +const ChatPort = 5225 +const ( // connectTimeout bounds the wait for a freshly started chat client // to open its API, which includes creating or migrating the // database. @@ -54,12 +54,15 @@ const ( var errExited = errors.New("simplex-chat exited") -// Run starts the chat client with its database in cfg.DataDir, connects -// to it, sets up the bot's address, then answers messages and serves the -// API until ctx is cancelled — which is a clean stop and returns nil — -// or until the chat client, the connection to it or the API's listener -// fails, which returns the error. -func Run(ctx context.Context, log *slog.Logger, cfg *config.Config) error { +// Run starts the chat client with its database in cfg.DataDir, serving +// its API on localhost at chatPort, connects to it, sets up the bot's +// address, then answers messages and serves the bot's API until ctx is +// cancelled — which is a clean stop and returns nil — or until the chat +// client, the connection to it or the API's listener fails, which +// returns the error. +func Run( + ctx context.Context, log *slog.Logger, cfg *config.Config, chatPort int, +) error { err := os.MkdirAll(cfg.DataDir, dataDirMode) if err != nil { return fmt.Errorf("creating data directory: %w", err) @@ -84,7 +87,7 @@ func Run(ctx context.Context, log *slog.Logger, cfg *config.Config) error { <-cli.Done() }() - client, err := connect(ctx, log, cli) + client, err := connect(ctx, log, cli, chatPort) if err != nil { return err } @@ -143,9 +146,10 @@ func stopAPI(ctx context.Context, log *slog.Logger, srv *http.Server) { } } -// connect waits for the chat client to open its API and connects to it. +// connect waits for the chat client to open its API on chatPort and +// connects to it. func connect( - ctx context.Context, log *slog.Logger, cli *simplex.CLI, + ctx context.Context, log *slog.Logger, cli *simplex.CLI, chatPort int, ) (*simplex.Client, error) { ctx, cancel := context.WithTimeout(ctx, connectTimeout) defer cancel() diff --git a/internal/bot/run_test.go b/internal/bot/run_test.go index a14620f..0c89299 100644 --- a/internal/bot/run_test.go +++ b/internal/bot/run_test.go @@ -52,9 +52,7 @@ func TestMain(m *testing.M) { // port it is given, on localhost, and answers the commands the bot // sends. SIGTERM ends it, as it ends the real client. Unlike the real // client, it also exits when the bot hangs up, so that it never -// outlives a test run that was cut short. It takes port 5225, the chat -// client's fixed port, so this test cannot run twice at once on one -// machine. +// outlives a test run that was cut short. func standIn() { arg := func(name string) string { return os.Args[slices.Index(os.Args, name)+1] @@ -142,6 +140,8 @@ func TestStopDuringRequest(t *testing.T) { t.Setenv("PATH", bin) cfg := &config.Config{DataDir: t.TempDir(), Port: freePort(t), APIToken: credential} + // Never bot.ChatPort: a real chat client may be listening there. + chatPort := freePort(t) ctx, stop := context.WithCancel(t.Context()) done := make(chan struct{}) @@ -150,7 +150,7 @@ func TestStopDuringRequest(t *testing.T) { go func() { defer close(done) - runErr = bot.Run(ctx, slog.New(slog.DiscardHandler), cfg) + runErr = bot.Run(ctx, slog.New(slog.DiscardHandler), cfg, chatPort) }() t.Cleanup(func() { diff --git a/internal/cli/run.go b/internal/cli/run.go index 8392856..a863fd2 100644 --- a/internal/cli/run.go +++ b/internal/cli/run.go @@ -45,7 +45,7 @@ func run(ctx context.Context, version string) error { ctx, stop := signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM) defer stop() - err = bot.Run(ctx, log, cfg) + err = bot.Run(ctx, log, cfg, bot.ChatPort) if err != nil { log.Error("stopped", "error", err)