Skip to content

Commit cd69d0b

Browse files
committed
progress: Host User interface, and more interfaces in general, tests pass
1 parent d197b97 commit cd69d0b

File tree

6 files changed

+71
-89
lines changed

6 files changed

+71
-89
lines changed

chat/member.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package chat
22

33
import (
4+
"time"
5+
46
"github.com/shazow/ssh-chat/chat/message"
57
"github.com/shazow/ssh-chat/set"
68
)
@@ -21,4 +23,10 @@ type Member interface {
2123
SetConfig(message.UserConfig)
2224

2325
Send(message.Message) error
26+
27+
Joined() time.Time
28+
ReplyTo() message.Author
29+
SetReplyTo(message.Author)
30+
Prompt() string
31+
SetHighlight(string) error
2432
}

chat/message/user.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,7 @@ func (u *User) Color() int {
3838
func (u *User) ID() string {
3939
return SanitizeName(u.name)
4040
}
41+
42+
func (u *User) Joined() time.Time {
43+
return u.joined
44+
}

chat/room.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,8 @@ func (r *Room) MemberByID(id string) (*roomMember, bool) {
199199
if err != nil {
200200
return nil, false
201201
}
202-
return m.Value().(*roomMember), true
202+
rm, ok := m.Value().(*roomMember)
203+
return rm, ok
203204
}
204205

205206
// IsOp returns whether a user is an operator in this room.

client.go

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
package sshchat
22

33
import (
4-
"time"
4+
"sync"
55

66
"github.com/shazow/ssh-chat/chat"
7-
"github.com/shazow/ssh-chat/chat/message"
87
"github.com/shazow/ssh-chat/sshd"
98
)
109

11-
type Client struct {
12-
user chat.Member
13-
conn sshd.Connection
10+
type client struct {
11+
chat.Member
12+
sync.Mutex
13+
conns []sshd.Connection
14+
}
15+
16+
func (cl *client) Connections() []sshd.Connection {
17+
return cl.conns
18+
}
1419

15-
timestamp time.Time
20+
func (cl *client) Close() error {
21+
// TODO: Stack errors?
22+
for _, conn := range cl.conns {
23+
conn.Close()
24+
}
25+
return nil
1626
}
1727

18-
type Replier interface {
19-
ReplyTo() message.Author
20-
SetReplyTo(message.Author)
28+
type User interface {
29+
chat.Member
30+
31+
Connections() []sshd.Connection
32+
Close() error
2133
}

host.go

Lines changed: 28 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type Host struct {
3535
mu sync.Mutex
3636
motd string
3737
count int
38-
clients map[chat.Member][]Client
38+
clients map[chat.Member][]client
3939
}
4040

4141
// NewHost creates a Host on top of an existing listener.
@@ -46,7 +46,7 @@ func NewHost(listener *sshd.SSHListener, auth *Auth) *Host {
4646
listener: listener,
4747
commands: chat.Commands{},
4848
auth: auth,
49-
clients: map[chat.Member][]Client{},
49+
clients: map[chat.Member][]client{},
5050
}
5151

5252
// Make our own commands registry instance.
@@ -75,10 +75,11 @@ func (h *Host) SetMotd(motd string) {
7575
// Connect a specific Terminal to this host and its room.
7676
func (h *Host) Connect(term *sshd.Terminal) {
7777
requestedName := term.Conn.Name()
78-
user := message.BufferedScreen(requestedName, term)
79-
80-
client := h.addClient(user, term.Conn)
81-
defer h.removeClient(user, client)
78+
screen := message.BufferedScreen(requestedName, term)
79+
user := &client{
80+
Member: screen,
81+
conns: []sshd.Connection{term.Conn},
82+
}
8283

8384
h.mu.Lock()
8485
motd := h.motd
@@ -91,10 +92,10 @@ func (h *Host) Connect(term *sshd.Terminal) {
9192
user.SetConfig(cfg)
9293

9394
// Close term once user is closed.
94-
defer user.Close()
95+
defer screen.Close()
9596
defer term.Close()
9697

97-
go user.Consume()
98+
go screen.Consume()
9899

99100
// Send MOTD
100101
if motd != "" {
@@ -180,44 +181,6 @@ func (h *Host) Connect(term *sshd.Terminal) {
180181
logger.Debugf("[%s] Leaving: %s", term.Conn.RemoteAddr(), user.Name())
181182
}
182183

183-
func (h *Host) addClient(user chat.Member, conn sshd.Connection) *Client {
184-
client := Client{
185-
user: user,
186-
conn: conn,
187-
timestamp: time.Now(),
188-
}
189-
h.mu.Lock()
190-
if _, ok := h.clients[user]; ok {
191-
logger.Warningf("user collision: %q", user)
192-
}
193-
h.clients[user] = append(h.clients[user], client)
194-
h.mu.Unlock()
195-
return &client
196-
}
197-
198-
func (h *Host) removeClient(user chat.Member, client *Client) {
199-
h.mu.Lock()
200-
defer h.mu.Unlock()
201-
202-
clients := h.clients[user]
203-
for i, c := range clients {
204-
// Find the user
205-
if &c != client {
206-
continue
207-
}
208-
// Delete corresponding client
209-
clients[i] = clients[len(clients)-1]
210-
clients = clients[:len(clients)-1]
211-
break
212-
}
213-
}
214-
215-
func (h *Host) findClients(user chat.Member) []Client {
216-
h.mu.Lock()
217-
defer h.mu.Unlock()
218-
return h.clients[user]
219-
}
220-
221184
// Serve our chat room onto the listener
222185
func (h *Host) Serve() {
223186
h.listener.HandlerFunc = h.Connect
@@ -244,7 +207,7 @@ func (h *Host) completeCommand(partial string) string {
244207
}
245208

246209
// AutoCompleteFunction returns a callback for terminal autocompletion
247-
func (h *Host) AutoCompleteFunction(u Replier) func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
210+
func (h *Host) AutoCompleteFunction(u User) func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
248211
return func(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
249212
if key != 9 {
250213
return
@@ -295,12 +258,13 @@ func (h *Host) AutoCompleteFunction(u Replier) func(line string, pos int, key ru
295258
}
296259

297260
// GetUser returns a message.User based on a name.
298-
func (h *Host) GetUser(name string) (chat.Member, bool) {
261+
func (h *Host) GetUser(name string) (User, bool) {
299262
m, ok := h.MemberByID(name)
300263
if !ok {
301264
return nil, false
302265
}
303-
return m.Member, true
266+
u, ok := m.Member.(User)
267+
return u, ok
304268
}
305269

306270
// InitCommands adds host-specific commands to a Commands container. These will
@@ -330,7 +294,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
330294
txt := fmt.Sprintf("[Sent PM to %s]", target.Name())
331295
ms := message.NewSystemMsg(txt, msg.From())
332296
room.Send(ms)
333-
target.(Replier).SetReplyTo(msg.From())
297+
target.SetReplyTo(msg.From())
334298
return nil
335299
},
336300
})
@@ -346,7 +310,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
346310
return errors.New("must specify message")
347311
}
348312

349-
target := msg.From().(Replier).ReplyTo()
313+
target := msg.From().(chat.Member).ReplyTo()
350314
if target == nil {
351315
return errors.New("no message to reply to")
352316
}
@@ -376,14 +340,12 @@ func (h *Host) InitCommands(c *chat.Commands) {
376340
return errors.New("user not found")
377341
}
378342

379-
// FIXME: Handle many clients
380-
clients := h.findClients(target)
381343
var whois string
382344
switch room.IsOp(msg.From().(chat.Member)) {
383345
case true:
384-
whois = whoisAdmin(clients)
346+
whois = whoisAdmin(target)
385347
case false:
386-
whois = whoisPublic(clients)
348+
whois = whoisPublic(target)
387349
}
388350
room.Send(message.NewSystemMsg(whois, msg.From()))
389351

@@ -439,9 +401,12 @@ func (h *Host) InitCommands(c *chat.Commands) {
439401
room.Ops.Add(set.Keyize(user.ID()))
440402
}
441403

442-
for _, client := range h.findClients(user) {
443-
h.auth.Op(client.conn.PublicKey(), until)
444-
}
404+
// TODO: Add pubkeys to op
405+
/*
406+
for _, conn := range user.Connections() {
407+
h.auth.Op(conn.PublicKey(), until)
408+
}
409+
*/
445410

446411
body := fmt.Sprintf("Made op by %s.", msg.From().Name())
447412
room.Send(message.NewSystemMsg(body, user))
@@ -477,17 +442,16 @@ func (h *Host) InitCommands(c *chat.Commands) {
477442
until, _ = time.ParseDuration(args[1])
478443
}
479444

480-
clients := h.findClients(target)
481-
for _, client := range clients {
482-
h.auth.Ban(client.conn.PublicKey(), until)
483-
h.auth.BanAddr(client.conn.RemoteAddr(), until)
445+
for _, conn := range target.Connections() {
446+
h.auth.Ban(conn.PublicKey(), until)
447+
h.auth.BanAddr(conn.RemoteAddr(), until)
484448
}
485449

486450
body := fmt.Sprintf("%s was banned by %s.", target.Name(), msg.From().Name())
487451
room.Send(message.NewAnnounceMsg(body))
488-
target.(io.Closer).Close()
452+
target.Close()
489453

490-
logger.Debugf("Banned: \n-> %s", whoisAdmin(clients))
454+
logger.Debugf("Banned: \n-> %s", whoisAdmin(target))
491455

492456
return nil
493457
},

whois.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package sshchat
22

33
import (
44
"net"
5-
"time"
65

76
humanize "github.com/dustin/go-humanize"
87
"github.com/shazow/ssh-chat/chat/message"
@@ -11,28 +10,22 @@ import (
1110

1211
// Helpers for printing whois messages
1312

14-
type joinTimestamped interface {
15-
Joined() time.Time
16-
}
17-
18-
func whoisPublic(clients []Client) string {
19-
// FIXME: Handle many clients
20-
conn, u := clients[0].conn, clients[0].user
21-
13+
func whoisPublic(u User) string {
2214
fingerprint := "(no public key)"
15+
// FIXME: Use all connections?
16+
conn := u.Connections()[0]
2317
if conn.PublicKey() != nil {
2418
fingerprint = sshd.Fingerprint(conn.PublicKey())
2519
}
2620
return "name: " + u.Name() + message.Newline +
2721
" > fingerprint: " + fingerprint + message.Newline +
2822
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
29-
" > joined: " + humanize.Time(u.(joinTimestamped).Joined())
23+
" > joined: " + humanize.Time(u.Joined())
3024
}
3125

32-
func whoisAdmin(clients []Client) string {
33-
// FIXME: Handle many clients
34-
conn, u := clients[0].conn, clients[0].user
35-
26+
func whoisAdmin(u User) string {
27+
// FIXME: Use all connections?
28+
conn := u.Connections()[0]
3629
ip, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
3730
fingerprint := "(no public key)"
3831
if conn.PublicKey() != nil {
@@ -42,5 +35,5 @@ func whoisAdmin(clients []Client) string {
4235
" > ip: " + ip + message.Newline +
4336
" > fingerprint: " + fingerprint + message.Newline +
4437
" > client: " + SanitizeData(string(conn.ClientVersion())) + message.Newline +
45-
" > joined: " + humanize.Time(u.(joinTimestamped).Joined())
38+
" > joined: " + humanize.Time(u.Joined())
4639
}

0 commit comments

Comments
 (0)