Files
mengyaping/mengyaping-backend/storage/storage.go
2026-02-16 00:13:37 +08:00

286 lines
5.8 KiB
Go

package storage
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"
"mengyaping-backend/config"
"mengyaping-backend/models"
)
// Storage 数据存储
type Storage struct {
dataPath string
mu sync.RWMutex
websites []models.Website
records map[string][]models.MonitorRecord // key: websiteID_urlID
groups []models.Group
}
var (
store *Storage
once sync.Once
)
// GetStorage 获取存储单例
func GetStorage() *Storage {
once.Do(func() {
cfg := config.GetConfig()
store = &Storage{
dataPath: cfg.DataPath,
websites: []models.Website{},
records: make(map[string][]models.MonitorRecord),
groups: models.DefaultGroups,
}
store.ensureDataDir()
store.load()
})
return store
}
// ensureDataDir 确保数据目录存在
func (s *Storage) ensureDataDir() {
os.MkdirAll(s.dataPath, 0755)
}
// load 加载数据
func (s *Storage) load() {
s.loadWebsites()
s.loadRecords()
s.loadGroups()
}
// loadWebsites 加载网站数据
func (s *Storage) loadWebsites() {
filePath := filepath.Join(s.dataPath, "websites.json")
data, err := os.ReadFile(filePath)
if err != nil {
return
}
json.Unmarshal(data, &s.websites)
}
// loadRecords 加载监控记录
func (s *Storage) loadRecords() {
filePath := filepath.Join(s.dataPath, "records.json")
data, err := os.ReadFile(filePath)
if err != nil {
return
}
json.Unmarshal(data, &s.records)
// 清理过期记录
s.cleanOldRecords()
}
// loadGroups 加载分组
func (s *Storage) loadGroups() {
filePath := filepath.Join(s.dataPath, "groups.json")
data, err := os.ReadFile(filePath)
if err != nil {
// 使用默认分组
s.groups = models.DefaultGroups
s.saveGroups()
return
}
json.Unmarshal(data, &s.groups)
}
// saveWebsites 保存网站数据
func (s *Storage) saveWebsites() error {
filePath := filepath.Join(s.dataPath, "websites.json")
data, err := json.MarshalIndent(s.websites, "", " ")
if err != nil {
return err
}
return os.WriteFile(filePath, data, 0644)
}
// saveRecords 保存监控记录
func (s *Storage) saveRecords() error {
filePath := filepath.Join(s.dataPath, "records.json")
data, err := json.MarshalIndent(s.records, "", " ")
if err != nil {
return err
}
return os.WriteFile(filePath, data, 0644)
}
// saveGroups 保存分组
func (s *Storage) saveGroups() error {
filePath := filepath.Join(s.dataPath, "groups.json")
data, err := json.MarshalIndent(s.groups, "", " ")
if err != nil {
return err
}
return os.WriteFile(filePath, data, 0644)
}
// cleanOldRecords 清理过期记录
func (s *Storage) cleanOldRecords() {
cfg := config.GetConfig()
cutoff := time.Now().AddDate(0, 0, -cfg.Monitor.HistoryDays)
for key, records := range s.records {
var newRecords []models.MonitorRecord
for _, r := range records {
if r.CheckedAt.After(cutoff) {
newRecords = append(newRecords, r)
}
}
s.records[key] = newRecords
}
}
// GetWebsites 获取所有网站
func (s *Storage) GetWebsites() []models.Website {
s.mu.RLock()
defer s.mu.RUnlock()
result := make([]models.Website, len(s.websites))
copy(result, s.websites)
return result
}
// GetWebsite 获取单个网站
func (s *Storage) GetWebsite(id string) *models.Website {
s.mu.RLock()
defer s.mu.RUnlock()
for _, w := range s.websites {
if w.ID == id {
website := w
return &website
}
}
return nil
}
// AddWebsite 添加网站
func (s *Storage) AddWebsite(website models.Website) error {
s.mu.Lock()
defer s.mu.Unlock()
s.websites = append(s.websites, website)
return s.saveWebsites()
}
// UpdateWebsite 更新网站
func (s *Storage) UpdateWebsite(website models.Website) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, w := range s.websites {
if w.ID == website.ID {
s.websites[i] = website
return s.saveWebsites()
}
}
return nil
}
// DeleteWebsite 删除网站
func (s *Storage) DeleteWebsite(id string) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, w := range s.websites {
if w.ID == id {
s.websites = append(s.websites[:i], s.websites[i+1:]...)
// 删除相关记录
for key := range s.records {
if len(key) > len(id) && key[:len(id)] == id {
delete(s.records, key)
}
}
s.saveRecords()
return s.saveWebsites()
}
}
return nil
}
// AddRecord 添加监控记录
func (s *Storage) AddRecord(record models.MonitorRecord) error {
s.mu.Lock()
defer s.mu.Unlock()
key := record.WebsiteID + "_" + record.URLID
s.records[key] = append(s.records[key], record)
// 每100条记录保存一次
if len(s.records[key])%100 == 0 {
return s.saveRecords()
}
return nil
}
// GetRecords 获取监控记录
func (s *Storage) GetRecords(websiteID, urlID string, since time.Time) []models.MonitorRecord {
s.mu.RLock()
defer s.mu.RUnlock()
key := websiteID + "_" + urlID
records := s.records[key]
var result []models.MonitorRecord
for _, r := range records {
if r.CheckedAt.After(since) {
result = append(result, r)
}
}
return result
}
// GetLatestRecord 获取最新记录
func (s *Storage) GetLatestRecord(websiteID, urlID string) *models.MonitorRecord {
s.mu.RLock()
defer s.mu.RUnlock()
key := websiteID + "_" + urlID
records := s.records[key]
if len(records) == 0 {
return nil
}
latest := records[len(records)-1]
return &latest
}
// GetGroups 获取所有分组
func (s *Storage) GetGroups() []models.Group {
s.mu.RLock()
defer s.mu.RUnlock()
result := make([]models.Group, len(s.groups))
copy(result, s.groups)
return result
}
// AddGroup 添加分组
func (s *Storage) AddGroup(group models.Group) error {
s.mu.Lock()
defer s.mu.Unlock()
s.groups = append(s.groups, group)
return s.saveGroups()
}
// SaveAll 保存所有数据
func (s *Storage) SaveAll() error {
s.mu.Lock()
defer s.mu.Unlock()
if err := s.saveWebsites(); err != nil {
return err
}
if err := s.saveRecords(); err != nil {
return err
}
return s.saveGroups()
}