13 const messageBuffer = 5
14 const messageTimeout = 5 * time.Second
15 const reHighlight = `\b(%s)\b`
17 var ErrUserClosed = errors.New("user closed")
19 // User definition, implemented set Item interface and io.Writer
28 replyTo *User // Set when user gets a /msg, for replying.
33 func NewUser(identity Identifier) *User {
36 Config: DefaultUserConfig,
38 msg: make(chan Message, messageBuffer),
39 done: make(chan struct{}),
41 u.SetColorIdx(rand.Int())
46 func NewUserScreen(identity Identifier, screen io.WriteCloser) *User {
47 u := NewUser(identity)
53 // Rename the user with a new Identifier.
54 func (u *User) SetId(id string) {
55 u.Identifier.SetId(id)
56 u.SetColorIdx(rand.Int())
59 // ReplyTo returns the last user that messaged this user.
60 func (u *User) ReplyTo() *User {
64 // SetReplyTo sets the last user to message this user.
65 func (u *User) SetReplyTo(user *User) {
69 // ToggleQuietMode will toggle whether or not quiet mode is enabled
70 func (u *User) ToggleQuietMode() {
71 u.Config.Quiet = !u.Config.Quiet
74 // SetColorIdx will set the colorIdx to a specific value, primarily used for
76 func (u *User) SetColorIdx(idx int) {
80 // Block until user is closed
81 func (u *User) Wait() {
85 // Disconnect user, stop accepting messages
86 func (u *User) Close() {
87 u.closeOnce.Do(func() {
91 // close(u.msg) TODO: Close?
96 // Consume message buffer into the handler. Will block, should be called in a
98 func (u *User) Consume() {
103 case m, ok := <-u.msg:
112 // Consume one message and stop, mostly for testing
113 func (u *User) ConsumeOne() Message {
117 // SetHighlight sets the highlighting regular expression to match string.
118 func (u *User) SetHighlight(s string) error {
119 re, err := regexp.Compile(fmt.Sprintf(reHighlight, s))
123 u.Config.Highlight = re
127 func (u *User) render(m Message) string {
128 switch m := m.(type) {
130 return m.RenderFor(u.Config) + Newline
132 u.SetReplyTo(m.From())
133 return m.Render(u.Config.Theme) + Newline
135 return m.Render(u.Config.Theme) + Newline
139 // HandleMsg will render the message to the screen, blocking.
140 func (u *User) HandleMsg(m Message) error {
142 _, err := u.screen.Write([]byte(r))
144 logger.Printf("Write failed to %s, closing: %s", u.Name(), err)
150 // Add message to consume by user
151 func (u *User) Send(m Message) error {
156 case <-time.After(messageTimeout):
157 logger.Printf("Message buffer full, closing: %s", u.Name())
164 // Container for per-user configurations.
165 type UserConfig struct {
166 Highlight *regexp.Regexp
172 // Default user configuration to use
173 var DefaultUserConfig UserConfig
176 DefaultUserConfig = UserConfig{
181 // TODO: Seed random?