Eric Bower
·
17 May 24
cli.go
1package pico
2
3import (
4 "fmt"
5 "log/slog"
6 "strings"
7
8 "github.com/charmbracelet/ssh"
9 "github.com/charmbracelet/wish"
10 "github.com/picosh/pico/db"
11 "github.com/picosh/pico/shared"
12 "github.com/picosh/pico/tui/common"
13 "github.com/picosh/pico/tui/notifications"
14 "github.com/picosh/pico/tui/plus"
15)
16
17func getUser(s ssh.Session, dbpool db.DB) (*db.User, error) {
18 var err error
19 key, err := shared.KeyText(s)
20 if err != nil {
21 return nil, fmt.Errorf("key not found")
22 }
23
24 user, err := dbpool.FindUserForKey(s.User(), key)
25 if err != nil {
26 return nil, err
27 }
28
29 if user.Name == "" {
30 return nil, fmt.Errorf("must have username set")
31 }
32
33 return user, nil
34}
35
36type Cmd struct {
37 User *db.User
38 Session shared.CmdSession
39 Log *slog.Logger
40 Dbpool db.DB
41 Write bool
42 Styles common.Styles
43}
44
45func (c *Cmd) output(out string) {
46 _, _ = c.Session.Write([]byte(out + "\r\n"))
47}
48
49func (c *Cmd) help() {
50 helpStr := "Commands: [help, pico+]\n"
51 c.output(helpStr)
52}
53
54func (c *Cmd) plus() {
55 view := plus.PlusView(c.User.Name, 80)
56 c.output(view)
57}
58
59func (c *Cmd) notifications() error {
60 md := notifications.NotificationsView(c.Dbpool, c.User.ID, 80)
61 c.output(md)
62 return nil
63}
64
65type CliHandler struct {
66 DBPool db.DB
67 Logger *slog.Logger
68}
69
70func WishMiddleware(handler *CliHandler) wish.Middleware {
71 dbpool := handler.DBPool
72 log := handler.Logger
73
74 return func(next ssh.Handler) ssh.Handler {
75 return func(sesh ssh.Session) {
76 args := sesh.Command()
77 if len(args) == 0 {
78 next(sesh)
79 return
80 }
81
82 user, err := getUser(sesh, dbpool)
83 if err != nil {
84 wish.Errorf(sesh, "detected ssh command: %s\n", args)
85 s := fmt.Errorf("error: you need to create an account before using the remote cli: %w", err)
86 wish.Fatalln(sesh, s)
87 return
88 }
89
90 if len(args) > 0 && args[0] == "chat" {
91 _, _, hasPty := sesh.Pty()
92 if !hasPty {
93 wish.Fatalln(
94 sesh,
95 "In order to render chat you need to enable PTY with the `ssh -t` flag",
96 )
97 return
98 }
99
100 pass, err := dbpool.UpsertToken(user.ID, "pico-chat")
101 if err != nil {
102 wish.Fatalln(sesh, err)
103 return
104 }
105 app, err := shared.NewSenpaiApp(sesh, user.Name, pass)
106 if err != nil {
107 wish.Fatalln(sesh, err)
108 return
109 }
110 app.Run()
111 app.Close()
112 return
113 }
114
115 opts := Cmd{
116 Session: sesh,
117 User: user,
118 Log: log,
119 Dbpool: dbpool,
120 Write: false,
121 }
122
123 cmd := strings.TrimSpace(args[0])
124 if len(args) == 1 {
125 if cmd == "help" {
126 opts.help()
127 return
128 } else if cmd == "pico+" {
129 opts.plus()
130 return
131 } else if cmd == "notifications" {
132 err := opts.notifications()
133 if err != nil {
134 wish.Fatalln(sesh, err)
135 }
136 return
137 } else {
138 next(sesh)
139 return
140 }
141 }
142
143 next(sesh)
144 }
145 }
146}