Add channel logging feature
This commit is contained in:
parent
8004edb7b8
commit
1e702b0e1e
|
@ -50,6 +50,8 @@ type Config struct {
|
|||
VIP VIP
|
||||
|
||||
MessageFilters []*MessageFilter
|
||||
|
||||
Logging Logging
|
||||
}
|
||||
|
||||
type TurnConfig struct {
|
||||
|
@ -99,6 +101,14 @@ type WebhookURL struct {
|
|||
URL string
|
||||
}
|
||||
|
||||
// Logging configs to monitor channels or usernames.
|
||||
type Logging struct {
|
||||
Enabled bool
|
||||
Directory string
|
||||
Channels []string
|
||||
Usernames []string
|
||||
}
|
||||
|
||||
// Current loaded configuration.
|
||||
var Current = DefaultConfig()
|
||||
|
||||
|
@ -175,6 +185,11 @@ func DefaultConfig() Config {
|
|||
ChatServerResponse: "Watch your language.",
|
||||
},
|
||||
},
|
||||
Logging: Logging{
|
||||
Directory: "./logs",
|
||||
Channels: []string{"lobby", "offtopic"},
|
||||
Usernames: []string{},
|
||||
},
|
||||
}
|
||||
c.JWT.Strict = true
|
||||
return c
|
||||
|
|
|
@ -220,12 +220,26 @@ func (s *Server) OnMessage(sub *Subscriber, msg messages.Message) {
|
|||
return
|
||||
}
|
||||
|
||||
// Log this conversation?
|
||||
if IsLoggingUsername(sub) {
|
||||
// The sender of this message is being logged.
|
||||
LogMessage(sub, rcpt.Username, sub.Username, msg)
|
||||
} else if IsLoggingUsername(rcpt) {
|
||||
// The recipient of this message is being logged.
|
||||
LogMessage(rcpt, sub.Username, sub.Username, msg)
|
||||
}
|
||||
|
||||
if err := s.SendTo(msg.Channel, message); err != nil {
|
||||
sub.ChatServer("Your message could not be delivered: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Are we logging this public channel?
|
||||
if IsLoggingChannel(msg.Channel) {
|
||||
LogChannel(s, msg.Channel, sub.Username, msg)
|
||||
}
|
||||
|
||||
// Broadcast a chat message to the room.
|
||||
s.Broadcast(message)
|
||||
}
|
||||
|
|
144
pkg/logging.go
Normal file
144
pkg/logging.go
Normal file
|
@ -0,0 +1,144 @@
|
|||
package barertc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.kirsle.net/apps/barertc/pkg/config"
|
||||
"git.kirsle.net/apps/barertc/pkg/log"
|
||||
"git.kirsle.net/apps/barertc/pkg/messages"
|
||||
)
|
||||
|
||||
// IsLoggingUsername checks whether the app is currently configured to log a user's DMs.
|
||||
func IsLoggingUsername(sub *Subscriber) bool {
|
||||
if !config.Current.Logging.Enabled {
|
||||
return false
|
||||
}
|
||||
|
||||
// Has a cached setting and writer.
|
||||
if sub.log {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check the server config.
|
||||
for _, username := range config.Current.Logging.Usernames {
|
||||
if username == sub.Username {
|
||||
sub.log = true
|
||||
}
|
||||
}
|
||||
|
||||
return sub.log
|
||||
}
|
||||
|
||||
// IsLoggingChannel checks whether the app is currently logging a public channel.
|
||||
func IsLoggingChannel(channel string) bool {
|
||||
if !config.Current.Logging.Enabled {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, value := range config.Current.Logging.Channels {
|
||||
if value == channel {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// LogMessage appends to a user's conversation log.
|
||||
func LogMessage(sub *Subscriber, otherUsername, senderUsername string, msg messages.Message) {
|
||||
if !sub.log {
|
||||
return
|
||||
}
|
||||
|
||||
// Create or get the filehandle.
|
||||
fh, err := initLogFile(sub, "@"+sub.Username, otherUsername)
|
||||
if err != nil {
|
||||
log.Error("LogMessage(%s): %s", sub.Username, err)
|
||||
return
|
||||
}
|
||||
|
||||
fh.Write(
|
||||
[]byte(fmt.Sprintf(
|
||||
"%s [%s] %s\n",
|
||||
time.Now().Format(time.RFC3339),
|
||||
senderUsername,
|
||||
msg.Message,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
// LogChannel appends to a channel's conversation log.
|
||||
func LogChannel(s *Server, channel string, username string, msg messages.Message) {
|
||||
fh, err := initLogFile(s, channel)
|
||||
if err != nil {
|
||||
log.Error("LogChannel(%s): %s", channel, err)
|
||||
}
|
||||
|
||||
fh.Write(
|
||||
[]byte(fmt.Sprintf(
|
||||
"%s [%s] %s\n",
|
||||
time.Now().Format(time.RFC3339),
|
||||
username,
|
||||
msg.Message,
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
// Initialize a logging directory.
|
||||
func initLogFile(sub LogCacheable, components ...string) (io.Writer, error) {
|
||||
// Initialize the logfh cache?
|
||||
var logfh = sub.GetLogFilehandleCache()
|
||||
|
||||
var (
|
||||
suffix = components[len(components)-1]
|
||||
middle = components[:len(components)-1]
|
||||
paths = append([]string{
|
||||
config.Current.Logging.Directory,
|
||||
}, middle...,
|
||||
)
|
||||
filename = strings.Join(
|
||||
append(paths, suffix+".txt"),
|
||||
"/",
|
||||
)
|
||||
)
|
||||
|
||||
// Already have this conversation log open?
|
||||
if fh, ok := logfh[suffix]; ok {
|
||||
return fh, nil
|
||||
}
|
||||
|
||||
log.Warn("Initialize log directory: path=%+v suffix=%s", paths, suffix)
|
||||
if err := os.MkdirAll(strings.Join(paths, "/"), 0755); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fh, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logfh[suffix] = fh
|
||||
return logfh[suffix], nil
|
||||
}
|
||||
|
||||
// Interface for objects that hold log filehandle caches.
|
||||
type LogCacheable interface {
|
||||
GetLogFilehandleCache() map[string]io.Writer
|
||||
}
|
||||
|
||||
// Implementations of LogCacheable.
|
||||
func (sub *Subscriber) GetLogFilehandleCache() map[string]io.Writer {
|
||||
if sub.logfh == nil {
|
||||
sub.logfh = map[string]io.Writer{}
|
||||
}
|
||||
return sub.logfh
|
||||
}
|
||||
func (s *Server) GetLogFilehandleCache() map[string]io.Writer {
|
||||
if s.logfh == nil {
|
||||
s.logfh = map[string]io.Writer{}
|
||||
}
|
||||
return s.logfh
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package barertc
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
@ -16,6 +17,9 @@ type Server struct {
|
|||
// Connected WebSocket subscribers.
|
||||
subscribersMu sync.RWMutex
|
||||
subscribers map[*Subscriber]struct{}
|
||||
|
||||
// Cached filehandles for channel logging.
|
||||
logfh map[string]io.Writer
|
||||
}
|
||||
|
||||
// NewServer initializes the Server.
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -44,6 +45,10 @@ type Subscriber struct {
|
|||
// Record which message IDs belong to this user.
|
||||
midMu sync.Mutex
|
||||
messageIDs map[int64]struct{}
|
||||
|
||||
// Logging.
|
||||
log bool
|
||||
logfh map[string]io.Writer
|
||||
}
|
||||
|
||||
// ReadLoop spawns a goroutine that reads from the websocket connection.
|
||||
|
|
Loading…
Reference in New Issue
Block a user