feat(core): implement group-based routing and optimize sync

Replace direct provider linkage with group-based routing for Keys and
Providers. This allows for more flexible load balancing and tiering
strategies.

Changes include:
- Remove `ProviderID` from Key model and DTO
- Add `Group` field to Key and Provider models
- Refactor Redis sync to use Hashes for O(1) partial updates
- Update API handlers to perform incremental syncs

BREAKING CHANGE: Key API payload no longer accepts `provider_id`. Redis
configuration storage format has changed from JSON strings to Hashes.
This commit is contained in:
zenfun
2025-12-02 14:41:05 +08:00
parent 57d92de5e6
commit aa57af874c
5 changed files with 154 additions and 93 deletions

View File

@@ -3,6 +3,7 @@ package api
import (
"net/http"
"strconv"
"strings"
"github.com/ez-api/ez-api/internal/dto"
"github.com/ez-api/ez-api/internal/model"
@@ -28,12 +29,17 @@ func (h *Handler) CreateKey(c *gin.Context) {
return
}
group := strings.TrimSpace(req.Group)
if group == "" {
group = "default"
}
key := model.Key{
ProviderID: &req.ProviderID,
KeySecret: req.KeySecret,
Balance: req.Balance,
Status: req.Status,
Weight: req.Weight,
KeySecret: req.KeySecret,
Group: group,
Balance: req.Balance,
Status: req.Status,
Weight: req.Weight,
}
if err := h.db.Create(&key).Error; err != nil {
@@ -42,7 +48,7 @@ func (h *Handler) CreateKey(c *gin.Context) {
}
// Write auth hash and refresh snapshots
if err := h.sync.SyncAll(h.db); err != nil {
if err := h.sync.SyncKey(&key); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync key to Redis", "details": err.Error()})
return
}
@@ -57,11 +63,17 @@ func (h *Handler) CreateProvider(c *gin.Context) {
return
}
group := strings.TrimSpace(req.Group)
if group == "" {
group = "default"
}
provider := model.Provider{
Name: req.Name,
Type: req.Type,
BaseURL: req.BaseURL,
APIKey: req.APIKey,
Group: group,
}
if err := h.db.Create(&provider).Error; err != nil {
@@ -69,7 +81,7 @@ func (h *Handler) CreateProvider(c *gin.Context) {
return
}
if err := h.sync.SyncAll(h.db); err != nil {
if err := h.sync.SyncProvider(&provider); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync provider", "details": err.Error()})
return
}
@@ -100,7 +112,7 @@ func (h *Handler) CreateModel(c *gin.Context) {
return
}
if err := h.sync.SyncAll(h.db); err != nil {
if err := h.sync.SyncModel(&modelReq); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync model", "details": err.Error()})
return
}
@@ -151,7 +163,7 @@ func (h *Handler) UpdateModel(c *gin.Context) {
return
}
if err := h.sync.SyncAll(h.db); err != nil {
if err := h.sync.SyncModel(&existing); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to sync model", "details": err.Error()})
return
}