feat(server): 添加缓存系统和视频流处理功能 - 初始化512MB内存缓存系统,TTL设置为60分钟 - 添加支持Range请求的视频流处理器,优化大文件加载性能 - 使用gin.Recovery()增强服务稳定性 - 将静态文件服务替换为专门的视频流处理器 fix(config): 更新服务器主机地址 - 将Host地址从192.168.124.2更新为192.168.124.8 ```
158 lines
3.2 KiB
Go
158 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// CacheItem 缓存项
|
|
type CacheItem struct {
|
|
data []byte
|
|
timestamp time.Time
|
|
size int
|
|
}
|
|
|
|
// ThumbnailCache 缩略图缓存
|
|
type ThumbnailCache struct {
|
|
items map[string]*CacheItem
|
|
mu sync.RWMutex
|
|
maxSize int64 // 最大缓存大小(字节)
|
|
usedSize int64 // 已使用大小
|
|
ttl time.Duration // 缓存过期时间
|
|
}
|
|
|
|
// NewThumbnailCache 创建新的缩略图缓存
|
|
func NewThumbnailCache(maxSizeMB int, ttlMinutes int) *ThumbnailCache {
|
|
return &ThumbnailCache{
|
|
items: make(map[string]*CacheItem),
|
|
maxSize: int64(maxSizeMB) * 1024 * 1024,
|
|
ttl: time.Duration(ttlMinutes) * time.Minute,
|
|
}
|
|
}
|
|
|
|
// Get 获取缓存项
|
|
func (c *ThumbnailCache) Get(key string) ([]byte, bool) {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
item, exists := c.items[key]
|
|
if !exists {
|
|
return nil, false
|
|
}
|
|
|
|
// 检查是否过期
|
|
if time.Since(item.timestamp) > c.ttl {
|
|
go c.Remove(key)
|
|
return nil, false
|
|
}
|
|
|
|
return item.data, true
|
|
}
|
|
|
|
// Set 设置缓存项
|
|
func (c *ThumbnailCache) Set(key string, data []byte) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
// 如果已存在,先删除旧的
|
|
if item, exists := c.items[key]; exists {
|
|
c.usedSize -= int64(item.size)
|
|
delete(c.items, key)
|
|
}
|
|
|
|
// 检查是否需要清理空间
|
|
itemSize := len(data)
|
|
if int64(itemSize) > c.maxSize {
|
|
// 单个文件太大,不缓存
|
|
return
|
|
}
|
|
|
|
// 清理过期或最旧的项直到有足够空间
|
|
c.cleanup(int64(itemSize))
|
|
|
|
// 添加新项
|
|
c.items[key] = &CacheItem{
|
|
data: data,
|
|
timestamp: time.Now(),
|
|
size: itemSize,
|
|
}
|
|
c.usedSize += int64(itemSize)
|
|
}
|
|
|
|
// Remove 移除缓存项
|
|
func (c *ThumbnailCache) Remove(key string) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
if item, exists := c.items[key]; exists {
|
|
c.usedSize -= int64(item.size)
|
|
delete(c.items, key)
|
|
}
|
|
}
|
|
|
|
// Clear 清空缓存
|
|
func (c *ThumbnailCache) Clear() {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
|
|
c.items = make(map[string]*CacheItem)
|
|
c.usedSize = 0
|
|
}
|
|
|
|
// cleanup 清理缓存,确保有足够空间
|
|
func (c *ThumbnailCache) cleanup(requiredSpace int64) {
|
|
// 首先清理过期项
|
|
now := time.Now()
|
|
for key, item := range c.items {
|
|
if now.Sub(item.timestamp) > c.ttl {
|
|
c.usedSize -= int64(item.size)
|
|
delete(c.items, key)
|
|
}
|
|
}
|
|
|
|
// 如果还不够,清理最旧的项
|
|
for c.usedSize+requiredSpace > c.maxSize && len(c.items) > 0 {
|
|
var oldestKey string
|
|
var oldestTime time.Time
|
|
|
|
for key, item := range c.items {
|
|
if oldestKey == "" || item.timestamp.Before(oldestTime) {
|
|
oldestKey = key
|
|
oldestTime = item.timestamp
|
|
}
|
|
}
|
|
|
|
if oldestKey != "" {
|
|
item := c.items[oldestKey]
|
|
c.usedSize -= int64(item.size)
|
|
delete(c.items, oldestKey)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Size 获取缓存大小(字节)
|
|
func (c *ThumbnailCache) Size() int64 {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return c.usedSize
|
|
}
|
|
|
|
// Count 获取缓存项数量
|
|
func (c *ThumbnailCache) Count() int {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
return len(c.items)
|
|
}
|
|
|
|
// Stats 获取缓存统计信息
|
|
func (c *ThumbnailCache) Stats() map[string]interface{} {
|
|
c.mu.RLock()
|
|
defer c.mu.RUnlock()
|
|
|
|
return map[string]interface{}{
|
|
"count": len(c.items),
|
|
"usedSize": c.usedSize,
|
|
"maxSize": c.maxSize,
|
|
"usagePercent": float64(c.usedSize) / float64(c.maxSize) * 100,
|
|
}
|
|
} |