| package instance |
|
|
| import ( |
| "fmt" |
| "log/slog" |
| "sync" |
|
|
| "github.com/pinchtab/pinchtab/internal/bridge" |
| ) |
|
|
| |
| |
| |
| type Locator struct { |
| mu sync.RWMutex |
| cache map[string]string |
|
|
| repo *Repository |
| fetcher TabFetcher |
| } |
|
|
| |
| func NewLocator(repo *Repository, fetcher TabFetcher) *Locator { |
| return &Locator{ |
| cache: make(map[string]string), |
| repo: repo, |
| fetcher: fetcher, |
| } |
| } |
|
|
| |
| |
| func (l *Locator) FindInstanceByTabID(tabID string) (*bridge.Instance, error) { |
| |
| l.mu.RLock() |
| instID, ok := l.cache[tabID] |
| l.mu.RUnlock() |
|
|
| if ok { |
| inst, found := l.repo.Get(instID) |
| if found && inst.Status == "running" { |
| return inst, nil |
| } |
| |
| l.Invalidate(tabID) |
| } |
|
|
| |
| running := l.repo.Running() |
| for _, inst := range running { |
| url := inst.URL |
| if url == "" { |
| url = fmt.Sprintf("http://localhost:%s", inst.Port) |
| } |
| tabs, err := l.fetcher.FetchTabs(url) |
| if err != nil { |
| slog.Debug("locator: failed to fetch tabs", "instance", inst.ID, "err", err) |
| continue |
| } |
| for _, tab := range tabs { |
| |
| l.mu.Lock() |
| l.cache[tab.ID] = inst.ID |
| l.mu.Unlock() |
|
|
| if tab.ID == tabID { |
| result := inst |
| return &result, nil |
| } |
| } |
| } |
|
|
| return nil, fmt.Errorf("tab %q not found in any running instance", tabID) |
| } |
|
|
| |
| func (l *Locator) Register(tabID, instanceID string) { |
| l.mu.Lock() |
| l.cache[tabID] = instanceID |
| l.mu.Unlock() |
| } |
|
|
| |
| func (l *Locator) Invalidate(tabID string) { |
| l.mu.Lock() |
| delete(l.cache, tabID) |
| l.mu.Unlock() |
| } |
|
|
| |
| func (l *Locator) InvalidateInstance(instanceID string) { |
| l.mu.Lock() |
| for tabID, instID := range l.cache { |
| if instID == instanceID { |
| delete(l.cache, tabID) |
| } |
| } |
| l.mu.Unlock() |
| } |
|
|
| |
| func (l *Locator) RefreshAll() { |
| l.mu.Lock() |
| l.cache = make(map[string]string) |
| l.mu.Unlock() |
|
|
| running := l.repo.Running() |
| for _, inst := range running { |
| url := inst.URL |
| if url == "" { |
| url = fmt.Sprintf("http://localhost:%s", inst.Port) |
| } |
| tabs, err := l.fetcher.FetchTabs(url) |
| if err != nil { |
| slog.Debug("locator: refresh failed", "instance", inst.ID, "err", err) |
| continue |
| } |
| l.mu.Lock() |
| for _, tab := range tabs { |
| l.cache[tab.ID] = inst.ID |
| } |
| l.mu.Unlock() |
| } |
| } |
|
|
| |
| func (l *Locator) CacheSize() int { |
| l.mu.RLock() |
| defer l.mu.RUnlock() |
| return len(l.cache) |
| } |
|
|