feat: 初始化 Wails + React + Go 桌面应用模板

- Wails v2.16.0 + React 19 + TypeScript + Vite 7
- 插件系统(build tag 控制编译,plugin.json 运行时配置)
- 支付插件(授权、账号、订单、退款、账单)
- 高并发基础设施(任务池、批量处理器、限流器、环形缓冲、管道)
- Windows 系统托盘(Win32 API)
- CodeGraph 索引 + .memory 记忆包
- 默认图标 assets/icon.png
This commit is contained in:
2026-09-17 19:31:17 +08:00
commit 1ea8c9da9c
57 changed files with 6305 additions and 0 deletions

119
internal/cache/cache.go vendored Normal file
View File

@@ -0,0 +1,119 @@
package cache
import (
"sync"
"time"
)
// Item 缓存项
type Item struct {
Value any
Expiration int64 // Unix 纳秒,0 表示永不过期
}
// IsExpired 是否已过期
func (i *Item) IsExpired() bool {
if i.Expiration == 0 {
return false
}
return time.Now().UnixNano() > i.Expiration
}
// Cache 线程安全的内存缓存,支持 TTL
type Cache struct {
mu sync.RWMutex
items map[string]*Item
ttl time.Duration
cleanup func()
}
// Option 缓存配置选项
type Option func(*Cache)
// WithTTL 设置默认过期时间
func WithTTL(ttl time.Duration) Option {
return func(c *Cache) {
c.ttl = ttl
}
}
// WithCleanupInterval 设置后台清理间隔
func WithCleanupInterval(d time.Duration) Option {
return func(c *Cache) {
go c.cleanupLoop(d)
}
}
// NewCache 创建缓存实例
func NewCache(opts ...Option) *Cache {
c := &Cache{
items: make(map[string]*Item),
ttl: 5 * time.Minute,
}
for _, opt := range opts {
opt(c)
}
return c
}
// Set 设置缓存项
func (c *Cache) Set(key string, value any) {
c.SetWithTTL(key, value, c.ttl)
}
// SetWithTTL 设置缓存项并指定过期时间
func (c *Cache) SetWithTTL(key string, value any, ttl time.Duration) {
c.mu.Lock()
defer c.mu.Unlock()
exp := int64(0)
if ttl > 0 {
exp = time.Now().Add(ttl).UnixNano()
}
c.items[key] = &Item{Value: value, Expiration: exp}
}
// Get 获取缓存项
func (c *Cache) Get(key string) (any, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, ok := c.items[key]
if !ok || item.IsExpired() {
return nil, false
}
return item.Value, true
}
// Delete 删除缓存项
func (c *Cache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.items, key)
}
// Len 返回缓存项数量
func (c *Cache) Len() int {
c.mu.RLock()
defer c.mu.RUnlock()
return len(c.items)
}
// Clear 清空缓存
func (c *Cache) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
c.items = make(map[string]*Item)
}
func (c *Cache) cleanupLoop(interval time.Duration) {
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
c.mu.Lock()
for k, v := range c.items {
if v.IsExpired() {
delete(c.items, k)
}
}
c.mu.Unlock()
}
}