1package server
2
3import (
4 "fmt"
5
6 "github.com/aymanbagabas/go-osc52"
7 tea "github.com/charmbracelet/bubbletea"
8 "github.com/charmbracelet/soft-serve/server/backend"
9 cm "github.com/charmbracelet/soft-serve/server/cmd"
10 "github.com/charmbracelet/soft-serve/server/config"
11 "github.com/charmbracelet/soft-serve/ui"
12 "github.com/charmbracelet/soft-serve/ui/common"
13 "github.com/charmbracelet/ssh"
14 "github.com/charmbracelet/wish"
15 bm "github.com/charmbracelet/wish/bubbletea"
16 "github.com/prometheus/client_golang/prometheus"
17 "github.com/prometheus/client_golang/prometheus/promauto"
18)
19
20var (
21 tuiSessionCounter = promauto.NewCounterVec(prometheus.CounterOpts{
22 Namespace: "soft_serve",
23 Subsystem: "ssh",
24 Name: "tui_session_total",
25 Help: "The total number of TUI sessions",
26 }, []string{"key", "user", "repo", "term"})
27)
28
29// SessionHandler is the soft-serve bubbletea ssh session handler.
30func SessionHandler(cfg *config.Config) bm.ProgramHandler {
31 return func(s ssh.Session) *tea.Program {
32 ak := backend.MarshalAuthorizedKey(s.PublicKey())
33 pty, _, active := s.Pty()
34 if !active {
35 return nil
36 }
37
38 cmd := s.Command()
39 initialRepo := ""
40 if len(cmd) == 1 {
41 initialRepo = cmd[0]
42 auth := cfg.Backend.AccessLevelByPublicKey(initialRepo, s.PublicKey())
43 if auth < backend.ReadOnlyAccess {
44 wish.Fatalln(s, cm.ErrUnauthorized)
45 return nil
46 }
47 }
48
49 envs := s.Environ()
50 envs = append(envs, fmt.Sprintf("TERM=%s", pty.Term))
51 output := osc52.NewOutput(s, envs)
52 c := common.NewCommon(s.Context(), output, pty.Window.Width, pty.Window.Height)
53 c.SetValue(common.ConfigKey, cfg)
54 m := ui.New(c, initialRepo)
55 p := tea.NewProgram(m,
56 tea.WithInput(s),
57 tea.WithOutput(s),
58 tea.WithAltScreen(),
59 tea.WithoutCatchPanics(),
60 tea.WithMouseCellMotion(),
61 )
62
63 tuiSessionCounter.WithLabelValues(ak, s.User(), initialRepo, pty.Term).Inc()
64
65 return p
66 }
67}