Files
dygou_go/internal/config/instance.go
T

98 lines
2.4 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
"sync"
"douyu_go/internal/constants"
"douyu_go/internal/types"
)
const maxInstanceSlots = 256
// InstanceLease 代表当前进程持有的实例槽位;必须在程序退出时释放。
type InstanceLease struct {
paths types.AppPaths
name string
lock instanceLock
releaseOnce sync.Once
}
// AcquireInstancePaths 按顺序占用空闲实例。第一个进程使用默认实例,
// 后续进程分别使用实例 2、实例 3,以隔离账号、配置与运行数据。
func AcquireInstancePaths() (*InstanceLease, error) {
baseDir := defaultDataDir()
instanceRoot := filepath.Join(baseDir, "instances")
lockDir := filepath.Join(instanceRoot, ".locks")
if err := osMkdirAll(lockDir); err != nil {
return nil, fmt.Errorf("创建实例锁目录失败: %w", err)
}
for slot := 1; slot <= maxInstanceSlots; slot++ {
lock, acquired, err := tryAcquireInstanceLock(filepath.Join(lockDir, instanceLockFileName(slot)))
if err != nil {
return nil, fmt.Errorf("锁定%s失败: %w", instanceName(slot), err)
}
if !acquired {
continue
}
dataDir := baseDir
if slot > 1 {
dataDir = filepath.Join(instanceRoot, fmt.Sprintf("instance-%d", slot))
}
paths := appPathsForDataDir(dataDir, slot == 1)
if slot > 1 && isWailsDev() && os.Getenv("DOUYU_LOG_DIR") == "" {
paths.LogDir = resolvePath(filepath.Join(constants.DefaultLogDir, "instances", fmt.Sprintf("instance-%d", slot)))
}
return &InstanceLease{
paths: paths,
name: instanceName(slot),
lock: lock,
}, nil
}
return nil, fmt.Errorf("最多支持同时运行 %d 个实例", maxInstanceSlots)
}
// Paths 返回当前实例独立的数据路径。
func (l *InstanceLease) Paths() types.AppPaths {
if l == nil {
return types.AppPaths{}
}
return l.paths
}
// Name 返回面向用户的实例名称。
func (l *InstanceLease) Name() string {
if l == nil {
return ""
}
return l.name
}
// Release 释放实例锁,允许新启动的程序复用该实例。
func (l *InstanceLease) Release() {
if l == nil || l.lock == nil {
return
}
l.releaseOnce.Do(func() {
_ = l.lock.Close()
})
}
func instanceName(slot int) string {
if slot <= 1 {
return "默认实例"
}
return fmt.Sprintf("实例 %d", slot)
}
func instanceLockFileName(slot int) string {
if slot <= 1 {
return "default.lock"
}
return fmt.Sprintf("instance-%d.lock", slot)
}