mirror of https://github.com/Wox-launcher/Wox
154 lines
4.5 KiB
Go
154 lines
4.5 KiB
Go
package setting
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
"wox/common"
|
|
"wox/database"
|
|
"wox/util"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// MRUItem represents a Most Recently Used item
|
|
type MRUItem struct {
|
|
PluginID string `json:"pluginId"`
|
|
Title string `json:"title"`
|
|
SubTitle string `json:"subTitle"`
|
|
Icon common.WoxImage `json:"icon"`
|
|
ContextData string `json:"contextData"`
|
|
LastUsed int64 `json:"lastUsed"`
|
|
UseCount int `json:"useCount"`
|
|
}
|
|
|
|
// MRUManager manages Most Recently Used items
|
|
type MRUManager struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewMRUManager creates a new MRU manager
|
|
func NewMRUManager(db *gorm.DB) *MRUManager {
|
|
return &MRUManager{db: db}
|
|
}
|
|
|
|
// AddMRUItem adds or updates an MRU item
|
|
func (m *MRUManager) AddMRUItem(ctx context.Context, item MRUItem) error {
|
|
hash := NewResultHash(item.PluginID, item.Title, item.SubTitle)
|
|
|
|
// Serialize icon to JSON
|
|
iconData, err := json.Marshal(item.Icon)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to serialize icon: %w", err)
|
|
}
|
|
|
|
now := time.Now()
|
|
timestamp := util.GetSystemTimestamp()
|
|
|
|
// Check if record exists
|
|
var existingRecord database.MRURecord
|
|
err = m.db.Where("hash = ?", string(hash)).First(&existingRecord).Error
|
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
// Create new record
|
|
record := database.MRURecord{
|
|
Hash: string(hash),
|
|
PluginID: item.PluginID,
|
|
Title: item.Title,
|
|
SubTitle: item.SubTitle,
|
|
Icon: string(iconData),
|
|
ContextData: item.ContextData,
|
|
LastUsed: timestamp,
|
|
UseCount: 1,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
return m.db.Create(&record).Error
|
|
} else if err != nil {
|
|
return fmt.Errorf("failed to query MRU record: %w", err)
|
|
} else {
|
|
// Update existing record
|
|
updates := map[string]interface{}{
|
|
"last_used": timestamp,
|
|
"use_count": existingRecord.UseCount + 1,
|
|
"context_data": item.ContextData, // Update context data in case it changed
|
|
"icon": string(iconData), // Update icon in case it changed
|
|
"updated_at": now,
|
|
}
|
|
return m.db.Model(&existingRecord).Updates(updates).Error
|
|
}
|
|
}
|
|
|
|
// GetMRUItems retrieves MRU items sorted by usage
|
|
func (m *MRUManager) GetMRUItems(ctx context.Context, limit int) ([]MRUItem, error) {
|
|
var records []database.MRURecord
|
|
|
|
// Order by last_used DESC, then by use_count DESC for items with same last_used time
|
|
err := m.db.Order("last_used DESC, use_count DESC").Limit(limit).Find(&records).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to query MRU records: %w", err)
|
|
}
|
|
|
|
items := make([]MRUItem, 0, len(records))
|
|
for _, record := range records {
|
|
// Deserialize icon
|
|
var icon common.WoxImage
|
|
if err := json.Unmarshal([]byte(record.Icon), &icon); err != nil {
|
|
util.GetLogger().Warn(ctx, fmt.Sprintf("failed to deserialize icon for MRU item %s: %s", record.Hash, err.Error()))
|
|
icon = common.WoxImage{} // Use empty icon as fallback
|
|
}
|
|
|
|
items = append(items, MRUItem{
|
|
PluginID: record.PluginID,
|
|
Title: record.Title,
|
|
SubTitle: record.SubTitle,
|
|
Icon: icon,
|
|
ContextData: record.ContextData,
|
|
LastUsed: record.LastUsed,
|
|
UseCount: record.UseCount,
|
|
})
|
|
}
|
|
|
|
return items, nil
|
|
}
|
|
|
|
// RemoveMRUItem removes an MRU item by hash
|
|
func (m *MRUManager) RemoveMRUItem(ctx context.Context, pluginID, title, subTitle string) error {
|
|
hash := NewResultHash(pluginID, title, subTitle)
|
|
result := m.db.Where("hash = ?", string(hash)).Delete(&database.MRURecord{})
|
|
if result.Error != nil {
|
|
return fmt.Errorf("failed to remove MRU item: %w", result.Error)
|
|
}
|
|
|
|
util.GetLogger().Debug(ctx, fmt.Sprintf("removed MRU item: %s", hash))
|
|
return nil
|
|
}
|
|
|
|
// CleanupOldMRUItems removes old MRU items to keep the database size manageable
|
|
func (m *MRUManager) CleanupOldMRUItems(ctx context.Context, keepCount int) error {
|
|
// Keep only the most recent keepCount items
|
|
subQuery := m.db.Model(&database.MRURecord{}).
|
|
Select("hash").
|
|
Order("last_used DESC, use_count DESC").
|
|
Limit(keepCount)
|
|
|
|
result := m.db.Where("hash NOT IN (?)", subQuery).Delete(&database.MRURecord{})
|
|
if result.Error != nil {
|
|
return fmt.Errorf("failed to cleanup old MRU items: %w", result.Error)
|
|
}
|
|
|
|
if result.RowsAffected > 0 {
|
|
util.GetLogger().Info(ctx, fmt.Sprintf("cleaned up %d old MRU items", result.RowsAffected))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetMRUCount returns the total number of MRU items
|
|
func (m *MRUManager) GetMRUCount(ctx context.Context) (int64, error) {
|
|
var count int64
|
|
err := m.db.Model(&database.MRURecord{}).Count(&count).Error
|
|
return count, err
|
|
}
|