2021-11-03 01:09:49 +00:00
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
2021-12-10 16:31:42 +00:00
|
|
|
"sort"
|
2021-11-03 01:09:49 +00:00
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
type memCache struct {
|
2021-12-10 16:31:42 +00:00
|
|
|
messages map[string][]*message
|
|
|
|
scheduled map[string]*message // Message ID -> message
|
|
|
|
nop bool
|
|
|
|
mu sync.Mutex
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ cache = (*memCache)(nil)
|
|
|
|
|
2021-12-09 15:23:17 +00:00
|
|
|
// newMemCache creates an in-memory cache
|
2021-11-03 01:09:49 +00:00
|
|
|
func newMemCache() *memCache {
|
|
|
|
return &memCache{
|
2021-12-10 16:31:42 +00:00
|
|
|
messages: make(map[string][]*message),
|
|
|
|
scheduled: make(map[string]*message),
|
|
|
|
nop: false,
|
2021-12-09 15:23:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// newNopCache creates an in-memory cache that discards all messages;
|
|
|
|
// it is always empty and can be used if caching is entirely disabled
|
|
|
|
func newNopCache() *memCache {
|
|
|
|
return &memCache{
|
2021-12-10 16:31:42 +00:00
|
|
|
messages: make(map[string][]*message),
|
|
|
|
scheduled: make(map[string]*message),
|
|
|
|
nop: true,
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) AddMessage(m *message) error {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
if c.nop {
|
2021-12-09 15:23:17 +00:00
|
|
|
return nil
|
|
|
|
}
|
2021-12-07 16:45:15 +00:00
|
|
|
if m.Event != messageEvent {
|
|
|
|
return errUnexpectedMessageType
|
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
if _, ok := c.messages[m.Topic]; !ok {
|
|
|
|
c.messages[m.Topic] = make([]*message, 0)
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
delayed := m.Time > time.Now().Unix()
|
|
|
|
if delayed {
|
|
|
|
c.scheduled[m.ID] = m
|
|
|
|
}
|
|
|
|
c.messages[m.Topic] = append(c.messages[m.Topic], m)
|
2021-11-03 01:09:49 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) Messages(topic string, since sinceTime, scheduled bool) ([]*message, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
if _, ok := c.messages[topic]; !ok || since.IsNone() {
|
2021-11-03 01:09:49 +00:00
|
|
|
return make([]*message, 0), nil
|
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
messages := make([]*message, 0)
|
|
|
|
for _, m := range c.messages[topic] {
|
|
|
|
_, messageScheduled := c.scheduled[m.ID]
|
|
|
|
include := m.Time >= since.Time().Unix() && (!messageScheduled || scheduled)
|
|
|
|
if include {
|
|
|
|
messages = append(messages, m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Slice(messages, func(i, j int) bool {
|
|
|
|
return messages[i].Time < messages[j].Time
|
|
|
|
})
|
|
|
|
return messages, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *memCache) MessagesDue() ([]*message, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
messages := make([]*message, 0)
|
|
|
|
for _, m := range c.scheduled {
|
|
|
|
due := time.Now().Unix() >= m.Time
|
|
|
|
if due {
|
2021-11-03 01:09:49 +00:00
|
|
|
messages = append(messages, m)
|
|
|
|
}
|
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
sort.Slice(messages, func(i, j int) bool {
|
|
|
|
return messages[i].Time < messages[j].Time
|
|
|
|
})
|
2021-11-03 01:09:49 +00:00
|
|
|
return messages, nil
|
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) MarkPublished(m *message) error {
|
|
|
|
c.mu.Lock()
|
|
|
|
delete(c.scheduled, m.ID)
|
|
|
|
c.mu.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *memCache) MessageCount(topic string) (int, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
if _, ok := c.messages[topic]; !ok {
|
2021-11-03 01:09:49 +00:00
|
|
|
return 0, nil
|
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
return len(c.messages[topic]), nil
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) Topics() (map[string]*topic, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
2021-12-09 03:57:31 +00:00
|
|
|
topics := make(map[string]*topic)
|
2021-12-10 16:31:42 +00:00
|
|
|
for topic := range c.messages {
|
2021-12-09 03:57:31 +00:00
|
|
|
topics[topic] = newTopic(topic)
|
|
|
|
}
|
|
|
|
return topics, nil
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) Prune(olderThan time.Time) error {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
for topic := range c.messages {
|
|
|
|
c.pruneTopic(topic, olderThan)
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-01-07 13:49:28 +00:00
|
|
|
func (c *memCache) AttachmentsSize(owner string) (int64, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
var size int64
|
|
|
|
for topic := range c.messages {
|
|
|
|
for _, m := range c.messages[topic] {
|
2022-01-13 20:17:30 +00:00
|
|
|
counted := m.Attachment != nil && m.Attachment.Owner == owner && m.Attachment.Expires > time.Now().Unix()
|
|
|
|
if counted {
|
2022-01-07 13:49:28 +00:00
|
|
|
size += m.Attachment.Size
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return size, nil
|
|
|
|
}
|
|
|
|
|
2022-01-07 14:15:33 +00:00
|
|
|
func (c *memCache) AttachmentsExpired() ([]string, error) {
|
|
|
|
c.mu.Lock()
|
|
|
|
defer c.mu.Unlock()
|
|
|
|
ids := make([]string, 0)
|
|
|
|
for topic := range c.messages {
|
|
|
|
for _, m := range c.messages[topic] {
|
|
|
|
if m.Attachment != nil && m.Attachment.Expires > 0 && m.Attachment.Expires < time.Now().Unix() {
|
|
|
|
ids = append(ids, m.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ids, nil
|
|
|
|
}
|
|
|
|
|
2021-12-10 16:31:42 +00:00
|
|
|
func (c *memCache) pruneTopic(topic string, olderThan time.Time) {
|
2021-12-09 03:57:31 +00:00
|
|
|
messages := make([]*message, 0)
|
2021-12-10 16:31:42 +00:00
|
|
|
for _, m := range c.messages[topic] {
|
2021-12-09 03:57:31 +00:00
|
|
|
if m.Time >= olderThan.Unix() {
|
|
|
|
messages = append(messages, m)
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|
|
|
|
}
|
2021-12-10 16:31:42 +00:00
|
|
|
c.messages[topic] = messages
|
2021-11-03 01:09:49 +00:00
|
|
|
}
|