AI Gateway Go 0.10.0 源码快照 + 旗舰版需求规划报告

M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。
含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ben
2026-08-12 11:45:54 +08:00
commit 5759c1862e
807 changed files with 114727 additions and 0 deletions
+357
View File
@@ -0,0 +1,357 @@
package provider
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
platformid "aigateway.local/core/internal/platform/id"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgconn"
"github.com/jackc/pgx/v5/pgxpool"
)
var (
ErrProviderNotFound = errors.New("provider not found")
ErrProviderExists = errors.New("provider already exists")
ErrMultipleDefaults = errors.New("multiple default providers")
ErrProviderStore = errors.New("provider store unavailable")
ErrProviderUpstream = errors.New("provider upstream unavailable")
)
type Record struct {
ID string
TenantID *string
Code string
Adapter string
BaseURL string
EncryptedCredentials []byte
CredentialKEKVersion int
Capabilities []string
Config json.RawMessage
Enabled bool
Revision int64
}
func (r *Repository) ListModels(ctx context.Context, providerID string) ([]Model, error) {
if r.pool == nil {
return nil, ErrProviderStore
}
rows, err := r.pool.Query(ctx, `
SELECT id::text, provider_id::text, provider_model_id, owned_by, metadata,
enabled, discovered_at, last_seen_at
FROM gateway.provider_models
WHERE provider_id = $1
ORDER BY enabled DESC, provider_model_id`, providerID)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer rows.Close()
models := make([]Model, 0)
for rows.Next() {
var model Model
if err := rows.Scan(
&model.ID, &model.ProviderID, &model.ProviderModelID, &model.OwnedBy,
&model.Metadata, &model.Enabled, &model.DiscoveredAt, &model.LastSeenAt,
); err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
models = append(models, model)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return models, nil
}
func (r *Repository) SyncModels(ctx context.Context, providerID, actorID string, models []DiscoveredModel) (ModelSyncResult, error) {
if r.pool == nil {
return ModelSyncResult{}, ErrProviderStore
}
eventID, err := platformid.NewUUID()
if err != nil {
return ModelSyncResult{}, err
}
transaction, err := r.pool.Begin(ctx)
if err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer func() { _ = transaction.Rollback(ctx) }()
var exists bool
if err := transaction.QueryRow(ctx, `
SELECT EXISTS (
SELECT 1 FROM gateway.providers WHERE id = $1 AND tenant_id IS NULL
)`, providerID).Scan(&exists); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
if !exists {
return ModelSyncResult{}, ErrProviderNotFound
}
if _, err := transaction.Exec(ctx, `
UPDATE gateway.provider_models
SET enabled = false, updated_at = clock_timestamp()
WHERE provider_id = $1 AND enabled = true`, providerID); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
for _, model := range models {
id, err := platformid.NewUUID()
if err != nil {
return ModelSyncResult{}, err
}
if _, err := transaction.Exec(ctx, `
INSERT INTO gateway.provider_models
(id, provider_id, provider_model_id, owned_by, metadata, enabled)
VALUES ($1, $2, $3, $4, $5, true)
ON CONFLICT (provider_id, provider_model_id) DO UPDATE
SET owned_by = EXCLUDED.owned_by,
metadata = EXCLUDED.metadata,
enabled = true,
last_seen_at = clock_timestamp(),
updated_at = clock_timestamp()`,
id, providerID, model.ProviderModelID, model.OwnedBy, model.Metadata,
); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
}
result := ModelSyncResult{Discovered: len(models), SyncedAt: time.Now().UTC()}
if err := transaction.QueryRow(ctx, `
SELECT count(*) FILTER (WHERE enabled), count(*) FILTER (WHERE NOT enabled)
FROM gateway.provider_models
WHERE provider_id = $1`, providerID).Scan(&result.Active, &result.Disabled); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
payload, _ := json.Marshal(map[string]any{
"provider_id": providerID, "discovered": result.Discovered,
"active": result.Active, "disabled": result.Disabled, "actor_id": actorID,
})
if _, err := transaction.Exec(ctx, `
INSERT INTO gateway.outbox_events
(event_id, event_type, event_version, aggregate_type, aggregate_id, payload)
VALUES ($1, 'provider.models_synced', 1, 'provider', $2, $3)`, eventID, providerID, payload); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
if err := transaction.Commit(ctx); err != nil {
return ModelSyncResult{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return result, nil
}
func (r *Repository) RotateCredentials(ctx context.Context, actorID string, rotations []CredentialRotation) error {
if r.pool == nil {
return ErrProviderStore
}
if len(rotations) == 0 {
return nil
}
transaction, err := r.pool.Begin(ctx)
if err != nil {
return fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer func() { _ = transaction.Rollback(ctx) }()
for _, rotation := range rotations {
result, err := transaction.Exec(ctx, `
UPDATE gateway.providers
SET encrypted_credentials = $2,
credential_kek_version = $3,
revision = revision + 1,
updated_at = clock_timestamp()
WHERE id = $1
AND tenant_id IS NULL
AND credential_kek_version = $4`,
rotation.ProviderID, rotation.Ciphertext, rotation.ToVersion, rotation.FromVersion,
)
if err != nil {
return fmt.Errorf("%w: %v", ErrProviderStore, err)
}
if result.RowsAffected() != 1 {
return fmt.Errorf("%w: provider %s changed during credential rotation", ErrProviderStore, rotation.ProviderID)
}
eventID, err := platformid.NewUUID()
if err != nil {
return err
}
payload, _ := json.Marshal(map[string]any{
"provider_id": rotation.ProviderID, "from_version": rotation.FromVersion,
"to_version": rotation.ToVersion, "actor_id": actorID,
})
if _, err := transaction.Exec(ctx, `
INSERT INTO gateway.outbox_events
(event_id, event_type, event_version, aggregate_type, aggregate_id, payload)
VALUES ($1, 'provider.credentials_rotated', 1, 'provider', $2, $3)`,
eventID, rotation.ProviderID, payload,
); err != nil {
return fmt.Errorf("%w: %v", ErrProviderStore, err)
}
}
if err := transaction.Commit(ctx); err != nil {
return fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return nil
}
type Repository struct {
pool *pgxpool.Pool
}
func NewRepository(pool *pgxpool.Pool) *Repository {
return &Repository{pool: pool}
}
func (r *Repository) List(ctx context.Context) ([]Record, error) {
if r.pool == nil {
return nil, ErrProviderStore
}
rows, err := r.pool.Query(ctx, `
SELECT id::text, tenant_id::text, code, adapter, base_url,
encrypted_credentials, credential_kek_version, capabilities,
config, enabled, revision
FROM gateway.providers
WHERE tenant_id IS NULL
ORDER BY code`)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer rows.Close()
var records []Record
for rows.Next() {
var record Record
if err := rows.Scan(
&record.ID, &record.TenantID, &record.Code, &record.Adapter, &record.BaseURL,
&record.EncryptedCredentials, &record.CredentialKEKVersion, &record.Capabilities,
&record.Config, &record.Enabled, &record.Revision,
); err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
records = append(records, record)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return records, nil
}
func (r *Repository) Get(ctx context.Context, id string) (Record, error) {
if r.pool == nil {
return Record{}, ErrProviderStore
}
var record Record
err := r.pool.QueryRow(ctx, `
SELECT id::text, tenant_id::text, code, adapter, base_url,
encrypted_credentials, credential_kek_version, capabilities,
config, enabled, revision
FROM gateway.providers
WHERE id = $1 AND tenant_id IS NULL`, id).Scan(
&record.ID, &record.TenantID, &record.Code, &record.Adapter, &record.BaseURL,
&record.EncryptedCredentials, &record.CredentialKEKVersion, &record.Capabilities,
&record.Config, &record.Enabled, &record.Revision,
)
return record, mapProviderError(err)
}
func (r *Repository) Create(ctx context.Context, record Record, actorID string) (Record, error) {
if r.pool == nil {
return Record{}, ErrProviderStore
}
id, err := platformid.NewUUID()
if err != nil {
return Record{}, err
}
eventID, err := platformid.NewUUID()
if err != nil {
return Record{}, err
}
record.ID = id
transaction, err := r.pool.Begin(ctx)
if err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer func() { _ = transaction.Rollback(ctx) }()
err = transaction.QueryRow(ctx, `
INSERT INTO gateway.providers
(id, code, adapter, base_url, encrypted_credentials,
credential_kek_version, capabilities, config, enabled, created_by)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING revision`, record.ID, record.Code, record.Adapter, record.BaseURL,
record.EncryptedCredentials, record.CredentialKEKVersion, record.Capabilities,
record.Config, record.Enabled, actorID).Scan(&record.Revision)
if err != nil {
return Record{}, mapProviderError(err)
}
payload, _ := json.Marshal(map[string]any{"provider_id": record.ID, "code": record.Code, "revision": record.Revision})
if _, err := transaction.Exec(ctx, `
INSERT INTO gateway.outbox_events
(event_id, event_type, event_version, aggregate_type, aggregate_id, payload)
VALUES ($1, 'provider.created', 1, 'provider', $2, $3)`, eventID, record.ID, payload); err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
if err := transaction.Commit(ctx); err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return record, nil
}
func (r *Repository) Update(ctx context.Context, record Record, actorID string, replaceCredentials bool) (Record, error) {
if r.pool == nil {
return Record{}, ErrProviderStore
}
eventID, err := platformid.NewUUID()
if err != nil {
return Record{}, err
}
transaction, err := r.pool.Begin(ctx)
if err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
defer func() { _ = transaction.Rollback(ctx) }()
err = transaction.QueryRow(ctx, `
UPDATE gateway.providers
SET code = $2,
adapter = $3,
base_url = $4,
encrypted_credentials = CASE WHEN $10 THEN $5 ELSE encrypted_credentials END,
credential_kek_version = CASE WHEN $10 THEN $6 ELSE credential_kek_version END,
capabilities = $7,
config = $8,
enabled = $9,
revision = revision + 1,
updated_at = clock_timestamp()
WHERE id = $1 AND tenant_id IS NULL
RETURNING revision`, record.ID, record.Code, record.Adapter, record.BaseURL,
record.EncryptedCredentials, record.CredentialKEKVersion, record.Capabilities,
record.Config, record.Enabled, replaceCredentials).Scan(&record.Revision)
if err != nil {
return Record{}, mapProviderError(err)
}
payload, _ := json.Marshal(map[string]any{
"provider_id": record.ID, "code": record.Code, "revision": record.Revision, "actor_id": actorID,
})
if _, err := transaction.Exec(ctx, `
INSERT INTO gateway.outbox_events
(event_id, event_type, event_version, aggregate_type, aggregate_id, payload)
VALUES ($1, 'provider.updated', 1, 'provider', $2, $3)`, eventID, record.ID, payload); err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
if err := transaction.Commit(ctx); err != nil {
return Record{}, fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return record, nil
}
func mapProviderError(err error) error {
if errors.Is(err, pgx.ErrNoRows) {
return ErrProviderNotFound
}
var pgError *pgconn.PgError
if errors.As(err, &pgError) && pgError.Code == "23505" {
if pgError.ConstraintName == "providers_single_global_default_idx" {
return ErrMultipleDefaults
}
return ErrProviderExists
}
if err != nil {
return fmt.Errorf("%w: %v", ErrProviderStore, err)
}
return nil
}