package cache import ( "sync" "time" "github.com/yaoapp/yao/agent/robot/types" ) // RefreshConfig holds refresh configuration type RefreshConfig struct { Interval time.Duration // full refresh interval (default: 1 hour) } // DefaultRefreshConfig returns default refresh configuration func DefaultRefreshConfig() *RefreshConfig { return &RefreshConfig{ Interval: time.Hour, } } // refreshState holds the refresh goroutine state type refreshState struct { ticker *time.Ticker done chan struct{} mu sync.Mutex } var refresher = &refreshState{} // Refresh refreshes a single robot's config from database func (c *Cache) Refresh(ctx *types.Context, memberID string) error { robot, err := c.LoadByID(ctx, memberID) if err != nil { // If robot not found, remove from cache if err == types.ErrRobotNotFound { c.Remove(memberID) return nil } return err } // Update cache c.Add(robot) return nil } // StartAutoRefresh starts periodic full refresh func (c *Cache) StartAutoRefresh(ctx *types.Context, config *RefreshConfig) { if config == nil { config = DefaultRefreshConfig() } refresher.mu.Lock() defer refresher.mu.Unlock() // Stop existing refresher if any if refresher.done != nil { close(refresher.done) } refresher.ticker = time.NewTicker(config.Interval) refresher.done = make(chan struct{}) go func() { for { select { case <-refresher.done: refresher.ticker.Stop() return case <-refresher.ticker.C: // Perform full refresh _ = c.Load(ctx) } } }() } // StopAutoRefresh stops the periodic refresh func (c *Cache) StopAutoRefresh() { refresher.mu.Lock() defer refresher.mu.Unlock() if refresher.done != nil { close(refresher.done) refresher.done = nil } } // RefreshAll reloads all robots from database func (c *Cache) RefreshAll(ctx *types.Context) error { return c.Load(ctx) } // Count returns the number of cached robots func (c *Cache) Count() int { c.mu.RLock() defer c.mu.RUnlock() return len(c.robots) } // ListAll returns all cached robots (across all teams) func (c *Cache) ListAll() []*types.Robot { c.mu.RLock() defer c.mu.RUnlock() robots := make([]*types.Robot, 0, len(c.robots)) for _, robot := range c.robots { robots = append(robots, robot) } return robots } // ListAutonomous returns all cached robots with AutonomousMode=true. func (c *Cache) ListAutonomous() []*types.Robot { c.mu.RLock() defer c.mu.RUnlock() robots := make([]*types.Robot, 0, len(c.robots)/2) for _, r := range c.robots { if r.AutonomousMode { robots = append(robots, r) } } return robots } // GetByStatus returns robots with the specified status func (c *Cache) GetByStatus(status types.RobotStatus) []*types.Robot { c.mu.RLock() defer c.mu.RUnlock() var robots []*types.Robot for _, robot := range c.robots { if robot.Status == status { robots = append(robots, robot) } } return robots } // GetIdle returns all idle robots ready to execute func (c *Cache) GetIdle() []*types.Robot { return c.GetByStatus(types.RobotIdle) } // GetWorking returns all currently working robots func (c *Cache) GetWorking() []*types.Robot { return c.GetByStatus(types.RobotWorking) }