// storeglue_scan.go:api_keys 行扫描(store.scanKey 未导出,镜像之;仅显式列名)。 package gateway import ( "database/sql" "strings" "time" "onesvm.com/onesvm/browser-server/internal/config" "onesvm.com/onesvm/browser-server/internal/store" ) // _ 保留 sql 包引用(Raw 返回值使用)。 var _ = sql.ErrNoRows // DBGlue store.DB 门面(gateway 内对 store 的扩展查询统一入口)。 type DBGlue struct { db *store.DB } // NewDBGlue 构造。 func NewDBGlue(db *store.DB) *DBGlue { return &DBGlue{db: db} } // Raw 暴露底层连接(KeysAll/ConsumerByName 共用)。 func (d *DBGlue) Raw() *sql.DB { return d.db.Raw() } // scanKeyPublic 镜像 store.scanKey(列序与 keys.go keyCols 一致)。 func scanKeyPublic(row interface{ Scan(...any) error }) (*store.ApiKey, error) { var k store.ApiKey var scopes, createdAt string var expires sql.NullString if err := row.Scan(&k.ID, &k.ConsumerID, &k.Prefix, &k.Name, &k.Hash, &k.Salt, &scopes, &k.RPM, &k.DailyQuota, &k.MonthlyQuota, &k.ConcurrentSessions, &k.Status, &expires, &createdAt); err != nil { return nil, err } k.Scopes = strings.Split(scopes, ",") if expires.Valid && expires.String != "" { t, err := time.Parse(time.RFC3339, expires.String) if err != nil { return nil, err } tz := t.In(config.TZ) k.ExpiresAt = &tz } ct, err := time.Parse(time.RFC3339, createdAt) if err != nil { return nil, err } k.CreatedAt = ct return &k, nil }