98 lines
2.7 KiB
Go
98 lines
2.7 KiB
Go
|
package barertc
|
||
|
|
||
|
import (
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"git.kirsle.net/apps/barertc/pkg/config"
|
||
|
"git.kirsle.net/apps/barertc/pkg/log"
|
||
|
"git.kirsle.net/apps/barertc/pkg/messages"
|
||
|
)
|
||
|
|
||
|
// Functionality for storing recent public channel messages and echo them to new joiners.
|
||
|
|
||
|
/*
|
||
|
Echo Messages On Join
|
||
|
|
||
|
This feature stores recent public messages to channels (in memory) to echo them
|
||
|
back to new users when they join the room.
|
||
|
*/
|
||
|
var (
|
||
|
echoMessages = map[string][]messages.Message{} // map channel ID -> messages
|
||
|
echoLock sync.RWMutex
|
||
|
)
|
||
|
|
||
|
// SendEchoedMessages will repeat recent public messages in public channels to the newly
|
||
|
// connecting subscriber as echoed messages.
|
||
|
func (sub *Subscriber) SendEchoedMessages() {
|
||
|
var echoes []messages.Message
|
||
|
|
||
|
// Read lock to collect the messages.
|
||
|
echoLock.RLock()
|
||
|
|
||
|
for _, msgs := range echoMessages {
|
||
|
echoes = append(echoes, msgs...)
|
||
|
}
|
||
|
|
||
|
// Release the lock.
|
||
|
echoLock.RUnlock()
|
||
|
|
||
|
// Send all of these in one Echo message.
|
||
|
sub.SendJSON(messages.Message{
|
||
|
Action: messages.ActionEcho,
|
||
|
Messages: echoes,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// EchoPushPublicMessage pushes a message into the recent message history of the channel ID.
|
||
|
//
|
||
|
// The buffer of recent messages (the size configured in settings.toml) is echoed to
|
||
|
// a new user when they join the chat so they can catch up.
|
||
|
func (s *Server) EchoPushPublicMessage(sub *Subscriber, channel string, msg messages.Message) {
|
||
|
|
||
|
// Get the channel from settings to see its capacity.
|
||
|
ch, ok := config.Current.GetChannel(channel)
|
||
|
if !ok {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
echoLock.Lock()
|
||
|
defer echoLock.Unlock()
|
||
|
|
||
|
// Initialize the storage for this channel?
|
||
|
if _, ok := echoMessages[channel]; !ok {
|
||
|
echoMessages[channel] = []messages.Message{}
|
||
|
}
|
||
|
|
||
|
// Timestamp it and append this message.
|
||
|
msg.Timestamp = time.Now().Format(time.RFC3339)
|
||
|
echoMessages[channel] = append(echoMessages[channel], msg)
|
||
|
|
||
|
// Trim the history to the configured window size.
|
||
|
if ln := len(echoMessages[channel]); ln > ch.EchoMessagesOnJoin {
|
||
|
echoMessages[channel] = echoMessages[channel][ln-ch.EchoMessagesOnJoin:]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// EchoTakebackMessage will remove any taken-back message that was cached
|
||
|
// in the echo buffer for new joiners.
|
||
|
func (s *Server) EchoTakebackMessage(msgID int64) {
|
||
|
|
||
|
// Takebacks are relatively uncommon enough, write lock while we read and/or
|
||
|
// maybe remove messages from the echo cache.
|
||
|
echoLock.Lock()
|
||
|
defer echoLock.Unlock()
|
||
|
|
||
|
// Find matching messages in each channel.
|
||
|
for _, ch := range config.Current.PublicChannels {
|
||
|
for i, msg := range echoMessages[ch.ID] {
|
||
|
if msg.MessageID == msgID {
|
||
|
log.Error("EchoTakebackMessage: message ID %d removed from channel %s", msgID, ch.ID)
|
||
|
|
||
|
// Remove this message.
|
||
|
echoMessages[ch.ID] = append(echoMessages[ch.ID][:i], echoMessages[ch.ID][i+1:]...)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|