package cache import ( "encoding/json" "fmt" "log" "sync" "time" "MobileMkch/models" ) type Cache struct { mu sync.RWMutex items map[string]cacheItem } type cacheItem struct { Data interface{} Timestamp time.Time TTL time.Duration } var ( instance *Cache once sync.Once ) func GetCache() *Cache { once.Do(func() { instance = &Cache{ items: make(map[string]cacheItem), } go instance.cleanup() }) return instance } func (c *Cache) Set(key string, data interface{}, ttl time.Duration) { c.mu.Lock() defer c.mu.Unlock() c.items[key] = cacheItem{ Data: data, Timestamp: time.Now(), TTL: ttl, } log.Printf("Кэшировано: %s (TTL: %v)", key, ttl) } func (c *Cache) Get(key string) (interface{}, bool) { c.mu.RLock() defer c.mu.RUnlock() item, exists := c.items[key] if !exists { return nil, false } if time.Since(item.Timestamp) > item.TTL { log.Printf("Кэш устарел: %s", key) return nil, false } log.Printf("Кэш найден: %s", key) return item.Data, true } func (c *Cache) Delete(key string) { c.mu.Lock() defer c.mu.Unlock() delete(c.items, key) log.Printf("Кэш удален: %s", key) } func (c *Cache) Clear() { c.mu.Lock() defer c.mu.Unlock() c.items = make(map[string]cacheItem) log.Printf("Кэш очищен") } func (c *Cache) cleanup() { ticker := time.NewTicker(5 * time.Minute) defer ticker.Stop() for range ticker.C { c.mu.Lock() now := time.Now() for key, item := range c.items { if now.Sub(item.Timestamp) > item.TTL { delete(c.items, key) log.Printf("Автоочистка кэша: %s", key) } } c.mu.Unlock() } } func (c *Cache) SetBoards(boards []models.Board) { data, _ := json.Marshal(boards) c.Set("boards", data, 10*time.Minute) } func (c *Cache) GetBoards() ([]models.Board, bool) { data, exists := c.Get("boards") if !exists { return nil, false } var boards []models.Board if err := json.Unmarshal(data.([]byte), &boards); err != nil { log.Printf("Ошибка десериализации досок: %v", err) return nil, false } return boards, true } func (c *Cache) SetThreads(boardCode string, threads []models.Thread) { data, _ := json.Marshal(threads) c.Set("threads_"+boardCode, data, 5*time.Minute) } func (c *Cache) GetThreads(boardCode string) ([]models.Thread, bool) { data, exists := c.Get("threads_" + boardCode) if !exists { return nil, false } var threads []models.Thread if err := json.Unmarshal(data.([]byte), &threads); err != nil { log.Printf("Ошибка десериализации тредов: %v", err) return nil, false } return threads, true } func (c *Cache) SetThreadsPage(boardCode string, page int, threads []models.Thread) { data, _ := json.Marshal(threads) key := fmt.Sprintf("threads_%s_page_%d", boardCode, page) c.Set(key, data, 3*time.Minute) } func (c *Cache) GetThreadsPage(boardCode string, page int) ([]models.Thread, bool) { key := fmt.Sprintf("threads_%s_page_%d", boardCode, page) data, exists := c.Get(key) if !exists { return nil, false } var threads []models.Thread if err := json.Unmarshal(data.([]byte), &threads); err != nil { log.Printf("Ошибка десериализации тредов страницы: %v", err) return nil, false } return threads, true } func (c *Cache) SetThreadDetail(threadID int, thread *models.ThreadDetail) { data, _ := json.Marshal(thread) c.Set("thread_"+string(rune(threadID)), data, 3*time.Minute) } func (c *Cache) GetThreadDetail(threadID int) (*models.ThreadDetail, bool) { data, exists := c.Get("thread_" + string(rune(threadID))) if !exists { return nil, false } var thread models.ThreadDetail if err := json.Unmarshal(data.([]byte), &thread); err != nil { log.Printf("Ошибка десериализации треда: %v", err) return nil, false } return &thread, true } func (c *Cache) SetComments(threadID int, comments []models.Comment) { data, _ := json.Marshal(comments) c.Set("comments_"+string(rune(threadID)), data, 3*time.Minute) } func (c *Cache) GetComments(threadID int) ([]models.Comment, bool) { data, exists := c.Get("comments_" + string(rune(threadID))) if !exists { return nil, false } var comments []models.Comment if err := json.Unmarshal(data.([]byte), &comments); err != nil { log.Printf("Ошибка десериализации комментариев: %v", err) return nil, false } return comments, true }