Skip to content

Instantly share code, notes, and snippets.

@terrabitz
Created February 5, 2021 19:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save terrabitz/b6781bbd2fb366c52d408f737fc84a5c to your computer and use it in GitHub Desktop.
Save terrabitz/b6781bbd2fb366c52d408f737fc84a5c to your computer and use it in GitHub Desktop.
Multiple tea.Msg Listeners
package main
import (
"context"
"fmt"
"log"
"net/http"
"net/http/httputil"
"strings"
"time"
"github.com/charmbracelet/bubbles/spinner"
tea "github.com/charmbracelet/bubbletea"
)
const spinnerFPS = 7
func main() {
requestsChan := make(chan *http.Request)
go func() {
time.Sleep(5 * time.Second)
r, err := http.NewRequest(http.MethodGet, "http://example.com", nil)
if err != nil {
log.Fatalln(err)
}
requestsChan <- r
}()
m := &model{
requestChan: requestsChan,
msgs: make(chan tea.Msg),
spinner: spinner.NewModel(),
}
m.spinner.Spinner = spinner.MiniDot
program := tea.NewProgram(m)
if err := program.Start(); err != nil {
log.Fatalln(err)
}
}
type Sub func(context.Context, chan<- tea.Msg)
type model struct {
msgs chan tea.Msg
requestChan <-chan *http.Request
currentRequest *http.Request
spinner spinner.Model
}
func (m *model) Init() tea.Cmd {
ctx := context.Background()
subs := []Sub{
m.listenSub,
m.tickSub,
}
for _, sub := range subs {
go sub(ctx, m.msgs)
}
return m.anyMsg
}
type requestMessage *http.Request
func (m *model) listenSub(ctx context.Context, msgs chan<- tea.Msg) {
for {
select {
case msgs <- requestMessage(<-m.requestChan):
case <-ctx.Done():
}
}
}
func (m *model) tickSub(ctx context.Context, msgs chan<- tea.Msg) {
t := time.NewTicker(time.Second / spinnerFPS)
for {
select {
case <-t.C:
select {
case msgs <- spinner.Tick():
case <-ctx.Done():
}
case <-ctx.Done():
t.Stop()
return
}
}
}
func (m *model) anyMsg() tea.Msg {
return <-m.msgs
}
func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "enter", " ":
if m.currentRequest == nil {
return m, m.anyMsg
}
m.currentRequest = nil
return m, m.anyMsg
}
case requestMessage:
m.currentRequest = (*http.Request)(msg)
return m, m.anyMsg
}
m.spinner, _ = m.spinner.Update(msg)
return m, m.anyMsg
}
func (m *model) View() string {
if m.currentRequest == nil {
return fmt.Sprintf("\n\n %s waiting for proxy requests to come in", m.spinner.View())
}
s := &strings.Builder{}
fmt.Fprintf(s, "URL: %v\n\n", m.currentRequest.RequestURI)
dump, err := httputil.DumpRequest(m.currentRequest, false)
if err != nil {
fmt.Fprintf(s, "<error while reading request body: %v>\n", err)
}
s.Write(dump)
return s.String()
}
@terrabitz
Copy link
Author

This gist is MIT licensed. See https://opensource.org/licenses/MIT for full license

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment