108 lines
2.2 KiB
Go
108 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"cursor-api-proxy/internal/config"
|
|
"cursor-api-proxy/internal/httputil"
|
|
"cursor-api-proxy/internal/models"
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
const modelCacheTTLMs = 5 * 60 * 1000
|
|
|
|
type ModelCache struct {
|
|
At int64
|
|
Models []models.CursorCliModel
|
|
}
|
|
|
|
type ModelCacheRef struct {
|
|
mu sync.Mutex
|
|
cache *ModelCache
|
|
inflight bool
|
|
waiters []chan struct{}
|
|
}
|
|
|
|
func (ref *ModelCacheRef) HandleModels(w http.ResponseWriter, r *http.Request, cfg config.BridgeConfig) {
|
|
now := time.Now().UnixMilli()
|
|
|
|
ref.mu.Lock()
|
|
if ref.cache != nil && now-ref.cache.At <= modelCacheTTLMs {
|
|
cache := ref.cache
|
|
ref.mu.Unlock()
|
|
writeModels(w, cache.Models)
|
|
return
|
|
}
|
|
|
|
if ref.inflight {
|
|
// Wait for the in-flight fetch
|
|
ch := make(chan struct{}, 1)
|
|
ref.waiters = append(ref.waiters, ch)
|
|
ref.mu.Unlock()
|
|
<-ch
|
|
ref.mu.Lock()
|
|
cache := ref.cache
|
|
ref.mu.Unlock()
|
|
writeModels(w, cache.Models)
|
|
return
|
|
}
|
|
|
|
ref.inflight = true
|
|
ref.mu.Unlock()
|
|
|
|
fetched, err := models.ListCursorCliModels(cfg.AgentBin, 60000)
|
|
|
|
ref.mu.Lock()
|
|
ref.inflight = false
|
|
if err == nil {
|
|
ref.cache = &ModelCache{At: time.Now().UnixMilli(), Models: fetched}
|
|
}
|
|
waiters := ref.waiters
|
|
ref.waiters = nil
|
|
ref.mu.Unlock()
|
|
|
|
for _, ch := range waiters {
|
|
ch <- struct{}{}
|
|
}
|
|
|
|
if err != nil {
|
|
httputil.WriteJSON(w, 500, map[string]interface{}{
|
|
"error": map[string]string{"message": err.Error(), "code": "models_fetch_error"},
|
|
}, nil)
|
|
return
|
|
}
|
|
|
|
writeModels(w, fetched)
|
|
}
|
|
|
|
func writeModels(w http.ResponseWriter, mods []models.CursorCliModel) {
|
|
cursorModels := make([]map[string]interface{}, len(mods))
|
|
for i, m := range mods {
|
|
cursorModels[i] = map[string]interface{}{
|
|
"id": m.ID,
|
|
"object": "model",
|
|
"owned_by": "cursor",
|
|
"name": m.Name,
|
|
}
|
|
}
|
|
|
|
ids := make([]string, len(mods))
|
|
for i, m := range mods {
|
|
ids[i] = m.ID
|
|
}
|
|
aliases := models.GetAnthropicModelAliases(ids)
|
|
for _, a := range aliases {
|
|
cursorModels = append(cursorModels, map[string]interface{}{
|
|
"id": a.ID,
|
|
"object": "model",
|
|
"owned_by": "cursor",
|
|
"name": a.Name,
|
|
})
|
|
}
|
|
|
|
httputil.WriteJSON(w, 200, map[string]interface{}{
|
|
"object": "list",
|
|
"data": cursorModels,
|
|
}, nil)
|
|
}
|