Add a feature where recent public channel messages can be echoed back to newly joining users when they enter the chat room. * Configure in settings.toml with EchoMessagesOnJoin. 0 = disable storage. * Messages are stored in RAM and lost on a server reboot. * A buffer of recent public messages per channel can be kept, e.g. for the 10 most recent messages. * The settings can be reloaded with /reconfigure and the message buffers will rebalance on the next message sent. * When a new user logs in, a new "echo" message is sent that contains all of the echoed messages on a "messages" list, in one WebSocket packet. * Echoed messages are put above the ChatServer welcome messages. * If a message is taken back, it's removed from the echo message buffer. Other Changes * Don't broadcast Presence messages within 30 seconds of the server boot, to lessen a flood of messages when a lot of users were connected at reboot. * Change the default "Join messages" setting on front-end to hide them in public channels. * For the admin buttons in ProfileModal, use the AlertModal instead of native browser prompts.
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:]...)
|
|
}
|
|
}
|
|
}
|
|
}
|