Skip to content

Commit e86996e

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

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
@@ -301,12 +264,13 @@ func (h *Host) AutoCompleteFunction(u Replier) func(line string, pos int, key ru
301264
}
302265

303266
// GetUser returns a message.User based on a name.
304-
func (h *Host) GetUser(name string) (chat.Member, bool) {
267+
func (h *Host) GetUser(name string) (User, bool) {
305268
m, ok := h.MemberByID(name)
306269
if !ok {
307270
return nil, false
308271
}
309-
return m.Member, true
272+
u, ok := m.Member.(User)
273+
return u, ok
310274
}
311275

312276
// InitCommands adds host-specific commands to a Commands container. These will
@@ -336,7 +300,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
336300
txt := fmt.Sprintf("[Sent PM to %s]", target.Name())
337301
ms := message.NewSystemMsg(txt, msg.From())
338302
room.Send(ms)
339-
target.(Replier).SetReplyTo(msg.From())
303+
target.SetReplyTo(msg.From())
340304
return nil
341305
},
342306
})
@@ -352,7 +316,7 @@ func (h *Host) InitCommands(c *chat.Commands) {
352316
return errors.New("must specify message")
353317
}
354318

355-
target := msg.From().(Replier).ReplyTo()
319+
target := msg.From().(chat.Member).ReplyTo()
356320
if target == nil {
357321
return errors.New("no message to reply to")
358322
}
@@ -388,14 +352,12 @@ func (h *Host) InitCommands(c *chat.Commands) {
388352
return errors.New("user not found")
389353
}
390354

391-
// FIXME: Handle many clients
392-
clients := h.findClients(target)
393355
var whois string
394356
switch room.IsOp(msg.From().(chat.Member)) {
395357
case true:
396-
whois = whoisAdmin(clients)
358+
whois = whoisAdmin(target)
397359
case false:
398-
whois = whoisPublic(clients)
360+
whois = whoisPublic(target)
399361
}
400362
room.Send(message.NewSystemMsg(whois, msg.From()))
401363

@@ -451,9 +413,12 @@ func (h *Host) InitCommands(c *chat.Commands) {
451413
room.Ops.Add(set.Keyize(user.ID()))
452414
}
453415

454-
for _, client := range h.findClients(user) {
455-
h.auth.Op(client.conn.PublicKey(), until)
456-
}
416+
// TODO: Add pubkeys to op
417+
/*
418+
for _, conn := range user.Connections() {
419+
h.auth.Op(conn.PublicKey(), until)
420+
}
421+
*/
457422

458423
body := fmt.Sprintf("Made op by %s.", msg.From().Name())
459424
room.Send(message.NewSystemMsg(body, user))
@@ -489,17 +454,16 @@ func (h *Host) InitCommands(c *chat.Commands) {
489454
until, _ = time.ParseDuration(args[1])
490455
}
491456

492-
clients := h.findClients(target)
493-
for _, client := range clients {
494-
h.auth.Ban(client.conn.PublicKey(), until)
495-
h.auth.BanAddr(client.conn.RemoteAddr(), until)
457+
for _, conn := range target.Connections() {
458+
h.auth.Ban(conn.PublicKey(), until)
459+
h.auth.BanAddr(conn.RemoteAddr(), until)
496460
}
497461

498462
body := fmt.Sprintf("%s was banned by %s.", target.Name(), msg.From().Name())
499463
room.Send(message.NewAnnounceMsg(body))
500-
target.(io.Closer).Close()
464+
target.Close()
501465

502-
logger.Debugf("Banned: \n-> %s", whoisAdmin(clients))
466+
logger.Debugf("Banned: \n-> %s", whoisAdmin(target))
503467

504468
return nil
505469
},

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)