From a4c25df1837d057f289ec17ce4a5106c246485ea Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 22 Jun 2023 12:03:37 -0700 Subject: [PATCH] Prompt: adds interactive prompt (that does nothing right now) --- go.mod | 3 ++- go.sum | 6 +++++ main.go | 28 ++++++++++++++++++--- prompt/prompt.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 prompt/prompt.go diff --git a/go.mod b/go.mod index 9dc6433..4d501a4 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,11 @@ module code.severnaya.net/kordophone-mock/v2 go 1.17 require ( + github.com/chzyer/readline v1.5.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect github.com/google/uuid v1.3.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect github.com/rs/zerolog v1.29.1 // indirect - golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect ) diff --git a/go.sum b/go.sum index ef347c5..c9ef3a0 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,7 @@ +github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= +github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= +github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= +github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -15,3 +19,5 @@ github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go index 1617de7..b19d73e 100644 --- a/main.go +++ b/main.go @@ -9,9 +9,18 @@ import ( "github.com/rs/zerolog/log" "code.severnaya.net/kordophone-mock/v2/web" + "code.severnaya.net/kordophone-mock/v2/prompt" ) -func main() { +type LoggingHook struct{ + prompt *prompt.Prompt +} + +func (t *LoggingHook) Run(e *zerolog.Event, level zerolog.Level, message string) { + t.prompt.CleanAndRefreshForLogging() +} + +func setupLogging() { debug := flag.Bool("debug", false, "enable debug logging") flag.Parse() @@ -23,8 +32,10 @@ func main() { if *debug { zerolog.SetGlobalLevel(zerolog.DebugLevel) } +} - log.Info().Msg("Initializing") +func main() { + setupLogging() c := web.MockHTTPServerConfiguration{ AuthEnabled: false, @@ -42,5 +53,16 @@ func main() { log.Info().Msgf("Generated test data. %d conversations", len(s.Server.Conversations())) log.Info().Msgf("Listening on %s", addr) - log.Fatal().Err(httpServer.ListenAndServe()) + go httpServer.ListenAndServe() + + rl := prompt.NewPrompt() + + // Hook logging so we can refresh the prompt when something is logged. + log.Logger = log.Logger.Hook(&LoggingHook{prompt: rl}) + + // Read indefinitely + err := rl.StartInteractive() + if err != nil { + log.Error().Err(err) + } } diff --git a/prompt/prompt.go b/prompt/prompt.go new file mode 100644 index 0000000..d04f78c --- /dev/null +++ b/prompt/prompt.go @@ -0,0 +1,63 @@ +package prompt + +import ( + "io" + + "github.com/rs/zerolog/log" + "github.com/chzyer/readline" +) + +type Prompt struct { + rl *readline.Instance +} + +func NewPrompt() *Prompt { + rl, err := readline.NewEx(&readline.Config{ + Prompt: "\033[31m»\033[0m ", + HistoryFile: "/tmp/readline.tmp", + InterruptPrompt: "^C", + EOFPrompt: "exit", + + HistorySearchFold: true, + }) + + if err != nil { + panic(err) + } + + return &Prompt{ + rl: rl, + } +} + +func (p *Prompt) StartInteractive() error { + for { + line, err := p.rl.Readline() + if err == readline.ErrInterrupt { + if len(line) == 0 { + break + } else { + continue + } + } else if err == io.EOF { + break + } + + switch { + case line == "exit": + return nil + default: + log.Info().Msgf("Line: %s", line) + } + } + + return nil +} + +func (p *Prompt) CleanAndRefreshForLogging() { + p.rl.Clean() + + // xxx: Lazy hack to make sure this runs _after_ the log is written. + go p.rl.Refresh() +} +