feat/create_new_token #2
5
go.mod
5
go.mod
|
@ -3,11 +3,10 @@ module ark-permission
|
||||||
go 1.22.3
|
go 1.22.3
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
code.30cm.net/wanderland/library-go/errors v1.0.1
|
||||||
github.com/go-playground/validator/v10 v10.22.0
|
github.com/go-playground/validator/v10 v10.22.0
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/golang/mock v1.6.0
|
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/stretchr/testify v1.9.0
|
|
||||||
github.com/zeromicro/go-zero v1.7.0
|
github.com/zeromicro/go-zero v1.7.0
|
||||||
go.uber.org/mock v0.4.0
|
go.uber.org/mock v0.4.0
|
||||||
google.golang.org/grpc v1.65.0
|
google.golang.org/grpc v1.65.0
|
||||||
|
@ -33,6 +32,7 @@ require (
|
||||||
github.com/go-playground/locales v0.14.1 // indirect
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/gnostic-models v0.6.8 // indirect
|
github.com/google/gnostic-models v0.6.8 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
|
@ -49,7 +49,6 @@ require (
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
|
||||||
github.com/prometheus/client_golang v1.19.1 // indirect
|
github.com/prometheus/client_golang v1.19.1 // indirect
|
||||||
github.com/prometheus/client_model v0.5.0 // indirect
|
github.com/prometheus/client_model v0.5.0 // indirect
|
||||||
github.com/prometheus/common v0.48.0 // indirect
|
github.com/prometheus/common v0.48.0 // indirect
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Decimal: 120314
|
||||||
|
// 12 represents Scope
|
||||||
|
// 03 represents Category
|
||||||
|
// 14 represents Detail error code
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenUnexpectedSigning = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// TokenUnexpectedSigningErr 031011
|
||||||
|
func TokenUnexpectedSigningErr(msg string) *ers.Err {
|
||||||
|
return ers.NewErr(code.CloudEPPermission, code.CatInput, code.InvalidFormat, msg)
|
||||||
|
}
|
|
@ -7,4 +7,6 @@ import (
|
||||||
|
|
||||||
type TokenRepository interface {
|
type TokenRepository interface {
|
||||||
Create(ctx context.Context, token entity.Token) error
|
Create(ctx context.Context, token entity.Token) error
|
||||||
|
GetByAccess(ctx context.Context, id string) (entity.Token, error)
|
||||||
|
Delete(ctx context.Context, token entity.Token) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
package code
|
|
||||||
|
|
||||||
const (
|
|
||||||
OK uint32 = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
// Scope
|
|
||||||
const (
|
|
||||||
Unset uint32 = iota
|
|
||||||
CloudEPPortalGW
|
|
||||||
CloudEPMember
|
|
||||||
)
|
|
||||||
|
|
||||||
// Category for general operations: 100 - 4900
|
|
||||||
const (
|
|
||||||
_ = iota
|
|
||||||
CatInput uint32 = iota * 100
|
|
||||||
CatDB
|
|
||||||
CatResource
|
|
||||||
CatGRPC
|
|
||||||
CatAuth
|
|
||||||
CatSystem
|
|
||||||
CatPubSub
|
|
||||||
)
|
|
||||||
|
|
||||||
// CatArk Category for specific app/service: 5000 - 9900
|
|
||||||
const (
|
|
||||||
CatArk uint32 = (iota + 50) * 100
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - Input 1xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatInput
|
|
||||||
InvalidFormat
|
|
||||||
NotValidImplementation
|
|
||||||
InvalidRange
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - Database 2xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatDB
|
|
||||||
DBError // general error
|
|
||||||
DBDataConvert
|
|
||||||
DBDuplicate
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - Resource 3xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatResource
|
|
||||||
ResourceNotFound
|
|
||||||
InvalidResourceFormat
|
|
||||||
ResourceAlreadyExist
|
|
||||||
ResourceInsufficient
|
|
||||||
InsufficientPermission
|
|
||||||
InvalidMeasurementID
|
|
||||||
ResourceExpired
|
|
||||||
ResourceMigrated
|
|
||||||
InvalidResourceState
|
|
||||||
InsufficientQuota
|
|
||||||
ResourceHasMultiOwner
|
|
||||||
)
|
|
||||||
|
|
||||||
/* Detail - GRPC */
|
|
||||||
// The GRPC detail code uses Go GRPC's built-in codes.
|
|
||||||
// Refer to "google.golang.org/grpc/codes" for more detail.
|
|
||||||
|
|
||||||
// Detail - Auth 5xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatAuth
|
|
||||||
Unauthorized
|
|
||||||
AuthExpired
|
|
||||||
InvalidPosixTime
|
|
||||||
SigAndPayloadNotMatched
|
|
||||||
Forbidden
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - System 6xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatSystem
|
|
||||||
SystemInternalError
|
|
||||||
SystemMaintainError
|
|
||||||
SystemTimeoutError
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - PubSub 7xx
|
|
||||||
const (
|
|
||||||
_ = iota + CatPubSub
|
|
||||||
Publish
|
|
||||||
Consume
|
|
||||||
MsgSizeTooLarge
|
|
||||||
)
|
|
||||||
|
|
||||||
// Detail - Ark 5xxx
|
|
||||||
const (
|
|
||||||
_ = iota + CatArk
|
|
||||||
ArkInternal
|
|
||||||
ArkHttp400
|
|
||||||
)
|
|
|
@ -1,13 +0,0 @@
|
||||||
package code
|
|
||||||
|
|
||||||
// CatToStr collects general error messages for each Category
|
|
||||||
// It is used to send back to API caller
|
|
||||||
var CatToStr = map[uint32]string{
|
|
||||||
CatInput: "Invalid Input Data",
|
|
||||||
CatDB: "Database Error",
|
|
||||||
CatResource: "Resource Error",
|
|
||||||
CatGRPC: "Internal Service Communication Error",
|
|
||||||
CatAuth: "Authentication Error",
|
|
||||||
CatArk: "Internal Service Communication Error",
|
|
||||||
CatSystem: "System Error",
|
|
||||||
}
|
|
|
@ -1,442 +0,0 @@
|
||||||
package error
|
|
||||||
|
|
||||||
import (
|
|
||||||
"ark-permission/internal/lib/error/code"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
_ "github.com/zeromicro/go-zero/core/logx"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
func newErr(scope, detail uint32, msg string) *Err {
|
|
||||||
cat := detail / 100 * 100
|
|
||||||
return &Err{
|
|
||||||
category: cat,
|
|
||||||
code: detail,
|
|
||||||
scope: scope,
|
|
||||||
msg: msg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBuiltinGRPCErr(scope, detail uint32, msg string) *Err {
|
|
||||||
return &Err{
|
|
||||||
category: code.CatGRPC,
|
|
||||||
code: detail,
|
|
||||||
scope: scope,
|
|
||||||
msg: msg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromError tries to let error as Err
|
|
||||||
// it supports to unwrap error that has Err
|
|
||||||
// return nil if failed to transfer
|
|
||||||
func FromError(err error) *Err {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var e *Err
|
|
||||||
if errors.As(err, &e) {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromCode parses code as following
|
|
||||||
// Decimal: 120314
|
|
||||||
// 12 represents Scope
|
|
||||||
// 03 represents Category
|
|
||||||
// 14 represents Detail error code
|
|
||||||
func FromCode(code uint32) *Err {
|
|
||||||
scope := code / 10000
|
|
||||||
detail := code % 10000
|
|
||||||
return &Err{
|
|
||||||
category: detail / 100 * 100,
|
|
||||||
code: detail,
|
|
||||||
scope: scope,
|
|
||||||
msg: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromGRPCError transfer error to Err
|
|
||||||
// useful for gRPC client
|
|
||||||
func FromGRPCError(err error) *Err {
|
|
||||||
s, _ := status.FromError(err)
|
|
||||||
e := FromCode(uint32(s.Code()))
|
|
||||||
e.msg = s.Message()
|
|
||||||
|
|
||||||
// For GRPC built-in code
|
|
||||||
if e.Scope() == code.Unset && e.Category() == 0 && e.Code() != code.OK {
|
|
||||||
e = newBuiltinGRPCErr(Scope, e.Code(), s.Message())
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: check GRPCStatus() in Errs struct
|
|
||||||
// ToGRPCError returns the status.Status
|
|
||||||
// Useful to return error in gRPC server
|
|
||||||
func ToGRPCError(e *Err) error {
|
|
||||||
return status.New(codes.Code(e.FullCode()), e.Error()).Err()
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** System ***/
|
|
||||||
|
|
||||||
// SystemTimeoutError returns Err
|
|
||||||
func SystemTimeoutError(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.SystemTimeoutError, fmt.Sprintf("system timeout: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemTimeoutErrorL logs error message and returns Err
|
|
||||||
func SystemTimeoutErrorL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := SystemTimeoutError(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemInternalError returns Err struct
|
|
||||||
func SystemInternalError(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.SystemInternalError, fmt.Sprintf("internal error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemInternalErrorL logs error message and returns Err
|
|
||||||
func SystemInternalErrorL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := SystemInternalError(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemMaintainErrorL logs error message and returns Err
|
|
||||||
func SystemMaintainErrorL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := SystemMaintainError(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemMaintainError returns Err struct
|
|
||||||
func SystemMaintainError(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.SystemMaintainError, fmt.Sprintf("service under maintenance: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatInput ***/
|
|
||||||
|
|
||||||
// InvalidFormat returns Err struct
|
|
||||||
func InvalidFormat(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidFormat, fmt.Sprintf("invalid format: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidFormatL logs error message and returns Err
|
|
||||||
func InvalidFormatL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidFormat(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidRange returns Err struct
|
|
||||||
func InvalidRange(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidRange, fmt.Sprintf("invalid range: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidRangeL logs error message and returns Err
|
|
||||||
func InvalidRangeL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidRange(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotValidImplementation returns Err struct
|
|
||||||
func NotValidImplementation(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.NotValidImplementation, fmt.Sprintf("not valid implementation: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotValidImplementationL logs error message and returns Err
|
|
||||||
func NotValidImplementationL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := NotValidImplementation(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatDB ***/
|
|
||||||
|
|
||||||
// DBError returns Err
|
|
||||||
func DBError(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.DBError, fmt.Sprintf("db error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBErrorL logs error message and returns Err
|
|
||||||
func DBErrorL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := DBError(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBDataConvert returns Err
|
|
||||||
func DBDataConvert(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.DBDataConvert, fmt.Sprintf("data from db convert error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBDataConvertL logs error message and returns Err
|
|
||||||
func DBDataConvertL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := DBDataConvert(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBDuplicate returns Err
|
|
||||||
func DBDuplicate(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.DBDuplicate, fmt.Sprintf("data Duplicate key error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DBDuplicateL logs error message and returns Err
|
|
||||||
func DBDuplicateL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := DBDuplicate(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatResource ***/
|
|
||||||
|
|
||||||
// ResourceNotFound returns Err and logging
|
|
||||||
func ResourceNotFound(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ResourceNotFound, fmt.Sprintf("resource not found: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceNotFoundL logs error message and returns Err
|
|
||||||
func ResourceNotFoundL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ResourceNotFound(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidResourceFormat returns Err
|
|
||||||
func InvalidResourceFormat(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidResourceFormat, fmt.Sprintf("invalid resource format: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidResourceFormatL logs error message and returns Err
|
|
||||||
func InvalidResourceFormatL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidResourceFormat(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidResourceState returns status not correct.
|
|
||||||
// for example: company should be destroy, agent should be no-sensor/fail-install ...
|
|
||||||
func InvalidResourceState(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidResourceState, fmt.Sprintf("invalid resource state: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidResourceStateL logs error message and returns status not correct.
|
|
||||||
func InvalidResourceStateL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidResourceState(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResourceInsufficient(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ResourceInsufficient,
|
|
||||||
fmt.Sprintf("insufficient resource: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResourceInsufficientL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ResourceInsufficient(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsufficientPermission returns Err
|
|
||||||
func InsufficientPermission(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InsufficientPermission,
|
|
||||||
fmt.Sprintf("insufficient permission: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsufficientPermissionL returns Err and log
|
|
||||||
func InsufficientPermissionL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InsufficientPermission(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceAlreadyExist returns Err
|
|
||||||
func ResourceAlreadyExist(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ResourceAlreadyExist, fmt.Sprintf("resource already exist: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceAlreadyExistL logs error message and returns Err
|
|
||||||
func ResourceAlreadyExistL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ResourceAlreadyExist(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidMeasurementID returns Err
|
|
||||||
func InvalidMeasurementID(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidMeasurementID, fmt.Sprintf("missing measurement id: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidMeasurementIDL logs error message and returns Err
|
|
||||||
func InvalidMeasurementIDL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidMeasurementID(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceExpired returns Err
|
|
||||||
func ResourceExpired(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ResourceExpired, fmt.Sprintf("resource expired: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceExpiredL logs error message and returns Err
|
|
||||||
func ResourceExpiredL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ResourceExpired(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceMigrated returns Err
|
|
||||||
func ResourceMigrated(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ResourceMigrated, fmt.Sprintf("resource migrated: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResourceMigratedL logs error message and returns Err
|
|
||||||
func ResourceMigratedL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ResourceMigrated(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsufficientQuota returns Err
|
|
||||||
func InsufficientQuota(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InsufficientQuota, fmt.Sprintf("insufficient quota: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InsufficientQuotaL logs error message and returns Err
|
|
||||||
func InsufficientQuotaL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InsufficientQuota(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatAuth ***/
|
|
||||||
|
|
||||||
// Unauthorized returns Err
|
|
||||||
func Unauthorized(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.Unauthorized, fmt.Sprintf("unauthorized: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnauthorizedL logs error message and returns Err
|
|
||||||
func UnauthorizedL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := Unauthorized(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthExpired returns Err
|
|
||||||
func AuthExpired(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.AuthExpired, fmt.Sprintf("expired: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// AuthExpiredL logs error message and returns Err
|
|
||||||
func AuthExpiredL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := AuthExpired(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidPosixTime returns Err
|
|
||||||
func InvalidPosixTime(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.InvalidPosixTime, fmt.Sprintf("invalid posix time: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// InvalidPosixTimeL logs error message and returns Err
|
|
||||||
func InvalidPosixTimeL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := InvalidPosixTime(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// SigAndPayloadNotMatched returns Err
|
|
||||||
func SigAndPayloadNotMatched(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.SigAndPayloadNotMatched, fmt.Sprintf("signature and the payload are not match: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SigAndPayloadNotMatchedL logs error message and returns Err
|
|
||||||
func SigAndPayloadNotMatchedL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := SigAndPayloadNotMatched(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forbidden returns Err
|
|
||||||
func Forbidden(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.Forbidden, fmt.Sprintf("forbidden: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForbiddenL logs error message and returns Err
|
|
||||||
func ForbiddenL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := Forbidden(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsAuthUnauthorizedError check the err is unauthorized error
|
|
||||||
func IsAuthUnauthorizedError(err *Err) bool {
|
|
||||||
switch err.Code() {
|
|
||||||
case code.Unauthorized, code.AuthExpired, code.InvalidPosixTime,
|
|
||||||
code.SigAndPayloadNotMatched, code.Forbidden,
|
|
||||||
code.InvalidFormat, code.ResourceNotFound:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatXBC ***/
|
|
||||||
|
|
||||||
// ArkInternal returns Err
|
|
||||||
func ArkInternal(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.ArkInternal, fmt.Sprintf("ark internal error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ArkInternalL logs error message and returns Err
|
|
||||||
func ArkInternalL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := ArkInternal(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
/*** CatPubSub ***/
|
|
||||||
|
|
||||||
// Publish returns Err
|
|
||||||
func Publish(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.Publish, fmt.Sprintf("publish: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// PublishL logs error message and returns Err
|
|
||||||
func PublishL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := Publish(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Consume returns Err
|
|
||||||
func Consume(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.Consume, fmt.Sprintf("consume: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MsgSizeTooLarge returns Err
|
|
||||||
func MsgSizeTooLarge(s ...string) *Err {
|
|
||||||
return newErr(Scope, code.MsgSizeTooLarge, fmt.Sprintf("kafka error: %s", strings.Join(s, " ")))
|
|
||||||
}
|
|
||||||
|
|
||||||
// MsgSizeTooLargeL logs error message and returns Err
|
|
||||||
func MsgSizeTooLargeL(l logx.Logger, s ...string) *Err {
|
|
||||||
e := MsgSizeTooLarge(s...)
|
|
||||||
l.WithCallerSkip(1).Error(e.Error())
|
|
||||||
return e
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,197 +0,0 @@
|
||||||
package error
|
|
||||||
|
|
||||||
import (
|
|
||||||
"ark-permission/internal/lib/error/code"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TODO Error要移到common 包
|
|
||||||
|
|
||||||
// Scope global variable should be set by service or module
|
|
||||||
var Scope = code.Unset
|
|
||||||
|
|
||||||
type Err struct {
|
|
||||||
category uint32
|
|
||||||
code uint32
|
|
||||||
scope uint32
|
|
||||||
msg string
|
|
||||||
internalErr error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error is the interface of error
|
|
||||||
// Getter function of private property "msg"
|
|
||||||
func (e *Err) Error() string {
|
|
||||||
if e == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// chain the error string if the internal err exists
|
|
||||||
var internalErrStr string
|
|
||||||
if e.internalErr != nil {
|
|
||||||
internalErrStr = e.internalErr.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.msg != "" {
|
|
||||||
if internalErrStr != "" {
|
|
||||||
return fmt.Sprintf("%s: %s", e.msg, internalErrStr)
|
|
||||||
}
|
|
||||||
return e.msg
|
|
||||||
}
|
|
||||||
|
|
||||||
generalErrStr := e.GeneralError()
|
|
||||||
if internalErrStr != "" {
|
|
||||||
return fmt.Sprintf("%s: %s", generalErrStr, internalErrStr)
|
|
||||||
}
|
|
||||||
return generalErrStr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Category getter function of private property "category"
|
|
||||||
func (e *Err) Category() uint32 {
|
|
||||||
if e == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return e.category
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scope getter function of private property "scope"
|
|
||||||
func (e *Err) Scope() uint32 {
|
|
||||||
if e == nil {
|
|
||||||
return code.Unset
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.scope
|
|
||||||
}
|
|
||||||
|
|
||||||
// CodeStr returns the string of error code with zero padding
|
|
||||||
func (e *Err) CodeStr() string {
|
|
||||||
if e == nil {
|
|
||||||
return "00000"
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Category() == code.CatGRPC {
|
|
||||||
return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code())
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%d%04d", e.Scope(), e.Code())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Code getter function of private property "code"
|
|
||||||
func (e *Err) Code() uint32 {
|
|
||||||
if e == nil {
|
|
||||||
return code.OK
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.code
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Err) FullCode() uint32 {
|
|
||||||
if e == nil {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
if e.Category() == code.CatGRPC {
|
|
||||||
return e.Scope()*10000 + e.Category() + e.Code()
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.Scope()*10000 + e.Code()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTPStatus returns corresponding HTTP status code
|
|
||||||
func (e *Err) HTTPStatus() int {
|
|
||||||
if e == nil || e.Code() == code.OK {
|
|
||||||
return http.StatusOK
|
|
||||||
}
|
|
||||||
// determine status code by code
|
|
||||||
switch e.Code() {
|
|
||||||
case code.ResourceInsufficient:
|
|
||||||
// 400
|
|
||||||
return http.StatusBadRequest
|
|
||||||
case code.Unauthorized, code.InsufficientPermission:
|
|
||||||
// 401
|
|
||||||
return http.StatusUnauthorized
|
|
||||||
case code.InsufficientQuota:
|
|
||||||
// 402
|
|
||||||
return http.StatusPaymentRequired
|
|
||||||
case code.InvalidPosixTime, code.Forbidden:
|
|
||||||
// 403
|
|
||||||
return http.StatusForbidden
|
|
||||||
case code.ResourceNotFound:
|
|
||||||
// 404
|
|
||||||
return http.StatusNotFound
|
|
||||||
case code.ResourceAlreadyExist, code.InvalidResourceState:
|
|
||||||
// 409
|
|
||||||
return http.StatusConflict
|
|
||||||
case code.NotValidImplementation:
|
|
||||||
// 501
|
|
||||||
return http.StatusNotImplemented
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine status code by category
|
|
||||||
switch e.Category() {
|
|
||||||
case code.CatInput:
|
|
||||||
return http.StatusBadRequest
|
|
||||||
default:
|
|
||||||
// return status code 500 if none of the condition is met
|
|
||||||
return http.StatusInternalServerError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GeneralError transform category level error message
|
|
||||||
// It's the general error message for customer/API caller
|
|
||||||
func (e *Err) GeneralError() string {
|
|
||||||
if e == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
errStr, ok := code.CatToStr[e.Category()]
|
|
||||||
if !ok {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return errStr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is called when performing errors.Is().
|
|
||||||
// DO NOT USE THIS FUNCTION DIRECTLY unless you are very certain about what you're doing.
|
|
||||||
// Use errors.Is instead.
|
|
||||||
// This function compares if two error variables are both *Err, and have the same code (without checking the wrapped internal error)
|
|
||||||
func (e *Err) Is(f error) bool {
|
|
||||||
var err *Err
|
|
||||||
ok := errors.As(f, &err)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return e.Code() == err.Code()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unwrap returns the underlying error
|
|
||||||
// The result of unwrapping an error may itself have an Unwrap method;
|
|
||||||
// we call the sequence of errors produced by repeated unwrapping the error chain.
|
|
||||||
func (e *Err) Unwrap() error {
|
|
||||||
if e == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return e.internalErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wrap sets the internal error to Err struct
|
|
||||||
func (e *Err) Wrap(internalErr error) *Err {
|
|
||||||
if e != nil {
|
|
||||||
e.internalErr = internalErr
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Err) GRPCStatus() *status.Status {
|
|
||||||
if e == nil {
|
|
||||||
return status.New(codes.OK, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
return status.New(codes.Code(e.FullCode()), e.Error())
|
|
||||||
}
|
|
|
@ -1,297 +0,0 @@
|
||||||
package error
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"member/internal/lib/error/code"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
var e *Err = nil
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, code.OK, e.Code())
|
|
||||||
assert.Equal(t, "00000", e.CodeStr())
|
|
||||||
assert.Equal(t, "", e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCode_GivenScope99DetailCode6687_ShouldReturn996687(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{scope: 99, code: 6687}
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, uint32(6687), e.Code())
|
|
||||||
assert.Equal(t, "996687", e.CodeStr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCode_GivenScope0DetailCode87_ShouldReturn87(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{scope: 0, code: 87}
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, uint32(87), e.Code())
|
|
||||||
assert.Equal(t, "00087", e.CodeStr())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFromCode_Given870005_ShouldHasScope87_Cat0_Detail5(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := FromCode(870005)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, uint32(87), e.Scope())
|
|
||||||
assert.Equal(t, uint32(0), e.Category())
|
|
||||||
assert.Equal(t, uint32(5), e.Code())
|
|
||||||
assert.Equal(t, "", e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFromCode_Given0_ShouldHasScope0_Cat0_Detail0(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := FromCode(0)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, uint32(0), e.Scope())
|
|
||||||
assert.Equal(t, uint32(0), e.Category())
|
|
||||||
assert.Equal(t, uint32(0), e.Code())
|
|
||||||
assert.Equal(t, "", e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestFromCode_Given9105_ShouldHasScope0_Cat9100_Detail9105(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := FromCode(9105)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, uint32(0), e.Scope())
|
|
||||||
assert.Equal(t, uint32(9100), e.Category())
|
|
||||||
assert.Equal(t, uint32(9105), e.Code())
|
|
||||||
assert.Equal(t, "", e.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErr_ShouldImplementErrorFunction(t *testing.T) {
|
|
||||||
// setup a func return error
|
|
||||||
f := func() error { return InvalidFormat("fake field") }
|
|
||||||
|
|
||||||
// act
|
|
||||||
err := f()
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
assert.Contains(t, fmt.Sprint(err), "fake field") // can be printed
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGeneralError_GivenNilErr_ShouldReturnEmptyString(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
var e *Err = nil
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, "", e.GeneralError())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGeneralError_GivenNotExistCat_ShouldReturnEmptyString(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{category: 123456}
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, "", e.GeneralError())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGeneralError_GivenCatDB_ShouldReturnDBError(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{category: code.CatDB}
|
|
||||||
catErrStr := code.CatToStr[code.CatDB]
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
assert.Equal(t, catErrStr, e.GeneralError())
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestError_GivenEmptyMsg_ShouldReturnCatGeneralErrorMessage(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{category: code.CatDB, msg: ""}
|
|
||||||
|
|
||||||
// act
|
|
||||||
errMsg := e.Error()
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, code.CatToStr[code.CatDB], errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestError_GivenMsg_ShouldReturnGiveMsg(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
e := Err{msg: "FAKE"}
|
|
||||||
|
|
||||||
// act
|
|
||||||
errMsg := e.Error()
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, "FAKE", errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
|
||||||
var nilErrs *Err
|
|
||||||
// act
|
|
||||||
result := errors.Is(nilErrs, DBError())
|
|
||||||
result2 := errors.Is(DBError(), nilErrs)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.False(t, result)
|
|
||||||
assert.False(t, result2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIs_GivenNil_ShouldReturnFalse(t *testing.T) {
|
|
||||||
// act
|
|
||||||
result := errors.Is(nil, DBError())
|
|
||||||
result2 := errors.Is(DBError(), nil)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.False(t, result)
|
|
||||||
assert.False(t, result2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIs_GivenNilReceiver_ShouldReturnCorrectResult(t *testing.T) {
|
|
||||||
var nilErr *Err = nil
|
|
||||||
|
|
||||||
// test 1: nilErr != DBError
|
|
||||||
var dbErr error = DBError("fake db error")
|
|
||||||
assert.False(t, nilErr.Is(dbErr))
|
|
||||||
|
|
||||||
// test 2: nilErr != nil error
|
|
||||||
var nilError error
|
|
||||||
assert.False(t, nilErr.Is(nilError))
|
|
||||||
|
|
||||||
// test 3: nilErr == another nilErr
|
|
||||||
var nilErr2 *Err = nil
|
|
||||||
assert.True(t, nilErr.Is(nilErr2))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIs_GivenDBError_ShouldReturnTrue(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
dbErr := DBError("fake db error")
|
|
||||||
|
|
||||||
// act
|
|
||||||
result := errors.Is(dbErr, DBError("not care"))
|
|
||||||
result2 := errors.Is(DBError(), dbErr)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.True(t, result)
|
|
||||||
assert.True(t, result2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIs_GivenDBErrorAssignToErrorType_ShouldReturnTrue(t *testing.T) {
|
|
||||||
// setup
|
|
||||||
var dbErr error = DBError("fake db error")
|
|
||||||
|
|
||||||
// act
|
|
||||||
result := errors.Is(dbErr, DBError("not care"))
|
|
||||||
result2 := errors.Is(DBError(), dbErr)
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.True(t, result)
|
|
||||||
assert.True(t, result2)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrap_GivenNilErr_ShouldNoPanic(t *testing.T) {
|
|
||||||
// act & assert
|
|
||||||
assert.NotPanics(t, func() {
|
|
||||||
var e *Err = nil
|
|
||||||
_ = e.Wrap(fmt.Errorf("test"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWrap_GivenErrorToWrap_ShouldReturnErrorWithWrappedError(t *testing.T) {
|
|
||||||
// act & assert
|
|
||||||
wrappedErr := fmt.Errorf("test")
|
|
||||||
wrappingErr := SystemInternalError("WrappingError").Wrap(wrappedErr)
|
|
||||||
unWrappedErr := wrappingErr.Unwrap()
|
|
||||||
|
|
||||||
assert.Equal(t, wrappedErr, unWrappedErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestUnwrap_GivenNilErr_ShouldReturnNil(t *testing.T) {
|
|
||||||
var e *Err = nil
|
|
||||||
internalErr := e.Unwrap()
|
|
||||||
assert.Nil(t, internalErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorsIs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
|
||||||
var e *Err = nil
|
|
||||||
assert.False(t, errors.Is(e, fmt.Errorf("test")))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErrorsAs_GivenNilErr_ShouldReturnFalse(t *testing.T) {
|
|
||||||
var internalErr *testErr
|
|
||||||
var e *Err = nil
|
|
||||||
assert.False(t, errors.As(e, &internalErr))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGRPCStatus(t *testing.T) {
|
|
||||||
// setup table driven tests
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
given *Err
|
|
||||||
expect *status.Status
|
|
||||||
expectConvert error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"nil errs.Err",
|
|
||||||
nil,
|
|
||||||
status.New(codes.OK, ""),
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"InvalidFormat Err",
|
|
||||||
InvalidFormat("fake"),
|
|
||||||
status.New(codes.Code(101), "invalid format: fake"),
|
|
||||||
status.New(codes.Code(101), "invalid format: fake").Err(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// act & assert
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
s := test.given.GRPCStatus()
|
|
||||||
assert.Equal(t, test.expect.Code(), s.Code())
|
|
||||||
assert.Equal(t, test.expect.Message(), s.Message())
|
|
||||||
assert.Equal(t, test.expectConvert, status.Convert(test.given).Err())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestErr_HTTPStatus(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
err *Err
|
|
||||||
want int
|
|
||||||
}{
|
|
||||||
{name: "nil error", err: nil, want: http.StatusOK},
|
|
||||||
{name: "invalid measurement id", err: &Err{category: code.CatResource, code: code.InvalidMeasurementID}, want: http.StatusInternalServerError},
|
|
||||||
{name: "resource already exists", err: &Err{category: code.CatResource, code: code.ResourceAlreadyExist}, want: http.StatusConflict},
|
|
||||||
{name: "invalid resource state", err: &Err{category: code.CatResource, code: code.InvalidResourceState}, want: http.StatusConflict},
|
|
||||||
{name: "invalid posix time", err: &Err{category: code.CatAuth, code: code.InvalidPosixTime}, want: http.StatusForbidden},
|
|
||||||
{name: "unauthorized", err: &Err{category: code.CatAuth, code: code.Unauthorized}, want: http.StatusUnauthorized},
|
|
||||||
{name: "db error", err: &Err{category: code.CatDB, code: code.DBError}, want: http.StatusInternalServerError},
|
|
||||||
{name: "insufficient permission", err: &Err{category: code.CatResource, code: code.InsufficientPermission}, want: http.StatusUnauthorized},
|
|
||||||
{name: "resource insufficient", err: &Err{category: code.CatResource, code: code.ResourceInsufficient}, want: http.StatusBadRequest},
|
|
||||||
{name: "invalid format", err: &Err{category: code.CatInput, code: code.InvalidFormat}, want: http.StatusBadRequest},
|
|
||||||
{name: "resource not found", err: &Err{code: code.ResourceNotFound}, want: http.StatusNotFound},
|
|
||||||
{name: "ok", err: &Err{code: code.OK}, want: http.StatusOK},
|
|
||||||
{name: "not valid implementation", err: &Err{category: code.CatInput, code: code.NotValidImplementation}, want: http.StatusNotImplemented},
|
|
||||||
{name: "forbidden", err: &Err{category: code.CatAuth, code: code.Forbidden}, want: http.StatusForbidden},
|
|
||||||
{name: "insufficient quota", err: &Err{category: code.CatResource, code: code.InsufficientQuota}, want: http.StatusPaymentRequired},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
|
|
||||||
// act
|
|
||||||
got := tt.err.HTTPStatus()
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assert.Equal(t, tt.want, got)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +1,9 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
"ark-permission/internal/svc"
|
"ark-permission/internal/svc"
|
||||||
|
"context"
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,9 +21,40 @@ func NewCancelTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Cance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cancelTokenReq struct {
|
||||||
|
Token string `json:"token" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
// CancelToken 取消 Token,也包含他裡面的 One Time Toke
|
||||||
func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
func (l *CancelTokenLogic) CancelToken(in *permission.CancelTokenReq) (*permission.OKResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// // 驗證所需
|
||||||
|
// if err := l.svcCtx.Validate.ValidateAll(&cancelTokenReq{
|
||||||
|
// Token: in.GetToken(),
|
||||||
|
// }); err != nil {
|
||||||
|
// return nil, ers.InvalidFormat(err.Error())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// claims, err := uc.parseClaims(accessToken)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// token, err := uc.TokenRepository.GetByAccess(ctx, claims.ID())
|
||||||
|
// if err != nil {
|
||||||
|
// if errors.Is(err, repository.ErrRecordNotFound) {
|
||||||
|
// return usecase.TokenError{Msg: "token not found"}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return usecase.InternalError{Err: fmt.Errorf("tokenRepository.GetByAccess error: %w", err)}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if err := uc.TokenRepository.Delete(ctx, token); err != nil {
|
||||||
|
// if errors.Is(err, repository.ErrRecordNotFound) {
|
||||||
|
// return nil, usecase.TokenError{Msg: "token not found"}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return nil, err
|
||||||
|
// }
|
||||||
|
|
||||||
return &permission.OKResp{}, nil
|
return &permission.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,10 @@ import (
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
"ark-permission/internal/domain"
|
"ark-permission/internal/domain"
|
||||||
"ark-permission/internal/entity"
|
"ark-permission/internal/entity"
|
||||||
ers "ark-permission/internal/lib/error"
|
|
||||||
"ark-permission/internal/svc"
|
"ark-permission/internal/svc"
|
||||||
"bytes"
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
"context"
|
"context"
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/golang-jwt/jwt/v4"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -111,30 +107,3 @@ func (l *NewTokenLogic) NewToken(in *permission.AuthorizationReq) (*permission.T
|
||||||
RefreshToken: token.RefreshToken,
|
RefreshToken: token.RefreshToken,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateAccessToken(token entity.Token, data any, sign string) (string, error) {
|
|
||||||
claim := entity.Claims{
|
|
||||||
Data: data,
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
ID: token.ID,
|
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Unix(int64(token.ExpiresIn), 0)),
|
|
||||||
Issuer: "permission",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claim).
|
|
||||||
SignedString([]byte(sign))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return accessToken, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateRefreshToken(accessToken string) string {
|
|
||||||
buf := bytes.NewBufferString(accessToken)
|
|
||||||
h := sha256.New()
|
|
||||||
_, _ = h.Write(buf.Bytes())
|
|
||||||
|
|
||||||
return hex.EncodeToString(h.Sum(nil))
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,109 +1,99 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ark-permission/gen_result/pb/permission"
|
|
||||||
"ark-permission/internal/domain"
|
|
||||||
"ark-permission/internal/entity"
|
"ark-permission/internal/entity"
|
||||||
libMock "ark-permission/internal/mock/lib"
|
|
||||||
repoMock "ark-permission/internal/mock/repository"
|
|
||||||
"ark-permission/internal/svc"
|
|
||||||
"errors"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewTokenLogic_NewToken(t *testing.T) {
|
// func TestNewTokenLogic_NewToken(t *testing.T) {
|
||||||
// mock
|
// // mock
|
||||||
ctrl := gomock.NewController(t)
|
// ctrl := gomock.NewController(t)
|
||||||
defer ctrl.Finish()
|
// defer ctrl.Finish()
|
||||||
|
//
|
||||||
tokenMockRepo := repoMock.NewMockTokenRepository(ctrl)
|
// tokenMockRepo := repoMock.NewMockTokenRepository(ctrl)
|
||||||
mockValidate := libMock.NewMockValidate(ctrl)
|
// mockValidate := libMock.NewMockValidate(ctrl)
|
||||||
|
//
|
||||||
sc := svc.ServiceContext{
|
// sc := svc.ServiceContext{
|
||||||
TokenRedisRepo: tokenMockRepo,
|
// TokenRedisRepo: tokenMockRepo,
|
||||||
Validate: mockValidate,
|
// Validate: mockValidate,
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
l := NewNewTokenLogic(context.Background(), &sc)
|
// l := NewNewTokenLogic(context.Background(), &sc)
|
||||||
|
//
|
||||||
tests := []struct {
|
// tests := []struct {
|
||||||
name string
|
// name string
|
||||||
input *permission.AuthorizationReq
|
// input *permission.AuthorizationReq
|
||||||
setupMocks func()
|
// setupMocks func()
|
||||||
expectError bool
|
// expectError bool
|
||||||
expected *permission.TokenResp
|
// expected *permission.TokenResp
|
||||||
}{
|
// }{
|
||||||
{
|
// {
|
||||||
name: "Valid token request",
|
// name: "Valid token request",
|
||||||
input: &permission.AuthorizationReq{
|
// input: &permission.AuthorizationReq{
|
||||||
GrantType: "authorization_code",
|
// GrantType: "authorization_code",
|
||||||
DeviceId: "device123",
|
// DeviceId: "device123",
|
||||||
Scope: "read",
|
// Scope: "read",
|
||||||
Expires: 3600,
|
// Expires: 3600,
|
||||||
IsRefreshToken: false,
|
// IsRefreshToken: false,
|
||||||
Data: map[string]string{
|
// Data: map[string]string{
|
||||||
"uid": "user123",
|
// "uid": "user123",
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
setupMocks: func() {
|
// setupMocks: func() {
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil)
|
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil)
|
||||||
tokenMockRepo.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil).Do(func(ctx context.Context, token entity.Token) {
|
// tokenMockRepo.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil).Do(func(ctx context.Context, token entity.Token) {
|
||||||
token.AccessToken = "access_token"
|
// token.AccessToken = "access_token"
|
||||||
})
|
// })
|
||||||
generateAccessTokenFunc = func(token entity.Token, data any, sign string) (string, error) {
|
// generateAccessTokenFunc = func(token entity.Token, data any, sign string) (string, error) {
|
||||||
return "access_token", nil
|
// return "access_token", nil
|
||||||
}
|
// }
|
||||||
generateRefreshTokenFunc = func(accessToken string) string {
|
// generateRefreshTokenFunc = func(accessToken string) string {
|
||||||
return "refresh_token"
|
// return "refresh_token"
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
expectError: false,
|
// expectError: false,
|
||||||
expected: &permission.TokenResp{
|
// expected: &permission.TokenResp{
|
||||||
AccessToken: "access_token",
|
// AccessToken: "access_token",
|
||||||
TokenType: domain.TokenTypeBearer,
|
// TokenType: domain.TokenTypeBearer,
|
||||||
ExpiresIn: 3600,
|
// ExpiresIn: 3600,
|
||||||
RefreshToken: "",
|
// RefreshToken: "",
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
{
|
// {
|
||||||
name: "Validation error",
|
// name: "Validation error",
|
||||||
input: &permission.AuthorizationReq{
|
// input: &permission.AuthorizationReq{
|
||||||
GrantType: "invalid_grant",
|
// GrantType: "invalid_grant",
|
||||||
DeviceId: "device123",
|
// DeviceId: "device123",
|
||||||
Scope: "read",
|
// Scope: "read",
|
||||||
Expires: 3600,
|
// Expires: 3600,
|
||||||
IsRefreshToken: false,
|
// IsRefreshToken: false,
|
||||||
Data: map[string]string{
|
// Data: map[string]string{
|
||||||
"uid": "user123",
|
// "uid": "user123",
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
setupMocks: func() {
|
// setupMocks: func() {
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid grant type"))
|
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid grant type"))
|
||||||
},
|
// },
|
||||||
expectError: true,
|
// expectError: true,
|
||||||
expected: nil,
|
// expected: nil,
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
for _, tt := range tests {
|
// for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
// t.Run(tt.name, func(t *testing.T) {
|
||||||
tt.setupMocks()
|
// tt.setupMocks()
|
||||||
|
//
|
||||||
resp, err := l.NewToken(tt.input)
|
// resp, err := l.NewToken(tt.input)
|
||||||
if tt.expectError {
|
// if tt.expectError {
|
||||||
assert.Error(t, err)
|
// assert.Error(t, err)
|
||||||
} else {
|
// } else {
|
||||||
assert.NoError(t, err)
|
// assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.expected, resp)
|
// assert.Equal(t, tt.expected, resp)
|
||||||
}
|
// }
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 測試 generateAccessToken 函數
|
// 測試 generateAccessToken 函數
|
||||||
func TestGenerateAccessToken(t *testing.T) {
|
func TestGenerateAccessToken(t *testing.T) {
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package logic
|
package logic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"ark-permission/internal/domain"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"ark-permission/gen_result/pb/permission"
|
"ark-permission/gen_result/pb/permission"
|
||||||
"ark-permission/internal/svc"
|
"ark-permission/internal/svc"
|
||||||
|
@ -26,6 +29,8 @@ func NewRefreshTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Refr
|
||||||
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
// RefreshToken 更新目前的token 以及裡面包含的一次性 Token
|
||||||
func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
func (l *RefreshTokenLogic) RefreshToken(in *permission.RefreshTokenReq) (*permission.RefreshTokenResp, error) {
|
||||||
// todo: add your logic here and delete this line
|
// todo: add your logic here and delete this line
|
||||||
|
e := domain.TokenUnexpectedSigningErr("gg88g88")
|
||||||
|
fmt.Printf(strconv.Itoa(int(e.Code())), e.Category(), e.Scope(), e.FullCode(), e.Error())
|
||||||
|
|
||||||
return &permission.RefreshTokenResp{}, nil
|
return &permission.RefreshTokenResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package logic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"ark-permission/internal/entity"
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func generateAccessToken(token entity.Token, data any, sign string) (string, error) {
|
||||||
|
claim := entity.Claims{
|
||||||
|
Data: data,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ID: token.ID,
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Unix(int64(token.ExpiresIn), 0)),
|
||||||
|
Issuer: "permission",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
accessToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claim).
|
||||||
|
SignedString([]byte(sign))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return accessToken, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRefreshToken(accessToken string) string {
|
||||||
|
buf := bytes.NewBufferString(accessToken)
|
||||||
|
h := sha256.New()
|
||||||
|
_, _ = h.Write(buf.Bytes())
|
||||||
|
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseClaims(accessToken string) (claims, error) {
|
||||||
|
claimMap, err := parseToken(accessToken)
|
||||||
|
if err != nil {
|
||||||
|
return claims{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
claims, ok := claimMap["data"].(map[string]string)
|
||||||
|
if ok {
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("get data from claim map error")
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseToken(accessToken string) (jwt.MapClaims, error) {
|
||||||
|
// token, err := jwt.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
// if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
// return nil, domain.TokenUnexpectedSigningErr(fmt.Sprintf("token unexpected signing method: %v", token.Header["alg"]))
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return []byte(uc.Config.CustomConfig.Token.Secret), nil
|
||||||
|
// })
|
||||||
|
//
|
||||||
|
// if err != nil {
|
||||||
|
// ers.FromCode()
|
||||||
|
// return jwt.MapClaims{}, usecase.TokenError{Msg: fmt.Sprintf("parse token error: %s token: %s", err.Error(), accessToken)}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
|
//
|
||||||
|
// if !(ok && token.Valid) {
|
||||||
|
// return jwt.MapClaims{}, usecase.TokenError{Msg: "token valid error"}
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return claims, nil
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"ark-permission/internal/domain"
|
"ark-permission/internal/domain"
|
||||||
"ark-permission/internal/domain/repository"
|
"ark-permission/internal/domain/repository"
|
||||||
"ark-permission/internal/entity"
|
"ark-permission/internal/entity"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -61,6 +63,59 @@ func (t *tokenRepository) Create(ctx context.Context, token entity.Token) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) GetByAccess(_ context.Context, id string) (entity.Token, error) {
|
||||||
|
return t.get(domain.GetAccessTokenRedisKey(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) Delete(ctx context.Context, token entity.Token) error {
|
||||||
|
err := t.store.Pipelined(func(tx redis.Pipeliner) error {
|
||||||
|
keys := []string{
|
||||||
|
domain.GetAccessTokenRedisKey(token.ID),
|
||||||
|
domain.RefreshTokenRedisKey.With(token.RefreshToken).ToString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if err := tx.Del(ctx, key).Err(); err != nil {
|
||||||
|
return fmt.Errorf("store.Del key error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.DeviceID != "" {
|
||||||
|
key := domain.DeviceTokenRedisKey.With(token.UID).ToString()
|
||||||
|
_, err := t.store.Hdel(key, token.DeviceID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("store.HDel deviceKey error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("store.Pipelined error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenRepository) get(key string) (entity.Token, error) {
|
||||||
|
body, err := t.store.Get(key)
|
||||||
|
if errors.Is(err, redis.Nil) {
|
||||||
|
return entity.Token{}, ers.ResourceNotFound("token key not found in redis", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return entity.Token{}, fmt.Errorf("store.Get tokenTag error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var token entity.Token
|
||||||
|
if err := json.Unmarshal([]byte(body), &token); err != nil {
|
||||||
|
return entity.Token{}, fmt.Errorf("json.Unmarshal token error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *tokenRepository) setToken(ctx context.Context, tx redis.Pipeliner, token entity.Token, body []byte, rTTL time.Duration) error {
|
func (t *tokenRepository) setToken(ctx context.Context, tx redis.Pipeliner, token entity.Token, body []byte, rTTL time.Duration) error {
|
||||||
err := tx.Set(ctx, domain.GetAccessTokenRedisKey(token.ID), body, rTTL).Err()
|
err := tx.Set(ctx, domain.GetAccessTokenRedisKey(token.ID), body, rTTL).Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -5,6 +5,8 @@ import (
|
||||||
"ark-permission/internal/domain/repository"
|
"ark-permission/internal/domain/repository"
|
||||||
"ark-permission/internal/lib/required"
|
"ark-permission/internal/lib/required"
|
||||||
repo "ark-permission/internal/repository"
|
repo "ark-permission/internal/repository"
|
||||||
|
ers "code.30cm.net/wanderland/library-go/errors"
|
||||||
|
"code.30cm.net/wanderland/library-go/errors/code"
|
||||||
"github.com/zeromicro/go-zero/core/stores/redis"
|
"github.com/zeromicro/go-zero/core/stores/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
ers.Scope = code.CloudEPPermission
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
|
|
|
@ -34,7 +34,7 @@ func main() {
|
||||||
})
|
})
|
||||||
defer s.Stop()
|
defer s.Stop()
|
||||||
|
|
||||||
// // 加入中間件
|
// 加入中間件
|
||||||
// s.AddUnaryInterceptors(middleware.TimeoutMiddleware)
|
// s.AddUnaryInterceptors(middleware.TimeoutMiddleware)
|
||||||
|
|
||||||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||||||
|
|
Loading…
Reference in New Issue