12 "github.com/shazow/ssh-chat/set"
15 const messageBuffer = 5
16 const messageTimeout = 5 * time.Second
17 const reHighlight = `\b(%s)\b`
19 var ErrUserClosed = errors.New("user closed")
21 // User definition, implemented set Item interface and io.Writer
35 replyTo *User // Set when user gets a /msg, for replying.
38 func NewUser(identity Identifier) *User {
41 config: DefaultUserConfig,
43 msg: make(chan Message, messageBuffer),
44 done: make(chan struct{}),
47 u.setColorIdx(rand.Int())
52 func NewUserScreen(identity Identifier, screen io.WriteCloser) *User {
53 u := NewUser(identity)
59 func (u *User) Config() UserConfig {
65 func (u *User) SetConfig(cfg UserConfig) {
71 // Rename the user with a new Identifier.
72 func (u *User) SetID(id string) {
73 u.Identifier.SetID(id)
74 u.setColorIdx(rand.Int())
77 // ReplyTo returns the last user that messaged this user.
78 func (u *User) ReplyTo() *User {
84 // SetReplyTo sets the last user to message this user.
85 func (u *User) SetReplyTo(user *User) {
91 // setColorIdx will set the colorIdx to a specific value, primarily used for
93 func (u *User) setColorIdx(idx int) {
97 // Disconnect user, stop accepting messages
98 func (u *User) Close() {
99 u.closeOnce.Do(func() {
103 // close(u.msg) TODO: Close?
108 // Consume message buffer into the handler. Will block, should be called in a
110 func (u *User) Consume() {
115 case m, ok := <-u.msg:
124 // Consume one message and stop, mostly for testing
125 func (u *User) ConsumeOne() Message {
129 // Check if there are pending messages, used for testing
130 func (u *User) HasMessages() bool {
140 // SetHighlight sets the highlighting regular expression to match string.
141 func (u *User) SetHighlight(s string) error {
142 re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
147 u.config.Highlight = re
152 func (u *User) render(m Message) string {
154 switch m := m.(type) {
156 return m.RenderFor(cfg) + Newline
158 u.SetReplyTo(m.From())
159 return m.Render(cfg.Theme) + Newline
161 return m.Render(cfg.Theme) + Newline
165 // HandleMsg will render the message to the screen, blocking.
166 func (u *User) HandleMsg(m Message) error {
168 _, err := u.screen.Write([]byte(r))
170 logger.Printf("Write failed to %s, closing: %s", u.Name(), err)
176 // Add message to consume by user
177 func (u *User) Send(m Message) error {
182 case <-time.After(messageTimeout):
183 logger.Printf("Message buffer full, closing: %s", u.Name())
190 // Container for per-user configurations.
191 type UserConfig struct {
192 Highlight *regexp.Regexp
198 // Default user configuration to use
199 var DefaultUserConfig UserConfig
202 DefaultUserConfig = UserConfig{
207 // TODO: Seed random?