92 lines
1.5 KiB
Go
92 lines
1.5 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const janitorInterval = 5 * time.Minute
|
|
|
|
type PreviewStore struct {
|
|
mu sync.Mutex
|
|
items map[string]previewItem
|
|
ttl time.Duration
|
|
now func() time.Time
|
|
}
|
|
|
|
type previewItem struct {
|
|
html []byte
|
|
mime string
|
|
filename string
|
|
expires time.Time
|
|
}
|
|
|
|
func NewPreviewStore(ttl time.Duration) *PreviewStore {
|
|
return &PreviewStore{
|
|
items: make(map[string]previewItem),
|
|
ttl: ttl,
|
|
now: time.Now,
|
|
}
|
|
}
|
|
|
|
func (s *PreviewStore) Put(html []byte, mime, filename string) string {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
id := uuid.NewString()
|
|
s.items[id] = previewItem{
|
|
html: append([]byte(nil), html...),
|
|
mime: mime,
|
|
filename: filename,
|
|
expires: s.now().Add(s.ttl),
|
|
}
|
|
|
|
return id
|
|
}
|
|
|
|
func (s *PreviewStore) Take(id string) (previewItem, bool) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
item, ok := s.items[id]
|
|
if !ok {
|
|
return previewItem{}, false
|
|
}
|
|
|
|
delete(s.items, id)
|
|
if s.now().After(item.expires) {
|
|
return previewItem{}, false
|
|
}
|
|
|
|
item.html = append([]byte(nil), item.html...)
|
|
return item, true
|
|
}
|
|
|
|
func (s *PreviewStore) janitor(ctx context.Context) {
|
|
ticker := time.NewTicker(janitorInterval)
|
|
defer ticker.Stop()
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case now := <-ticker.C:
|
|
s.cleanupExpired(now)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *PreviewStore) cleanupExpired(now time.Time) {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
for id, item := range s.items {
|
|
if now.After(item.expires) {
|
|
delete(s.items, id)
|
|
}
|
|
}
|
|
}
|