package chat
-import "sync"
+import (
+ "fmt"
+ "io"
+ "sync"
+)
+
+const timestampFmt = "2006-01-02 15:04:05"
// History contains the history entries
type History struct {
+ sync.RWMutex
entries []Message
head int
size int
- lock sync.Mutex
+ out io.Writer
}
// NewHistory constructs a new history of the given size
// Add adds the given entry to the entries in the history
func (h *History) Add(entry Message) {
- h.lock.Lock()
- defer h.lock.Unlock()
+ h.Lock()
+ defer h.Unlock()
max := cap(h.entries)
h.head = (h.head + 1) % max
if h.size < max {
h.size++
}
+
+ if h.out != nil {
+ fmt.Fprintf(h.out, "[%s] %s\n", entry.Timestamp().UTC().Format(timestampFmt), entry.String())
+ }
}
// Len returns the number of entries in the history
// Get the entry with the given number
func (h *History) Get(num int) []Message {
- h.lock.Lock()
- defer h.lock.Unlock()
+ h.RLock()
+ defer h.RUnlock()
max := cap(h.entries)
if num > h.size {
return r
}
+
+// SetOutput sets the output for logging added messages
+func (h *History) SetOutput(w io.Writer) {
+ h.Lock()
+ h.out = w
+ h.Unlock()
+}
Render(*Theme) string
String() string
Command() string
+ Timestamp() time.Time
}
type MessageTo interface {
return ""
}
+func (m *Msg) Timestamp() time.Time {
+ return m.timestamp
+}
+
// PublicMsg is any message from a user sent to the room.
type PublicMsg struct {
Msg
import (
"errors"
"fmt"
+ "io"
"sync"
)
})
}
+// SetLogging sets logging output for the room's history
+func (r *Room) SetLogging(out io.Writer) {
+ r.history.SetOutput(out)
+}
+
// HandleMsg reacts to a message, will block until done.
func (r *Room) HandleMsg(m Message) {
switch m := m.(type) {
Admin string `long:"admin" description:"File of public keys who are admins."`
Whitelist string `long:"whitelist" description:"Optional file of public keys who are allowed to connect."`
Motd string `long:"motd" description:"Optional Message of the Day file."`
+ Log string `long:"log" description:"Write chat log to this file."`
Pprof int `long:"pprof" description:"Enable pprof http server for profiling."`
}
return err
}
auth.Op(key)
- logger.Debugf("Added admin: %s", line)
+ logger.Debugf("Added admin: %s", sshd.Fingerprint(key))
return nil
})
if err != nil {
host.SetMotd(motdString)
}
+ if options.Log == "-" {
+ host.SetLogging(os.Stdout)
+ } else if options.Log != "" {
+ fp, err := os.OpenFile(options.Log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
+ if err != nil {
+ logger.Errorf("Failed to open log file for writing: %v", err)
+ return
+ }
+ host.SetLogging(fp)
+ }
+
go host.Serve()
// Construct interrupt handler