Commit 7319122e authored by LLLLLLiulei's avatar LLLLLLiulei
Browse files

merge upstream/main

parents 029994a8 4809fa4f
......@@ -13,6 +13,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/announcement"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/predicate"
"github.com/Wei-Shaw/sub2api/ent/promocode"
......@@ -220,6 +221,33 @@ func (f TraverseAnnouncementRead) Traverse(ctx context.Context, q ent.Query) err
return fmt.Errorf("unexpected query type %T. expect *ent.AnnouncementReadQuery", q)
}
// The ErrorPassthroughRuleFunc type is an adapter to allow the use of ordinary function as a Querier.
type ErrorPassthroughRuleFunc func(context.Context, *ent.ErrorPassthroughRuleQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f ErrorPassthroughRuleFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.ErrorPassthroughRuleQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.ErrorPassthroughRuleQuery", q)
}
// The TraverseErrorPassthroughRule type is an adapter to allow the use of ordinary function as Traverser.
type TraverseErrorPassthroughRule func(context.Context, *ent.ErrorPassthroughRuleQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseErrorPassthroughRule) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseErrorPassthroughRule) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.ErrorPassthroughRuleQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.ErrorPassthroughRuleQuery", q)
}
// The GroupFunc type is an adapter to allow the use of ordinary function as a Querier.
type GroupFunc func(context.Context, *ent.GroupQuery) (ent.Value, error)
......@@ -584,6 +612,8 @@ func NewQuery(q ent.Query) (Query, error) {
return &query[*ent.AnnouncementQuery, predicate.Announcement, announcement.OrderOption]{typ: ent.TypeAnnouncement, tq: q}, nil
case *ent.AnnouncementReadQuery:
return &query[*ent.AnnouncementReadQuery, predicate.AnnouncementRead, announcementread.OrderOption]{typ: ent.TypeAnnouncementRead, tq: q}, nil
case *ent.ErrorPassthroughRuleQuery:
return &query[*ent.ErrorPassthroughRuleQuery, predicate.ErrorPassthroughRule, errorpassthroughrule.OrderOption]{typ: ent.TypeErrorPassthroughRule, tq: q}, nil
case *ent.GroupQuery:
return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil
case *ent.PromoCodeQuery:
......
......@@ -309,6 +309,42 @@ var (
},
},
}
// ErrorPassthroughRulesColumns holds the columns for the "error_passthrough_rules" table.
ErrorPassthroughRulesColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true},
{Name: "created_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "updated_at", Type: field.TypeTime, SchemaType: map[string]string{"postgres": "timestamptz"}},
{Name: "name", Type: field.TypeString, Size: 100},
{Name: "enabled", Type: field.TypeBool, Default: true},
{Name: "priority", Type: field.TypeInt, Default: 0},
{Name: "error_codes", Type: field.TypeJSON, Nullable: true, SchemaType: map[string]string{"postgres": "jsonb"}},
{Name: "keywords", Type: field.TypeJSON, Nullable: true, SchemaType: map[string]string{"postgres": "jsonb"}},
{Name: "match_mode", Type: field.TypeString, Size: 10, Default: "any"},
{Name: "platforms", Type: field.TypeJSON, Nullable: true, SchemaType: map[string]string{"postgres": "jsonb"}},
{Name: "passthrough_code", Type: field.TypeBool, Default: true},
{Name: "response_code", Type: field.TypeInt, Nullable: true},
{Name: "passthrough_body", Type: field.TypeBool, Default: true},
{Name: "custom_message", Type: field.TypeString, Nullable: true, Size: 2147483647},
{Name: "description", Type: field.TypeString, Nullable: true, Size: 2147483647},
}
// ErrorPassthroughRulesTable holds the schema information for the "error_passthrough_rules" table.
ErrorPassthroughRulesTable = &schema.Table{
Name: "error_passthrough_rules",
Columns: ErrorPassthroughRulesColumns,
PrimaryKey: []*schema.Column{ErrorPassthroughRulesColumns[0]},
Indexes: []*schema.Index{
{
Name: "errorpassthroughrule_enabled",
Unique: false,
Columns: []*schema.Column{ErrorPassthroughRulesColumns[4]},
},
{
Name: "errorpassthroughrule_priority",
Unique: false,
Columns: []*schema.Column{ErrorPassthroughRulesColumns[5]},
},
},
}
// GroupsColumns holds the columns for the "groups" table.
GroupsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true},
......@@ -950,6 +986,7 @@ var (
AccountGroupsTable,
AnnouncementsTable,
AnnouncementReadsTable,
ErrorPassthroughRulesTable,
GroupsTable,
PromoCodesTable,
PromoCodeUsagesTable,
......@@ -989,6 +1026,9 @@ func init() {
AnnouncementReadsTable.Annotation = &entsql.Annotation{
Table: "announcement_reads",
}
ErrorPassthroughRulesTable.Annotation = &entsql.Annotation{
Table: "error_passthrough_rules",
}
GroupsTable.Annotation = &entsql.Annotation{
Table: "groups",
}
......
......@@ -17,6 +17,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/announcement"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/predicate"
"github.com/Wei-Shaw/sub2api/ent/promocode"
......@@ -48,6 +49,7 @@ const (
TypeAccountGroup = "AccountGroup"
TypeAnnouncement = "Announcement"
TypeAnnouncementRead = "AnnouncementRead"
TypeErrorPassthroughRule = "ErrorPassthroughRule"
TypeGroup = "Group"
TypePromoCode = "PromoCode"
TypePromoCodeUsage = "PromoCodeUsage"
......@@ -5750,6 +5752,1272 @@ func (m *AnnouncementReadMutation) ResetEdge(name string) error {
return fmt.Errorf("unknown AnnouncementRead edge %s", name)
}
 
// ErrorPassthroughRuleMutation represents an operation that mutates the ErrorPassthroughRule nodes in the graph.
type ErrorPassthroughRuleMutation struct {
config
op Op
typ string
id *int64
created_at *time.Time
updated_at *time.Time
name *string
enabled *bool
priority *int
addpriority *int
error_codes *[]int
appenderror_codes []int
keywords *[]string
appendkeywords []string
match_mode *string
platforms *[]string
appendplatforms []string
passthrough_code *bool
response_code *int
addresponse_code *int
passthrough_body *bool
custom_message *string
description *string
clearedFields map[string]struct{}
done bool
oldValue func(context.Context) (*ErrorPassthroughRule, error)
predicates []predicate.ErrorPassthroughRule
}
var _ ent.Mutation = (*ErrorPassthroughRuleMutation)(nil)
// errorpassthroughruleOption allows management of the mutation configuration using functional options.
type errorpassthroughruleOption func(*ErrorPassthroughRuleMutation)
// newErrorPassthroughRuleMutation creates new mutation for the ErrorPassthroughRule entity.
func newErrorPassthroughRuleMutation(c config, op Op, opts ...errorpassthroughruleOption) *ErrorPassthroughRuleMutation {
m := &ErrorPassthroughRuleMutation{
config: c,
op: op,
typ: TypeErrorPassthroughRule,
clearedFields: make(map[string]struct{}),
}
for _, opt := range opts {
opt(m)
}
return m
}
// withErrorPassthroughRuleID sets the ID field of the mutation.
func withErrorPassthroughRuleID(id int64) errorpassthroughruleOption {
return func(m *ErrorPassthroughRuleMutation) {
var (
err error
once sync.Once
value *ErrorPassthroughRule
)
m.oldValue = func(ctx context.Context) (*ErrorPassthroughRule, error) {
once.Do(func() {
if m.done {
err = errors.New("querying old values post mutation is not allowed")
} else {
value, err = m.Client().ErrorPassthroughRule.Get(ctx, id)
}
})
return value, err
}
m.id = &id
}
}
// withErrorPassthroughRule sets the old ErrorPassthroughRule of the mutation.
func withErrorPassthroughRule(node *ErrorPassthroughRule) errorpassthroughruleOption {
return func(m *ErrorPassthroughRuleMutation) {
m.oldValue = func(context.Context) (*ErrorPassthroughRule, error) {
return node, nil
}
m.id = &node.ID
}
}
// Client returns a new `ent.Client` from the mutation. If the mutation was
// executed in a transaction (ent.Tx), a transactional client is returned.
func (m ErrorPassthroughRuleMutation) Client() *Client {
client := &Client{config: m.config}
client.init()
return client
}
// Tx returns an `ent.Tx` for mutations that were executed in transactions;
// it returns an error otherwise.
func (m ErrorPassthroughRuleMutation) Tx() (*Tx, error) {
if _, ok := m.driver.(*txDriver); !ok {
return nil, errors.New("ent: mutation is not running in a transaction")
}
tx := &Tx{config: m.config}
tx.init()
return tx, nil
}
// ID returns the ID value in the mutation. Note that the ID is only available
// if it was provided to the builder or after it was returned from the database.
func (m *ErrorPassthroughRuleMutation) ID() (id int64, exists bool) {
if m.id == nil {
return
}
return *m.id, true
}
// IDs queries the database and returns the entity ids that match the mutation's predicate.
// That means, if the mutation is applied within a transaction with an isolation level such
// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated
// or updated by the mutation.
func (m *ErrorPassthroughRuleMutation) IDs(ctx context.Context) ([]int64, error) {
switch {
case m.op.Is(OpUpdateOne | OpDeleteOne):
id, exists := m.ID()
if exists {
return []int64{id}, nil
}
fallthrough
case m.op.Is(OpUpdate | OpDelete):
return m.Client().ErrorPassthroughRule.Query().Where(m.predicates...).IDs(ctx)
default:
return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op)
}
}
// SetCreatedAt sets the "created_at" field.
func (m *ErrorPassthroughRuleMutation) SetCreatedAt(t time.Time) {
m.created_at = &t
}
// CreatedAt returns the value of the "created_at" field in the mutation.
func (m *ErrorPassthroughRuleMutation) CreatedAt() (r time.Time, exists bool) {
v := m.created_at
if v == nil {
return
}
return *v, true
}
// OldCreatedAt returns the old "created_at" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldCreatedAt(ctx context.Context) (v time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCreatedAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldCreatedAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldCreatedAt: %w", err)
}
return oldValue.CreatedAt, nil
}
// ResetCreatedAt resets all changes to the "created_at" field.
func (m *ErrorPassthroughRuleMutation) ResetCreatedAt() {
m.created_at = nil
}
// SetUpdatedAt sets the "updated_at" field.
func (m *ErrorPassthroughRuleMutation) SetUpdatedAt(t time.Time) {
m.updated_at = &t
}
// UpdatedAt returns the value of the "updated_at" field in the mutation.
func (m *ErrorPassthroughRuleMutation) UpdatedAt() (r time.Time, exists bool) {
v := m.updated_at
if v == nil {
return
}
return *v, true
}
// OldUpdatedAt returns the old "updated_at" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldUpdatedAt(ctx context.Context) (v time.Time, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldUpdatedAt is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldUpdatedAt requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldUpdatedAt: %w", err)
}
return oldValue.UpdatedAt, nil
}
// ResetUpdatedAt resets all changes to the "updated_at" field.
func (m *ErrorPassthroughRuleMutation) ResetUpdatedAt() {
m.updated_at = nil
}
// SetName sets the "name" field.
func (m *ErrorPassthroughRuleMutation) SetName(s string) {
m.name = &s
}
// Name returns the value of the "name" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Name() (r string, exists bool) {
v := m.name
if v == nil {
return
}
return *v, true
}
// OldName returns the old "name" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldName(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldName is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldName requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldName: %w", err)
}
return oldValue.Name, nil
}
// ResetName resets all changes to the "name" field.
func (m *ErrorPassthroughRuleMutation) ResetName() {
m.name = nil
}
// SetEnabled sets the "enabled" field.
func (m *ErrorPassthroughRuleMutation) SetEnabled(b bool) {
m.enabled = &b
}
// Enabled returns the value of the "enabled" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Enabled() (r bool, exists bool) {
v := m.enabled
if v == nil {
return
}
return *v, true
}
// OldEnabled returns the old "enabled" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldEnabled(ctx context.Context) (v bool, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldEnabled is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldEnabled requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldEnabled: %w", err)
}
return oldValue.Enabled, nil
}
// ResetEnabled resets all changes to the "enabled" field.
func (m *ErrorPassthroughRuleMutation) ResetEnabled() {
m.enabled = nil
}
// SetPriority sets the "priority" field.
func (m *ErrorPassthroughRuleMutation) SetPriority(i int) {
m.priority = &i
m.addpriority = nil
}
// Priority returns the value of the "priority" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Priority() (r int, exists bool) {
v := m.priority
if v == nil {
return
}
return *v, true
}
// OldPriority returns the old "priority" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldPriority(ctx context.Context) (v int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPriority is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPriority requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPriority: %w", err)
}
return oldValue.Priority, nil
}
// AddPriority adds i to the "priority" field.
func (m *ErrorPassthroughRuleMutation) AddPriority(i int) {
if m.addpriority != nil {
*m.addpriority += i
} else {
m.addpriority = &i
}
}
// AddedPriority returns the value that was added to the "priority" field in this mutation.
func (m *ErrorPassthroughRuleMutation) AddedPriority() (r int, exists bool) {
v := m.addpriority
if v == nil {
return
}
return *v, true
}
// ResetPriority resets all changes to the "priority" field.
func (m *ErrorPassthroughRuleMutation) ResetPriority() {
m.priority = nil
m.addpriority = nil
}
// SetErrorCodes sets the "error_codes" field.
func (m *ErrorPassthroughRuleMutation) SetErrorCodes(i []int) {
m.error_codes = &i
m.appenderror_codes = nil
}
// ErrorCodes returns the value of the "error_codes" field in the mutation.
func (m *ErrorPassthroughRuleMutation) ErrorCodes() (r []int, exists bool) {
v := m.error_codes
if v == nil {
return
}
return *v, true
}
// OldErrorCodes returns the old "error_codes" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldErrorCodes(ctx context.Context) (v []int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldErrorCodes is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldErrorCodes requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldErrorCodes: %w", err)
}
return oldValue.ErrorCodes, nil
}
// AppendErrorCodes adds i to the "error_codes" field.
func (m *ErrorPassthroughRuleMutation) AppendErrorCodes(i []int) {
m.appenderror_codes = append(m.appenderror_codes, i...)
}
// AppendedErrorCodes returns the list of values that were appended to the "error_codes" field in this mutation.
func (m *ErrorPassthroughRuleMutation) AppendedErrorCodes() ([]int, bool) {
if len(m.appenderror_codes) == 0 {
return nil, false
}
return m.appenderror_codes, true
}
// ClearErrorCodes clears the value of the "error_codes" field.
func (m *ErrorPassthroughRuleMutation) ClearErrorCodes() {
m.error_codes = nil
m.appenderror_codes = nil
m.clearedFields[errorpassthroughrule.FieldErrorCodes] = struct{}{}
}
// ErrorCodesCleared returns if the "error_codes" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) ErrorCodesCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldErrorCodes]
return ok
}
// ResetErrorCodes resets all changes to the "error_codes" field.
func (m *ErrorPassthroughRuleMutation) ResetErrorCodes() {
m.error_codes = nil
m.appenderror_codes = nil
delete(m.clearedFields, errorpassthroughrule.FieldErrorCodes)
}
// SetKeywords sets the "keywords" field.
func (m *ErrorPassthroughRuleMutation) SetKeywords(s []string) {
m.keywords = &s
m.appendkeywords = nil
}
// Keywords returns the value of the "keywords" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Keywords() (r []string, exists bool) {
v := m.keywords
if v == nil {
return
}
return *v, true
}
// OldKeywords returns the old "keywords" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldKeywords(ctx context.Context) (v []string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldKeywords is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldKeywords requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldKeywords: %w", err)
}
return oldValue.Keywords, nil
}
// AppendKeywords adds s to the "keywords" field.
func (m *ErrorPassthroughRuleMutation) AppendKeywords(s []string) {
m.appendkeywords = append(m.appendkeywords, s...)
}
// AppendedKeywords returns the list of values that were appended to the "keywords" field in this mutation.
func (m *ErrorPassthroughRuleMutation) AppendedKeywords() ([]string, bool) {
if len(m.appendkeywords) == 0 {
return nil, false
}
return m.appendkeywords, true
}
// ClearKeywords clears the value of the "keywords" field.
func (m *ErrorPassthroughRuleMutation) ClearKeywords() {
m.keywords = nil
m.appendkeywords = nil
m.clearedFields[errorpassthroughrule.FieldKeywords] = struct{}{}
}
// KeywordsCleared returns if the "keywords" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) KeywordsCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldKeywords]
return ok
}
// ResetKeywords resets all changes to the "keywords" field.
func (m *ErrorPassthroughRuleMutation) ResetKeywords() {
m.keywords = nil
m.appendkeywords = nil
delete(m.clearedFields, errorpassthroughrule.FieldKeywords)
}
// SetMatchMode sets the "match_mode" field.
func (m *ErrorPassthroughRuleMutation) SetMatchMode(s string) {
m.match_mode = &s
}
// MatchMode returns the value of the "match_mode" field in the mutation.
func (m *ErrorPassthroughRuleMutation) MatchMode() (r string, exists bool) {
v := m.match_mode
if v == nil {
return
}
return *v, true
}
// OldMatchMode returns the old "match_mode" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldMatchMode(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldMatchMode is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldMatchMode requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldMatchMode: %w", err)
}
return oldValue.MatchMode, nil
}
// ResetMatchMode resets all changes to the "match_mode" field.
func (m *ErrorPassthroughRuleMutation) ResetMatchMode() {
m.match_mode = nil
}
// SetPlatforms sets the "platforms" field.
func (m *ErrorPassthroughRuleMutation) SetPlatforms(s []string) {
m.platforms = &s
m.appendplatforms = nil
}
// Platforms returns the value of the "platforms" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Platforms() (r []string, exists bool) {
v := m.platforms
if v == nil {
return
}
return *v, true
}
// OldPlatforms returns the old "platforms" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldPlatforms(ctx context.Context) (v []string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPlatforms is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPlatforms requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPlatforms: %w", err)
}
return oldValue.Platforms, nil
}
// AppendPlatforms adds s to the "platforms" field.
func (m *ErrorPassthroughRuleMutation) AppendPlatforms(s []string) {
m.appendplatforms = append(m.appendplatforms, s...)
}
// AppendedPlatforms returns the list of values that were appended to the "platforms" field in this mutation.
func (m *ErrorPassthroughRuleMutation) AppendedPlatforms() ([]string, bool) {
if len(m.appendplatforms) == 0 {
return nil, false
}
return m.appendplatforms, true
}
// ClearPlatforms clears the value of the "platforms" field.
func (m *ErrorPassthroughRuleMutation) ClearPlatforms() {
m.platforms = nil
m.appendplatforms = nil
m.clearedFields[errorpassthroughrule.FieldPlatforms] = struct{}{}
}
// PlatformsCleared returns if the "platforms" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) PlatformsCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldPlatforms]
return ok
}
// ResetPlatforms resets all changes to the "platforms" field.
func (m *ErrorPassthroughRuleMutation) ResetPlatforms() {
m.platforms = nil
m.appendplatforms = nil
delete(m.clearedFields, errorpassthroughrule.FieldPlatforms)
}
// SetPassthroughCode sets the "passthrough_code" field.
func (m *ErrorPassthroughRuleMutation) SetPassthroughCode(b bool) {
m.passthrough_code = &b
}
// PassthroughCode returns the value of the "passthrough_code" field in the mutation.
func (m *ErrorPassthroughRuleMutation) PassthroughCode() (r bool, exists bool) {
v := m.passthrough_code
if v == nil {
return
}
return *v, true
}
// OldPassthroughCode returns the old "passthrough_code" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldPassthroughCode(ctx context.Context) (v bool, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPassthroughCode is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPassthroughCode requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPassthroughCode: %w", err)
}
return oldValue.PassthroughCode, nil
}
// ResetPassthroughCode resets all changes to the "passthrough_code" field.
func (m *ErrorPassthroughRuleMutation) ResetPassthroughCode() {
m.passthrough_code = nil
}
// SetResponseCode sets the "response_code" field.
func (m *ErrorPassthroughRuleMutation) SetResponseCode(i int) {
m.response_code = &i
m.addresponse_code = nil
}
// ResponseCode returns the value of the "response_code" field in the mutation.
func (m *ErrorPassthroughRuleMutation) ResponseCode() (r int, exists bool) {
v := m.response_code
if v == nil {
return
}
return *v, true
}
// OldResponseCode returns the old "response_code" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldResponseCode(ctx context.Context) (v *int, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldResponseCode is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldResponseCode requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldResponseCode: %w", err)
}
return oldValue.ResponseCode, nil
}
// AddResponseCode adds i to the "response_code" field.
func (m *ErrorPassthroughRuleMutation) AddResponseCode(i int) {
if m.addresponse_code != nil {
*m.addresponse_code += i
} else {
m.addresponse_code = &i
}
}
// AddedResponseCode returns the value that was added to the "response_code" field in this mutation.
func (m *ErrorPassthroughRuleMutation) AddedResponseCode() (r int, exists bool) {
v := m.addresponse_code
if v == nil {
return
}
return *v, true
}
// ClearResponseCode clears the value of the "response_code" field.
func (m *ErrorPassthroughRuleMutation) ClearResponseCode() {
m.response_code = nil
m.addresponse_code = nil
m.clearedFields[errorpassthroughrule.FieldResponseCode] = struct{}{}
}
// ResponseCodeCleared returns if the "response_code" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) ResponseCodeCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldResponseCode]
return ok
}
// ResetResponseCode resets all changes to the "response_code" field.
func (m *ErrorPassthroughRuleMutation) ResetResponseCode() {
m.response_code = nil
m.addresponse_code = nil
delete(m.clearedFields, errorpassthroughrule.FieldResponseCode)
}
// SetPassthroughBody sets the "passthrough_body" field.
func (m *ErrorPassthroughRuleMutation) SetPassthroughBody(b bool) {
m.passthrough_body = &b
}
// PassthroughBody returns the value of the "passthrough_body" field in the mutation.
func (m *ErrorPassthroughRuleMutation) PassthroughBody() (r bool, exists bool) {
v := m.passthrough_body
if v == nil {
return
}
return *v, true
}
// OldPassthroughBody returns the old "passthrough_body" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldPassthroughBody(ctx context.Context) (v bool, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldPassthroughBody is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldPassthroughBody requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldPassthroughBody: %w", err)
}
return oldValue.PassthroughBody, nil
}
// ResetPassthroughBody resets all changes to the "passthrough_body" field.
func (m *ErrorPassthroughRuleMutation) ResetPassthroughBody() {
m.passthrough_body = nil
}
// SetCustomMessage sets the "custom_message" field.
func (m *ErrorPassthroughRuleMutation) SetCustomMessage(s string) {
m.custom_message = &s
}
// CustomMessage returns the value of the "custom_message" field in the mutation.
func (m *ErrorPassthroughRuleMutation) CustomMessage() (r string, exists bool) {
v := m.custom_message
if v == nil {
return
}
return *v, true
}
// OldCustomMessage returns the old "custom_message" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldCustomMessage(ctx context.Context) (v *string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCustomMessage is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldCustomMessage requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldCustomMessage: %w", err)
}
return oldValue.CustomMessage, nil
}
// ClearCustomMessage clears the value of the "custom_message" field.
func (m *ErrorPassthroughRuleMutation) ClearCustomMessage() {
m.custom_message = nil
m.clearedFields[errorpassthroughrule.FieldCustomMessage] = struct{}{}
}
// CustomMessageCleared returns if the "custom_message" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) CustomMessageCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldCustomMessage]
return ok
}
// ResetCustomMessage resets all changes to the "custom_message" field.
func (m *ErrorPassthroughRuleMutation) ResetCustomMessage() {
m.custom_message = nil
delete(m.clearedFields, errorpassthroughrule.FieldCustomMessage)
}
// SetDescription sets the "description" field.
func (m *ErrorPassthroughRuleMutation) SetDescription(s string) {
m.description = &s
}
// Description returns the value of the "description" field in the mutation.
func (m *ErrorPassthroughRuleMutation) Description() (r string, exists bool) {
v := m.description
if v == nil {
return
}
return *v, true
}
// OldDescription returns the old "description" field's value of the ErrorPassthroughRule entity.
// If the ErrorPassthroughRule object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *ErrorPassthroughRuleMutation) OldDescription(ctx context.Context) (v *string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldDescription is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldDescription requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldDescription: %w", err)
}
return oldValue.Description, nil
}
// ClearDescription clears the value of the "description" field.
func (m *ErrorPassthroughRuleMutation) ClearDescription() {
m.description = nil
m.clearedFields[errorpassthroughrule.FieldDescription] = struct{}{}
}
// DescriptionCleared returns if the "description" field was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) DescriptionCleared() bool {
_, ok := m.clearedFields[errorpassthroughrule.FieldDescription]
return ok
}
// ResetDescription resets all changes to the "description" field.
func (m *ErrorPassthroughRuleMutation) ResetDescription() {
m.description = nil
delete(m.clearedFields, errorpassthroughrule.FieldDescription)
}
// Where appends a list predicates to the ErrorPassthroughRuleMutation builder.
func (m *ErrorPassthroughRuleMutation) Where(ps ...predicate.ErrorPassthroughRule) {
m.predicates = append(m.predicates, ps...)
}
// WhereP appends storage-level predicates to the ErrorPassthroughRuleMutation builder. Using this method,
// users can use type-assertion to append predicates that do not depend on any generated package.
func (m *ErrorPassthroughRuleMutation) WhereP(ps ...func(*sql.Selector)) {
p := make([]predicate.ErrorPassthroughRule, len(ps))
for i := range ps {
p[i] = ps[i]
}
m.Where(p...)
}
// Op returns the operation name.
func (m *ErrorPassthroughRuleMutation) Op() Op {
return m.op
}
// SetOp allows setting the mutation operation.
func (m *ErrorPassthroughRuleMutation) SetOp(op Op) {
m.op = op
}
// Type returns the node type of this mutation (ErrorPassthroughRule).
func (m *ErrorPassthroughRuleMutation) Type() string {
return m.typ
}
// Fields returns all fields that were changed during this mutation. Note that in
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *ErrorPassthroughRuleMutation) Fields() []string {
fields := make([]string, 0, 14)
if m.created_at != nil {
fields = append(fields, errorpassthroughrule.FieldCreatedAt)
}
if m.updated_at != nil {
fields = append(fields, errorpassthroughrule.FieldUpdatedAt)
}
if m.name != nil {
fields = append(fields, errorpassthroughrule.FieldName)
}
if m.enabled != nil {
fields = append(fields, errorpassthroughrule.FieldEnabled)
}
if m.priority != nil {
fields = append(fields, errorpassthroughrule.FieldPriority)
}
if m.error_codes != nil {
fields = append(fields, errorpassthroughrule.FieldErrorCodes)
}
if m.keywords != nil {
fields = append(fields, errorpassthroughrule.FieldKeywords)
}
if m.match_mode != nil {
fields = append(fields, errorpassthroughrule.FieldMatchMode)
}
if m.platforms != nil {
fields = append(fields, errorpassthroughrule.FieldPlatforms)
}
if m.passthrough_code != nil {
fields = append(fields, errorpassthroughrule.FieldPassthroughCode)
}
if m.response_code != nil {
fields = append(fields, errorpassthroughrule.FieldResponseCode)
}
if m.passthrough_body != nil {
fields = append(fields, errorpassthroughrule.FieldPassthroughBody)
}
if m.custom_message != nil {
fields = append(fields, errorpassthroughrule.FieldCustomMessage)
}
if m.description != nil {
fields = append(fields, errorpassthroughrule.FieldDescription)
}
return fields
}
// Field returns the value of a field with the given name. The second boolean
// return value indicates that this field was not set, or was not defined in the
// schema.
func (m *ErrorPassthroughRuleMutation) Field(name string) (ent.Value, bool) {
switch name {
case errorpassthroughrule.FieldCreatedAt:
return m.CreatedAt()
case errorpassthroughrule.FieldUpdatedAt:
return m.UpdatedAt()
case errorpassthroughrule.FieldName:
return m.Name()
case errorpassthroughrule.FieldEnabled:
return m.Enabled()
case errorpassthroughrule.FieldPriority:
return m.Priority()
case errorpassthroughrule.FieldErrorCodes:
return m.ErrorCodes()
case errorpassthroughrule.FieldKeywords:
return m.Keywords()
case errorpassthroughrule.FieldMatchMode:
return m.MatchMode()
case errorpassthroughrule.FieldPlatforms:
return m.Platforms()
case errorpassthroughrule.FieldPassthroughCode:
return m.PassthroughCode()
case errorpassthroughrule.FieldResponseCode:
return m.ResponseCode()
case errorpassthroughrule.FieldPassthroughBody:
return m.PassthroughBody()
case errorpassthroughrule.FieldCustomMessage:
return m.CustomMessage()
case errorpassthroughrule.FieldDescription:
return m.Description()
}
return nil, false
}
// OldField returns the old value of the field from the database. An error is
// returned if the mutation operation is not UpdateOne, or the query to the
// database failed.
func (m *ErrorPassthroughRuleMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
switch name {
case errorpassthroughrule.FieldCreatedAt:
return m.OldCreatedAt(ctx)
case errorpassthroughrule.FieldUpdatedAt:
return m.OldUpdatedAt(ctx)
case errorpassthroughrule.FieldName:
return m.OldName(ctx)
case errorpassthroughrule.FieldEnabled:
return m.OldEnabled(ctx)
case errorpassthroughrule.FieldPriority:
return m.OldPriority(ctx)
case errorpassthroughrule.FieldErrorCodes:
return m.OldErrorCodes(ctx)
case errorpassthroughrule.FieldKeywords:
return m.OldKeywords(ctx)
case errorpassthroughrule.FieldMatchMode:
return m.OldMatchMode(ctx)
case errorpassthroughrule.FieldPlatforms:
return m.OldPlatforms(ctx)
case errorpassthroughrule.FieldPassthroughCode:
return m.OldPassthroughCode(ctx)
case errorpassthroughrule.FieldResponseCode:
return m.OldResponseCode(ctx)
case errorpassthroughrule.FieldPassthroughBody:
return m.OldPassthroughBody(ctx)
case errorpassthroughrule.FieldCustomMessage:
return m.OldCustomMessage(ctx)
case errorpassthroughrule.FieldDescription:
return m.OldDescription(ctx)
}
return nil, fmt.Errorf("unknown ErrorPassthroughRule field %s", name)
}
// SetField sets the value of a field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *ErrorPassthroughRuleMutation) SetField(name string, value ent.Value) error {
switch name {
case errorpassthroughrule.FieldCreatedAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetCreatedAt(v)
return nil
case errorpassthroughrule.FieldUpdatedAt:
v, ok := value.(time.Time)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetUpdatedAt(v)
return nil
case errorpassthroughrule.FieldName:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetName(v)
return nil
case errorpassthroughrule.FieldEnabled:
v, ok := value.(bool)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetEnabled(v)
return nil
case errorpassthroughrule.FieldPriority:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPriority(v)
return nil
case errorpassthroughrule.FieldErrorCodes:
v, ok := value.([]int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetErrorCodes(v)
return nil
case errorpassthroughrule.FieldKeywords:
v, ok := value.([]string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetKeywords(v)
return nil
case errorpassthroughrule.FieldMatchMode:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetMatchMode(v)
return nil
case errorpassthroughrule.FieldPlatforms:
v, ok := value.([]string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPlatforms(v)
return nil
case errorpassthroughrule.FieldPassthroughCode:
v, ok := value.(bool)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPassthroughCode(v)
return nil
case errorpassthroughrule.FieldResponseCode:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetResponseCode(v)
return nil
case errorpassthroughrule.FieldPassthroughBody:
v, ok := value.(bool)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetPassthroughBody(v)
return nil
case errorpassthroughrule.FieldCustomMessage:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetCustomMessage(v)
return nil
case errorpassthroughrule.FieldDescription:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetDescription(v)
return nil
}
return fmt.Errorf("unknown ErrorPassthroughRule field %s", name)
}
// AddedFields returns all numeric fields that were incremented/decremented during
// this mutation.
func (m *ErrorPassthroughRuleMutation) AddedFields() []string {
var fields []string
if m.addpriority != nil {
fields = append(fields, errorpassthroughrule.FieldPriority)
}
if m.addresponse_code != nil {
fields = append(fields, errorpassthroughrule.FieldResponseCode)
}
return fields
}
// AddedField returns the numeric value that was incremented/decremented on a field
// with the given name. The second boolean return value indicates that this field
// was not set, or was not defined in the schema.
func (m *ErrorPassthroughRuleMutation) AddedField(name string) (ent.Value, bool) {
switch name {
case errorpassthroughrule.FieldPriority:
return m.AddedPriority()
case errorpassthroughrule.FieldResponseCode:
return m.AddedResponseCode()
}
return nil, false
}
// AddField adds the value to the field with the given name. It returns an error if
// the field is not defined in the schema, or if the type mismatched the field
// type.
func (m *ErrorPassthroughRuleMutation) AddField(name string, value ent.Value) error {
switch name {
case errorpassthroughrule.FieldPriority:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddPriority(v)
return nil
case errorpassthroughrule.FieldResponseCode:
v, ok := value.(int)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.AddResponseCode(v)
return nil
}
return fmt.Errorf("unknown ErrorPassthroughRule numeric field %s", name)
}
// ClearedFields returns all nullable fields that were cleared during this
// mutation.
func (m *ErrorPassthroughRuleMutation) ClearedFields() []string {
var fields []string
if m.FieldCleared(errorpassthroughrule.FieldErrorCodes) {
fields = append(fields, errorpassthroughrule.FieldErrorCodes)
}
if m.FieldCleared(errorpassthroughrule.FieldKeywords) {
fields = append(fields, errorpassthroughrule.FieldKeywords)
}
if m.FieldCleared(errorpassthroughrule.FieldPlatforms) {
fields = append(fields, errorpassthroughrule.FieldPlatforms)
}
if m.FieldCleared(errorpassthroughrule.FieldResponseCode) {
fields = append(fields, errorpassthroughrule.FieldResponseCode)
}
if m.FieldCleared(errorpassthroughrule.FieldCustomMessage) {
fields = append(fields, errorpassthroughrule.FieldCustomMessage)
}
if m.FieldCleared(errorpassthroughrule.FieldDescription) {
fields = append(fields, errorpassthroughrule.FieldDescription)
}
return fields
}
// FieldCleared returns a boolean indicating if a field with the given name was
// cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) FieldCleared(name string) bool {
_, ok := m.clearedFields[name]
return ok
}
// ClearField clears the value of the field with the given name. It returns an
// error if the field is not defined in the schema.
func (m *ErrorPassthroughRuleMutation) ClearField(name string) error {
switch name {
case errorpassthroughrule.FieldErrorCodes:
m.ClearErrorCodes()
return nil
case errorpassthroughrule.FieldKeywords:
m.ClearKeywords()
return nil
case errorpassthroughrule.FieldPlatforms:
m.ClearPlatforms()
return nil
case errorpassthroughrule.FieldResponseCode:
m.ClearResponseCode()
return nil
case errorpassthroughrule.FieldCustomMessage:
m.ClearCustomMessage()
return nil
case errorpassthroughrule.FieldDescription:
m.ClearDescription()
return nil
}
return fmt.Errorf("unknown ErrorPassthroughRule nullable field %s", name)
}
// ResetField resets all changes in the mutation for the field with the given name.
// It returns an error if the field is not defined in the schema.
func (m *ErrorPassthroughRuleMutation) ResetField(name string) error {
switch name {
case errorpassthroughrule.FieldCreatedAt:
m.ResetCreatedAt()
return nil
case errorpassthroughrule.FieldUpdatedAt:
m.ResetUpdatedAt()
return nil
case errorpassthroughrule.FieldName:
m.ResetName()
return nil
case errorpassthroughrule.FieldEnabled:
m.ResetEnabled()
return nil
case errorpassthroughrule.FieldPriority:
m.ResetPriority()
return nil
case errorpassthroughrule.FieldErrorCodes:
m.ResetErrorCodes()
return nil
case errorpassthroughrule.FieldKeywords:
m.ResetKeywords()
return nil
case errorpassthroughrule.FieldMatchMode:
m.ResetMatchMode()
return nil
case errorpassthroughrule.FieldPlatforms:
m.ResetPlatforms()
return nil
case errorpassthroughrule.FieldPassthroughCode:
m.ResetPassthroughCode()
return nil
case errorpassthroughrule.FieldResponseCode:
m.ResetResponseCode()
return nil
case errorpassthroughrule.FieldPassthroughBody:
m.ResetPassthroughBody()
return nil
case errorpassthroughrule.FieldCustomMessage:
m.ResetCustomMessage()
return nil
case errorpassthroughrule.FieldDescription:
m.ResetDescription()
return nil
}
return fmt.Errorf("unknown ErrorPassthroughRule field %s", name)
}
// AddedEdges returns all edge names that were set/added in this mutation.
func (m *ErrorPassthroughRuleMutation) AddedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// AddedIDs returns all IDs (to other nodes) that were added for the given edge
// name in this mutation.
func (m *ErrorPassthroughRuleMutation) AddedIDs(name string) []ent.Value {
return nil
}
// RemovedEdges returns all edge names that were removed in this mutation.
func (m *ErrorPassthroughRuleMutation) RemovedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with
// the given name in this mutation.
func (m *ErrorPassthroughRuleMutation) RemovedIDs(name string) []ent.Value {
return nil
}
// ClearedEdges returns all edge names that were cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) ClearedEdges() []string {
edges := make([]string, 0, 0)
return edges
}
// EdgeCleared returns a boolean which indicates if the edge with the given name
// was cleared in this mutation.
func (m *ErrorPassthroughRuleMutation) EdgeCleared(name string) bool {
return false
}
// ClearEdge clears the value of the edge with the given name. It returns an error
// if that edge is not defined in the schema.
func (m *ErrorPassthroughRuleMutation) ClearEdge(name string) error {
return fmt.Errorf("unknown ErrorPassthroughRule unique edge %s", name)
}
// ResetEdge resets all changes to the edge with the given name in this mutation.
// It returns an error if the edge is not defined in the schema.
func (m *ErrorPassthroughRuleMutation) ResetEdge(name string) error {
return fmt.Errorf("unknown ErrorPassthroughRule edge %s", name)
}
// GroupMutation represents an operation that mutates the Group nodes in the graph.
type GroupMutation struct {
config
......
......@@ -21,6 +21,9 @@ type Announcement func(*sql.Selector)
// AnnouncementRead is the predicate function for announcementread builders.
type AnnouncementRead func(*sql.Selector)
// ErrorPassthroughRule is the predicate function for errorpassthroughrule builders.
type ErrorPassthroughRule func(*sql.Selector)
// Group is the predicate function for group builders.
type Group func(*sql.Selector)
......
......@@ -10,6 +10,7 @@ import (
"github.com/Wei-Shaw/sub2api/ent/announcement"
"github.com/Wei-Shaw/sub2api/ent/announcementread"
"github.com/Wei-Shaw/sub2api/ent/apikey"
"github.com/Wei-Shaw/sub2api/ent/errorpassthroughrule"
"github.com/Wei-Shaw/sub2api/ent/group"
"github.com/Wei-Shaw/sub2api/ent/promocode"
"github.com/Wei-Shaw/sub2api/ent/promocodeusage"
......@@ -270,6 +271,61 @@ func init() {
announcementreadDescCreatedAt := announcementreadFields[3].Descriptor()
// announcementread.DefaultCreatedAt holds the default value on creation for the created_at field.
announcementread.DefaultCreatedAt = announcementreadDescCreatedAt.Default.(func() time.Time)
errorpassthroughruleMixin := schema.ErrorPassthroughRule{}.Mixin()
errorpassthroughruleMixinFields0 := errorpassthroughruleMixin[0].Fields()
_ = errorpassthroughruleMixinFields0
errorpassthroughruleFields := schema.ErrorPassthroughRule{}.Fields()
_ = errorpassthroughruleFields
// errorpassthroughruleDescCreatedAt is the schema descriptor for created_at field.
errorpassthroughruleDescCreatedAt := errorpassthroughruleMixinFields0[0].Descriptor()
// errorpassthroughrule.DefaultCreatedAt holds the default value on creation for the created_at field.
errorpassthroughrule.DefaultCreatedAt = errorpassthroughruleDescCreatedAt.Default.(func() time.Time)
// errorpassthroughruleDescUpdatedAt is the schema descriptor for updated_at field.
errorpassthroughruleDescUpdatedAt := errorpassthroughruleMixinFields0[1].Descriptor()
// errorpassthroughrule.DefaultUpdatedAt holds the default value on creation for the updated_at field.
errorpassthroughrule.DefaultUpdatedAt = errorpassthroughruleDescUpdatedAt.Default.(func() time.Time)
// errorpassthroughrule.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
errorpassthroughrule.UpdateDefaultUpdatedAt = errorpassthroughruleDescUpdatedAt.UpdateDefault.(func() time.Time)
// errorpassthroughruleDescName is the schema descriptor for name field.
errorpassthroughruleDescName := errorpassthroughruleFields[0].Descriptor()
// errorpassthroughrule.NameValidator is a validator for the "name" field. It is called by the builders before save.
errorpassthroughrule.NameValidator = func() func(string) error {
validators := errorpassthroughruleDescName.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(name string) error {
for _, fn := range fns {
if err := fn(name); err != nil {
return err
}
}
return nil
}
}()
// errorpassthroughruleDescEnabled is the schema descriptor for enabled field.
errorpassthroughruleDescEnabled := errorpassthroughruleFields[1].Descriptor()
// errorpassthroughrule.DefaultEnabled holds the default value on creation for the enabled field.
errorpassthroughrule.DefaultEnabled = errorpassthroughruleDescEnabled.Default.(bool)
// errorpassthroughruleDescPriority is the schema descriptor for priority field.
errorpassthroughruleDescPriority := errorpassthroughruleFields[2].Descriptor()
// errorpassthroughrule.DefaultPriority holds the default value on creation for the priority field.
errorpassthroughrule.DefaultPriority = errorpassthroughruleDescPriority.Default.(int)
// errorpassthroughruleDescMatchMode is the schema descriptor for match_mode field.
errorpassthroughruleDescMatchMode := errorpassthroughruleFields[5].Descriptor()
// errorpassthroughrule.DefaultMatchMode holds the default value on creation for the match_mode field.
errorpassthroughrule.DefaultMatchMode = errorpassthroughruleDescMatchMode.Default.(string)
// errorpassthroughrule.MatchModeValidator is a validator for the "match_mode" field. It is called by the builders before save.
errorpassthroughrule.MatchModeValidator = errorpassthroughruleDescMatchMode.Validators[0].(func(string) error)
// errorpassthroughruleDescPassthroughCode is the schema descriptor for passthrough_code field.
errorpassthroughruleDescPassthroughCode := errorpassthroughruleFields[7].Descriptor()
// errorpassthroughrule.DefaultPassthroughCode holds the default value on creation for the passthrough_code field.
errorpassthroughrule.DefaultPassthroughCode = errorpassthroughruleDescPassthroughCode.Default.(bool)
// errorpassthroughruleDescPassthroughBody is the schema descriptor for passthrough_body field.
errorpassthroughruleDescPassthroughBody := errorpassthroughruleFields[9].Descriptor()
// errorpassthroughrule.DefaultPassthroughBody holds the default value on creation for the passthrough_body field.
errorpassthroughrule.DefaultPassthroughBody = errorpassthroughruleDescPassthroughBody.Default.(bool)
groupMixin := schema.Group{}.Mixin()
groupMixinHooks1 := groupMixin[1].Hooks()
group.Hooks[0] = groupMixinHooks1[0]
......
// Package schema 定义 Ent ORM 的数据库 schema。
package schema
import (
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
"entgo.io/ent"
"entgo.io/ent/dialect"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
)
// ErrorPassthroughRule 定义全局错误透传规则的 schema。
//
// 错误透传规则用于控制上游错误如何返回给客户端:
// - 匹配条件:错误码 + 关键词组合
// - 响应行为:透传原始信息 或 自定义错误信息
// - 响应状态码:可指定返回给客户端的状态码
// - 平台范围:规则适用的平台(Anthropic、OpenAI、Gemini、Antigravity)
type ErrorPassthroughRule struct {
ent.Schema
}
// Annotations 返回 schema 的注解配置。
func (ErrorPassthroughRule) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "error_passthrough_rules"},
}
}
// Mixin 返回该 schema 使用的混入组件。
func (ErrorPassthroughRule) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.TimeMixin{},
}
}
// Fields 定义错误透传规则实体的所有字段。
func (ErrorPassthroughRule) Fields() []ent.Field {
return []ent.Field{
// name: 规则名称,用于在界面中标识规则
field.String("name").
MaxLen(100).
NotEmpty(),
// enabled: 是否启用该规则
field.Bool("enabled").
Default(true),
// priority: 规则优先级,数值越小优先级越高
// 匹配时按优先级顺序检查,命中第一个匹配的规则
field.Int("priority").
Default(0),
// error_codes: 匹配的错误码列表(OR关系)
// 例如:[422, 400] 表示匹配 422 或 400 错误码
field.JSON("error_codes", []int{}).
Optional().
SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
// keywords: 匹配的关键词列表(OR关系)
// 例如:["context limit", "model not supported"]
// 关键词匹配不区分大小写
field.JSON("keywords", []string{}).
Optional().
SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
// match_mode: 匹配模式
// - "any": 错误码匹配 OR 关键词匹配(任一条件满足即可)
// - "all": 错误码匹配 AND 关键词匹配(所有条件都必须满足)
field.String("match_mode").
MaxLen(10).
Default("any"),
// platforms: 适用平台列表
// 例如:["anthropic", "openai", "gemini", "antigravity"]
// 空列表表示适用于所有平台
field.JSON("platforms", []string{}).
Optional().
SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
// passthrough_code: 是否透传上游原始状态码
// true: 使用上游返回的状态码
// false: 使用 response_code 指定的状态码
field.Bool("passthrough_code").
Default(true),
// response_code: 自定义响应状态码
// 当 passthrough_code=false 时使用此状态码
field.Int("response_code").
Optional().
Nillable(),
// passthrough_body: 是否透传上游原始错误信息
// true: 使用上游返回的错误信息
// false: 使用 custom_message 指定的错误信息
field.Bool("passthrough_body").
Default(true),
// custom_message: 自定义错误信息
// 当 passthrough_body=false 时使用此错误信息
field.Text("custom_message").
Optional().
Nillable(),
// description: 规则描述,用于说明规则的用途
field.Text("description").
Optional().
Nillable(),
}
}
// Indexes 定义数据库索引,优化查询性能。
func (ErrorPassthroughRule) Indexes() []ent.Index {
return []ent.Index{
index.Fields("enabled"), // 筛选启用的规则
index.Fields("priority"), // 按优先级排序
}
}
......@@ -24,6 +24,8 @@ type Tx struct {
Announcement *AnnouncementClient
// AnnouncementRead is the client for interacting with the AnnouncementRead builders.
AnnouncementRead *AnnouncementReadClient
// ErrorPassthroughRule is the client for interacting with the ErrorPassthroughRule builders.
ErrorPassthroughRule *ErrorPassthroughRuleClient
// Group is the client for interacting with the Group builders.
Group *GroupClient
// PromoCode is the client for interacting with the PromoCode builders.
......@@ -186,6 +188,7 @@ func (tx *Tx) init() {
tx.AccountGroup = NewAccountGroupClient(tx.config)
tx.Announcement = NewAnnouncementClient(tx.config)
tx.AnnouncementRead = NewAnnouncementReadClient(tx.config)
tx.ErrorPassthroughRule = NewErrorPassthroughRuleClient(tx.config)
tx.Group = NewGroupClient(tx.config)
tx.PromoCode = NewPromoCodeClient(tx.config)
tx.PromoCodeUsage = NewPromoCodeUsageClient(tx.config)
......
module github.com/Wei-Shaw/sub2api
go 1.25.6
go 1.25.7
require (
entgo.io/ent v0.14.5
......
package admin
import (
"strconv"
"github.com/Wei-Shaw/sub2api/internal/model"
"github.com/Wei-Shaw/sub2api/internal/pkg/response"
"github.com/Wei-Shaw/sub2api/internal/service"
"github.com/gin-gonic/gin"
)
// ErrorPassthroughHandler 处理错误透传规则的 HTTP 请求
type ErrorPassthroughHandler struct {
service *service.ErrorPassthroughService
}
// NewErrorPassthroughHandler 创建错误透传规则处理器
func NewErrorPassthroughHandler(service *service.ErrorPassthroughService) *ErrorPassthroughHandler {
return &ErrorPassthroughHandler{service: service}
}
// CreateErrorPassthroughRuleRequest 创建规则请求
type CreateErrorPassthroughRuleRequest struct {
Name string `json:"name" binding:"required"`
Enabled *bool `json:"enabled"`
Priority int `json:"priority"`
ErrorCodes []int `json:"error_codes"`
Keywords []string `json:"keywords"`
MatchMode string `json:"match_mode"`
Platforms []string `json:"platforms"`
PassthroughCode *bool `json:"passthrough_code"`
ResponseCode *int `json:"response_code"`
PassthroughBody *bool `json:"passthrough_body"`
CustomMessage *string `json:"custom_message"`
Description *string `json:"description"`
}
// UpdateErrorPassthroughRuleRequest 更新规则请求(部分更新,所有字段可选)
type UpdateErrorPassthroughRuleRequest struct {
Name *string `json:"name"`
Enabled *bool `json:"enabled"`
Priority *int `json:"priority"`
ErrorCodes []int `json:"error_codes"`
Keywords []string `json:"keywords"`
MatchMode *string `json:"match_mode"`
Platforms []string `json:"platforms"`
PassthroughCode *bool `json:"passthrough_code"`
ResponseCode *int `json:"response_code"`
PassthroughBody *bool `json:"passthrough_body"`
CustomMessage *string `json:"custom_message"`
Description *string `json:"description"`
}
// List 获取所有规则
// GET /api/v1/admin/error-passthrough-rules
func (h *ErrorPassthroughHandler) List(c *gin.Context) {
rules, err := h.service.List(c.Request.Context())
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Success(c, rules)
}
// GetByID 根据 ID 获取规则
// GET /api/v1/admin/error-passthrough-rules/:id
func (h *ErrorPassthroughHandler) GetByID(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequest(c, "Invalid rule ID")
return
}
rule, err := h.service.GetByID(c.Request.Context(), id)
if err != nil {
response.ErrorFrom(c, err)
return
}
if rule == nil {
response.NotFound(c, "Rule not found")
return
}
response.Success(c, rule)
}
// Create 创建规则
// POST /api/v1/admin/error-passthrough-rules
func (h *ErrorPassthroughHandler) Create(c *gin.Context) {
var req CreateErrorPassthroughRuleRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error())
return
}
rule := &model.ErrorPassthroughRule{
Name: req.Name,
Priority: req.Priority,
ErrorCodes: req.ErrorCodes,
Keywords: req.Keywords,
Platforms: req.Platforms,
}
// 设置默认值
if req.Enabled != nil {
rule.Enabled = *req.Enabled
} else {
rule.Enabled = true
}
if req.MatchMode != "" {
rule.MatchMode = req.MatchMode
} else {
rule.MatchMode = model.MatchModeAny
}
if req.PassthroughCode != nil {
rule.PassthroughCode = *req.PassthroughCode
} else {
rule.PassthroughCode = true
}
if req.PassthroughBody != nil {
rule.PassthroughBody = *req.PassthroughBody
} else {
rule.PassthroughBody = true
}
rule.ResponseCode = req.ResponseCode
rule.CustomMessage = req.CustomMessage
rule.Description = req.Description
// 确保切片不为 nil
if rule.ErrorCodes == nil {
rule.ErrorCodes = []int{}
}
if rule.Keywords == nil {
rule.Keywords = []string{}
}
if rule.Platforms == nil {
rule.Platforms = []string{}
}
created, err := h.service.Create(c.Request.Context(), rule)
if err != nil {
if _, ok := err.(*model.ValidationError); ok {
response.BadRequest(c, err.Error())
return
}
response.ErrorFrom(c, err)
return
}
response.Success(c, created)
}
// Update 更新规则(支持部分更新)
// PUT /api/v1/admin/error-passthrough-rules/:id
func (h *ErrorPassthroughHandler) Update(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequest(c, "Invalid rule ID")
return
}
var req UpdateErrorPassthroughRuleRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "Invalid request: "+err.Error())
return
}
// 先获取现有规则
existing, err := h.service.GetByID(c.Request.Context(), id)
if err != nil {
response.ErrorFrom(c, err)
return
}
if existing == nil {
response.NotFound(c, "Rule not found")
return
}
// 部分更新:只更新请求中提供的字段
rule := &model.ErrorPassthroughRule{
ID: id,
Name: existing.Name,
Enabled: existing.Enabled,
Priority: existing.Priority,
ErrorCodes: existing.ErrorCodes,
Keywords: existing.Keywords,
MatchMode: existing.MatchMode,
Platforms: existing.Platforms,
PassthroughCode: existing.PassthroughCode,
ResponseCode: existing.ResponseCode,
PassthroughBody: existing.PassthroughBody,
CustomMessage: existing.CustomMessage,
Description: existing.Description,
}
// 应用请求中提供的更新
if req.Name != nil {
rule.Name = *req.Name
}
if req.Enabled != nil {
rule.Enabled = *req.Enabled
}
if req.Priority != nil {
rule.Priority = *req.Priority
}
if req.ErrorCodes != nil {
rule.ErrorCodes = req.ErrorCodes
}
if req.Keywords != nil {
rule.Keywords = req.Keywords
}
if req.MatchMode != nil {
rule.MatchMode = *req.MatchMode
}
if req.Platforms != nil {
rule.Platforms = req.Platforms
}
if req.PassthroughCode != nil {
rule.PassthroughCode = *req.PassthroughCode
}
if req.ResponseCode != nil {
rule.ResponseCode = req.ResponseCode
}
if req.PassthroughBody != nil {
rule.PassthroughBody = *req.PassthroughBody
}
if req.CustomMessage != nil {
rule.CustomMessage = req.CustomMessage
}
if req.Description != nil {
rule.Description = req.Description
}
// 确保切片不为 nil
if rule.ErrorCodes == nil {
rule.ErrorCodes = []int{}
}
if rule.Keywords == nil {
rule.Keywords = []string{}
}
if rule.Platforms == nil {
rule.Platforms = []string{}
}
updated, err := h.service.Update(c.Request.Context(), rule)
if err != nil {
if _, ok := err.(*model.ValidationError); ok {
response.BadRequest(c, err.Error())
return
}
response.ErrorFrom(c, err)
return
}
response.Success(c, updated)
}
// Delete 删除规则
// DELETE /api/v1/admin/error-passthrough-rules/:id
func (h *ErrorPassthroughHandler) Delete(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {
response.BadRequest(c, "Invalid rule ID")
return
}
if err := h.service.Delete(c.Request.Context(), id); err != nil {
response.ErrorFrom(c, err)
return
}
response.Success(c, gin.H{"message": "Rule deleted successfully"})
}
......@@ -45,6 +45,9 @@ type UpdateUserRequest struct {
Concurrency *int `json:"concurrency"`
Status string `json:"status" binding:"omitempty,oneof=active disabled"`
AllowedGroups *[]int64 `json:"allowed_groups"`
// GroupRates 用户专属分组倍率配置
// map[groupID]*rate,nil 表示删除该分组的专属倍率
GroupRates map[int64]*float64 `json:"group_rates"`
}
// UpdateBalanceRequest represents balance update request
......@@ -183,6 +186,7 @@ func (h *UserHandler) Update(c *gin.Context) {
Concurrency: req.Concurrency,
Status: req.Status,
AllowedGroups: req.AllowedGroups,
GroupRates: req.GroupRates,
})
if err != nil {
response.ErrorFrom(c, err)
......
......@@ -243,3 +243,21 @@ func (h *APIKeyHandler) GetAvailableGroups(c *gin.Context) {
}
response.Success(c, out)
}
// GetUserGroupRates 获取当前用户的专属分组倍率配置
// GET /api/v1/groups/rates
func (h *APIKeyHandler) GetUserGroupRates(c *gin.Context) {
subject, ok := middleware2.GetAuthSubjectFromContext(c)
if !ok {
response.Unauthorized(c, "User not authenticated")
return
}
rates, err := h.apiKeyService.GetUserGroupRates(c.Request.Context(), subject.UserID)
if err != nil {
response.ErrorFrom(c, err)
return
}
response.Success(c, rates)
}
......@@ -58,8 +58,9 @@ func UserFromServiceAdmin(u *service.User) *AdminUser {
return nil
}
return &AdminUser{
User: *base,
Notes: u.Notes,
User: *base,
Notes: u.Notes,
GroupRates: u.GroupRates,
}
}
......
......@@ -29,6 +29,9 @@ type AdminUser struct {
User
Notes string `json:"notes"`
// GroupRates 用户专属分组倍率配置
// map[groupID]rateMultiplier
GroupRates map[int64]float64 `json:"group_rates,omitempty"`
}
type APIKey struct {
......
......@@ -33,6 +33,7 @@ type GatewayHandler struct {
billingCacheService *service.BillingCacheService
usageService *service.UsageService
apiKeyService *service.APIKeyService
errorPassthroughService *service.ErrorPassthroughService
concurrencyHelper *ConcurrencyHelper
maxAccountSwitches int
maxAccountSwitchesGemini int
......@@ -48,6 +49,7 @@ func NewGatewayHandler(
billingCacheService *service.BillingCacheService,
usageService *service.UsageService,
apiKeyService *service.APIKeyService,
errorPassthroughService *service.ErrorPassthroughService,
cfg *config.Config,
) *GatewayHandler {
pingInterval := time.Duration(0)
......@@ -70,6 +72,7 @@ func NewGatewayHandler(
billingCacheService: billingCacheService,
usageService: usageService,
apiKeyService: apiKeyService,
errorPassthroughService: errorPassthroughService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatClaude, pingInterval),
maxAccountSwitches: maxAccountSwitches,
maxAccountSwitchesGemini: maxAccountSwitchesGemini,
......@@ -201,7 +204,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
maxAccountSwitches := h.maxAccountSwitchesGemini
switchCount := 0
failedAccountIDs := make(map[int64]struct{})
lastFailoverStatus := 0
var lastFailoverErr *service.UpstreamFailoverError
for {
selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), apiKey.GroupID, sessionKey, reqModel, failedAccountIDs, "") // Gemini 不使用会话限制
......@@ -210,7 +213,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted)
return
}
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
if lastFailoverErr != nil {
h.handleFailoverExhausted(c, lastFailoverErr, service.PlatformGemini, streamStarted)
} else {
h.handleFailoverExhaustedSimple(c, 502, streamStarted)
}
return
}
account := selection.Account
......@@ -301,9 +308,9 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
var failoverErr *service.UpstreamFailoverError
if errors.As(err, &failoverErr) {
failedAccountIDs[account.ID] = struct{}{}
lastFailoverStatus = failoverErr.StatusCode
lastFailoverErr = failoverErr
if switchCount >= maxAccountSwitches {
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
h.handleFailoverExhausted(c, failoverErr, service.PlatformGemini, streamStarted)
return
}
switchCount++
......@@ -352,7 +359,7 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
maxAccountSwitches := h.maxAccountSwitches
switchCount := 0
failedAccountIDs := make(map[int64]struct{})
lastFailoverStatus := 0
var lastFailoverErr *service.UpstreamFailoverError
retryWithFallback := false
for {
......@@ -363,7 +370,11 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted)
return
}
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
if lastFailoverErr != nil {
h.handleFailoverExhausted(c, lastFailoverErr, platform, streamStarted)
} else {
h.handleFailoverExhaustedSimple(c, 502, streamStarted)
}
return
}
account := selection.Account
......@@ -487,9 +498,9 @@ func (h *GatewayHandler) Messages(c *gin.Context) {
var failoverErr *service.UpstreamFailoverError
if errors.As(err, &failoverErr) {
failedAccountIDs[account.ID] = struct{}{}
lastFailoverStatus = failoverErr.StatusCode
lastFailoverErr = failoverErr
if switchCount >= maxAccountSwitches {
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
h.handleFailoverExhausted(c, failoverErr, account.Platform, streamStarted)
return
}
switchCount++
......@@ -755,7 +766,37 @@ func (h *GatewayHandler) handleConcurrencyError(c *gin.Context, err error, slotT
fmt.Sprintf("Concurrency limit exceeded for %s, please retry later", slotType), streamStarted)
}
func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, statusCode int, streamStarted bool) {
func (h *GatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *service.UpstreamFailoverError, platform string, streamStarted bool) {
statusCode := failoverErr.StatusCode
responseBody := failoverErr.ResponseBody
// 先检查透传规则
if h.errorPassthroughService != nil && len(responseBody) > 0 {
if rule := h.errorPassthroughService.MatchRule(platform, statusCode, responseBody); rule != nil {
// 确定响应状态码
respCode := statusCode
if !rule.PassthroughCode && rule.ResponseCode != nil {
respCode = *rule.ResponseCode
}
// 确定响应消息
msg := service.ExtractUpstreamErrorMessage(responseBody)
if !rule.PassthroughBody && rule.CustomMessage != nil {
msg = *rule.CustomMessage
}
h.handleStreamingAwareError(c, respCode, "upstream_error", msg, streamStarted)
return
}
}
// 使用默认的错误映射
status, errType, errMsg := h.mapUpstreamError(statusCode)
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
}
// handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况
func (h *GatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) {
status, errType, errMsg := h.mapUpstreamError(statusCode)
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
}
......
......@@ -253,7 +253,7 @@ func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) {
maxAccountSwitches := h.maxAccountSwitchesGemini
switchCount := 0
failedAccountIDs := make(map[int64]struct{})
lastFailoverStatus := 0
var lastFailoverErr *service.UpstreamFailoverError
for {
selection, err := h.gatewayService.SelectAccountWithLoadAwareness(c.Request.Context(), apiKey.GroupID, sessionKey, modelName, failedAccountIDs, "") // Gemini 不使用会话限制
......@@ -262,7 +262,7 @@ func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) {
googleError(c, http.StatusServiceUnavailable, "No available Gemini accounts: "+err.Error())
return
}
handleGeminiFailoverExhausted(c, lastFailoverStatus)
h.handleGeminiFailoverExhausted(c, lastFailoverErr)
return
}
account := selection.Account
......@@ -353,11 +353,11 @@ func (h *GatewayHandler) GeminiV1BetaModels(c *gin.Context) {
if errors.As(err, &failoverErr) {
failedAccountIDs[account.ID] = struct{}{}
if switchCount >= maxAccountSwitches {
lastFailoverStatus = failoverErr.StatusCode
handleGeminiFailoverExhausted(c, lastFailoverStatus)
lastFailoverErr = failoverErr
h.handleGeminiFailoverExhausted(c, lastFailoverErr)
return
}
lastFailoverStatus = failoverErr.StatusCode
lastFailoverErr = failoverErr
switchCount++
log.Printf("Gemini account %d: upstream error %d, switching account %d/%d", account.ID, failoverErr.StatusCode, switchCount, maxAccountSwitches)
continue
......@@ -414,7 +414,36 @@ func parseGeminiModelAction(rest string) (model string, action string, err error
return "", "", &pathParseError{"invalid model action path"}
}
func handleGeminiFailoverExhausted(c *gin.Context, statusCode int) {
func (h *GatewayHandler) handleGeminiFailoverExhausted(c *gin.Context, failoverErr *service.UpstreamFailoverError) {
if failoverErr == nil {
googleError(c, http.StatusBadGateway, "Upstream request failed")
return
}
statusCode := failoverErr.StatusCode
responseBody := failoverErr.ResponseBody
// 先检查透传规则
if h.errorPassthroughService != nil && len(responseBody) > 0 {
if rule := h.errorPassthroughService.MatchRule(service.PlatformGemini, statusCode, responseBody); rule != nil {
// 确定响应状态码
respCode := statusCode
if !rule.PassthroughCode && rule.ResponseCode != nil {
respCode = *rule.ResponseCode
}
// 确定响应消息
msg := service.ExtractUpstreamErrorMessage(responseBody)
if !rule.PassthroughBody && rule.CustomMessage != nil {
msg = *rule.CustomMessage
}
googleError(c, respCode, msg)
return
}
}
// 使用默认的错误映射
status, message := mapGeminiUpstreamError(statusCode)
googleError(c, status, message)
}
......
......@@ -24,6 +24,7 @@ type AdminHandlers struct {
Subscription *admin.SubscriptionHandler
Usage *admin.UsageHandler
UserAttribute *admin.UserAttributeHandler
ErrorPassthrough *admin.ErrorPassthroughHandler
}
// Handlers contains all HTTP handlers
......
......@@ -22,11 +22,12 @@ import (
// OpenAIGatewayHandler handles OpenAI API gateway requests
type OpenAIGatewayHandler struct {
gatewayService *service.OpenAIGatewayService
billingCacheService *service.BillingCacheService
apiKeyService *service.APIKeyService
concurrencyHelper *ConcurrencyHelper
maxAccountSwitches int
gatewayService *service.OpenAIGatewayService
billingCacheService *service.BillingCacheService
apiKeyService *service.APIKeyService
errorPassthroughService *service.ErrorPassthroughService
concurrencyHelper *ConcurrencyHelper
maxAccountSwitches int
}
// NewOpenAIGatewayHandler creates a new OpenAIGatewayHandler
......@@ -35,6 +36,7 @@ func NewOpenAIGatewayHandler(
concurrencyService *service.ConcurrencyService,
billingCacheService *service.BillingCacheService,
apiKeyService *service.APIKeyService,
errorPassthroughService *service.ErrorPassthroughService,
cfg *config.Config,
) *OpenAIGatewayHandler {
pingInterval := time.Duration(0)
......@@ -46,11 +48,12 @@ func NewOpenAIGatewayHandler(
}
}
return &OpenAIGatewayHandler{
gatewayService: gatewayService,
billingCacheService: billingCacheService,
apiKeyService: apiKeyService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatComment, pingInterval),
maxAccountSwitches: maxAccountSwitches,
gatewayService: gatewayService,
billingCacheService: billingCacheService,
apiKeyService: apiKeyService,
errorPassthroughService: errorPassthroughService,
concurrencyHelper: NewConcurrencyHelper(concurrencyService, SSEPingFormatComment, pingInterval),
maxAccountSwitches: maxAccountSwitches,
}
}
......@@ -201,7 +204,7 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
maxAccountSwitches := h.maxAccountSwitches
switchCount := 0
failedAccountIDs := make(map[int64]struct{})
lastFailoverStatus := 0
var lastFailoverErr *service.UpstreamFailoverError
for {
// Select account supporting the requested model
......@@ -213,7 +216,11 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
h.handleStreamingAwareError(c, http.StatusServiceUnavailable, "api_error", "No available accounts: "+err.Error(), streamStarted)
return
}
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
if lastFailoverErr != nil {
h.handleFailoverExhausted(c, lastFailoverErr, streamStarted)
} else {
h.handleFailoverExhaustedSimple(c, 502, streamStarted)
}
return
}
account := selection.Account
......@@ -278,12 +285,11 @@ func (h *OpenAIGatewayHandler) Responses(c *gin.Context) {
var failoverErr *service.UpstreamFailoverError
if errors.As(err, &failoverErr) {
failedAccountIDs[account.ID] = struct{}{}
lastFailoverErr = failoverErr
if switchCount >= maxAccountSwitches {
lastFailoverStatus = failoverErr.StatusCode
h.handleFailoverExhausted(c, lastFailoverStatus, streamStarted)
h.handleFailoverExhausted(c, failoverErr, streamStarted)
return
}
lastFailoverStatus = failoverErr.StatusCode
switchCount++
log.Printf("Account %d: upstream error %d, switching account %d/%d", account.ID, failoverErr.StatusCode, switchCount, maxAccountSwitches)
continue
......@@ -324,7 +330,37 @@ func (h *OpenAIGatewayHandler) handleConcurrencyError(c *gin.Context, err error,
fmt.Sprintf("Concurrency limit exceeded for %s, please retry later", slotType), streamStarted)
}
func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, statusCode int, streamStarted bool) {
func (h *OpenAIGatewayHandler) handleFailoverExhausted(c *gin.Context, failoverErr *service.UpstreamFailoverError, streamStarted bool) {
statusCode := failoverErr.StatusCode
responseBody := failoverErr.ResponseBody
// 先检查透传规则
if h.errorPassthroughService != nil && len(responseBody) > 0 {
if rule := h.errorPassthroughService.MatchRule("openai", statusCode, responseBody); rule != nil {
// 确定响应状态码
respCode := statusCode
if !rule.PassthroughCode && rule.ResponseCode != nil {
respCode = *rule.ResponseCode
}
// 确定响应消息
msg := service.ExtractUpstreamErrorMessage(responseBody)
if !rule.PassthroughBody && rule.CustomMessage != nil {
msg = *rule.CustomMessage
}
h.handleStreamingAwareError(c, respCode, "upstream_error", msg, streamStarted)
return
}
}
// 使用默认的错误映射
status, errType, errMsg := h.mapUpstreamError(statusCode)
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
}
// handleFailoverExhaustedSimple 简化版本,用于没有响应体的情况
func (h *OpenAIGatewayHandler) handleFailoverExhaustedSimple(c *gin.Context, statusCode int, streamStarted bool) {
status, errType, errMsg := h.mapUpstreamError(statusCode)
h.handleStreamingAwareError(c, status, errType, errMsg, streamStarted)
}
......
......@@ -27,6 +27,7 @@ func ProvideAdminHandlers(
subscriptionHandler *admin.SubscriptionHandler,
usageHandler *admin.UsageHandler,
userAttributeHandler *admin.UserAttributeHandler,
errorPassthroughHandler *admin.ErrorPassthroughHandler,
) *AdminHandlers {
return &AdminHandlers{
Dashboard: dashboardHandler,
......@@ -47,6 +48,7 @@ func ProvideAdminHandlers(
Subscription: subscriptionHandler,
Usage: usageHandler,
UserAttribute: userAttributeHandler,
ErrorPassthrough: errorPassthroughHandler,
}
}
......@@ -125,6 +127,7 @@ var ProviderSet = wire.NewSet(
admin.NewSubscriptionHandler,
admin.NewUsageHandler,
admin.NewUserAttributeHandler,
admin.NewErrorPassthroughHandler,
// AdminHandlers and Handlers constructors
ProvideAdminHandlers,
......
// Package model 定义服务层使用的数据模型。
package model
import "time"
// ErrorPassthroughRule 全局错误透传规则
// 用于控制上游错误如何返回给客户端
type ErrorPassthroughRule struct {
ID int64 `json:"id"`
Name string `json:"name"` // 规则名称
Enabled bool `json:"enabled"` // 是否启用
Priority int `json:"priority"` // 优先级(数字越小优先级越高)
ErrorCodes []int `json:"error_codes"` // 匹配的错误码列表(OR关系)
Keywords []string `json:"keywords"` // 匹配的关键词列表(OR关系)
MatchMode string `json:"match_mode"` // "any"(任一条件) 或 "all"(所有条件)
Platforms []string `json:"platforms"` // 适用平台列表
PassthroughCode bool `json:"passthrough_code"` // 是否透传原始状态码
ResponseCode *int `json:"response_code"` // 自定义状态码(passthrough_code=false 时使用)
PassthroughBody bool `json:"passthrough_body"` // 是否透传原始错误信息
CustomMessage *string `json:"custom_message"` // 自定义错误信息(passthrough_body=false 时使用)
Description *string `json:"description"` // 规则描述
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// MatchModeAny 表示任一条件匹配即可
const MatchModeAny = "any"
// MatchModeAll 表示所有条件都必须匹配
const MatchModeAll = "all"
// 支持的平台常量
const (
PlatformAnthropic = "anthropic"
PlatformOpenAI = "openai"
PlatformGemini = "gemini"
PlatformAntigravity = "antigravity"
)
// AllPlatforms 返回所有支持的平台列表
func AllPlatforms() []string {
return []string{PlatformAnthropic, PlatformOpenAI, PlatformGemini, PlatformAntigravity}
}
// Validate 验证规则配置的有效性
func (r *ErrorPassthroughRule) Validate() error {
if r.Name == "" {
return &ValidationError{Field: "name", Message: "name is required"}
}
if r.MatchMode != MatchModeAny && r.MatchMode != MatchModeAll {
return &ValidationError{Field: "match_mode", Message: "match_mode must be 'any' or 'all'"}
}
// 至少需要配置一个匹配条件(错误码或关键词)
if len(r.ErrorCodes) == 0 && len(r.Keywords) == 0 {
return &ValidationError{Field: "conditions", Message: "at least one error_code or keyword is required"}
}
if !r.PassthroughCode && (r.ResponseCode == nil || *r.ResponseCode <= 0) {
return &ValidationError{Field: "response_code", Message: "response_code is required when passthrough_code is false"}
}
if !r.PassthroughBody && (r.CustomMessage == nil || *r.CustomMessage == "") {
return &ValidationError{Field: "custom_message", Message: "custom_message is required when passthrough_body is false"}
}
return nil
}
// ValidationError 表示验证错误
type ValidationError struct {
Field string
Message string
}
func (e *ValidationError) Error() string {
return e.Field + ": " + e.Message
}
......@@ -71,6 +71,12 @@ var DefaultModels = []Model{
DisplayName: "Claude Opus 4.5",
CreatedAt: "2025-11-01T00:00:00Z",
},
{
ID: "claude-opus-4-6",
Type: "model",
DisplayName: "Claude Opus 4.6",
CreatedAt: "2026-02-06T00:00:00Z",
},
{
ID: "claude-sonnet-4-5-20250929",
Type: "model",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment