update cache instance and update rest proto

This commit is contained in:
Yavolte 2025-06-17 17:16:11 +08:00
parent 59c949f627
commit f5687a0094
10 changed files with 177 additions and 30 deletions

View File

@ -2,6 +2,7 @@ package auth
import ( import (
"context" "context"
"reflect"
"strings" "strings"
"git.nobla.cn/golang/aeus/metadata" "git.nobla.cn/golang/aeus/metadata"
@ -32,16 +33,7 @@ type Option func(*options)
// Parser is a jwt parser // Parser is a jwt parser
type options struct { type options struct {
allows []string allows []string
claims func() jwt.Claims claims reflect.Type
}
// WithClaims with customer claim
// If you use it in Server, f needs to return a new jwt.Claims object each time to avoid concurrent write problems
// If you use it in Client, f only needs to return a single object to provide performance
func WithClaims(f func() jwt.Claims) Option {
return func(o *options) {
o.claims = f
}
} }
// WithAllow with allow path // WithAllow with allow path
@ -54,6 +46,12 @@ func WithAllow(paths ...string) Option {
} }
} }
func WithClaims(claims reflect.Type) Option {
return func(o *options) {
o.claims = claims
}
}
// isAllowed check if the path is allowed // isAllowed check if the path is allowed
func isAllowed(uripath string, allows []string) bool { func isAllowed(uripath string, allows []string) bool {
for _, str := range allows { for _, str := range allows {
@ -70,7 +68,7 @@ func isAllowed(uripath string, allows []string) bool {
return true return true
} }
} }
return true return false
} }
// JWT auth middleware // JWT auth middleware
@ -90,21 +88,24 @@ func JWT(keyFunc jwt.Keyfunc, cbs ...Option) middleware.Middleware {
} }
} }
} }
authorizationValue, ok := md.Get(authorizationKey) token, ok := md.Get(authorizationKey)
if !ok { if !ok {
return errors.ErrAccessDenied return errors.ErrAccessDenied
} }
if !strings.HasPrefix(authorizationValue, bearerWord) { if strings.HasPrefix(token, bearerWord) {
return errors.ErrAccessDenied token = strings.TrimPrefix(token, bearerWord)
} }
var ( var (
ti *jwt.Token ti *jwt.Token
) )
authorizationToken := strings.TrimSpace(strings.TrimPrefix(authorizationValue, bearerWord)) token = strings.TrimSpace(token)
if opts.claims != nil { if opts.claims != nil {
ti, err = jwt.ParseWithClaims(authorizationToken, opts.claims(), keyFunc) if claims, ok := reflect.New(opts.claims).Interface().(jwt.Claims); ok {
} else { ti, err = jwt.ParseWithClaims(token, claims, keyFunc)
ti, err = jwt.Parse(authorizationToken, keyFunc) }
}
if ti == nil {
ti, err = jwt.Parse(token, keyFunc)
} }
if err != nil { if err != nil {
if errors.Is(err, jwt.ErrTokenMalformed) || errors.Is(err, jwt.ErrTokenUnverifiable) { if errors.Is(err, jwt.ErrTokenMalformed) || errors.Is(err, jwt.ErrTokenUnverifiable) {

8
pkg/cache/cache.go vendored
View File

@ -13,7 +13,7 @@ var (
type Cache interface { type Cache interface {
// Get gets a cached value by key. // Get gets a cached value by key.
Get(ctx context.Context, key string) (any, time.Time, error) Get(ctx context.Context, key string) (any, error)
// Put stores a key-value pair into cache. // Put stores a key-value pair into cache.
Put(ctx context.Context, key string, val any, d time.Duration) error Put(ctx context.Context, key string, val any, d time.Duration) error
// Delete removes a key from cache. // Delete removes a key from cache.
@ -22,8 +22,12 @@ type Cache interface {
String() string String() string
} }
func Default() Cache {
return std
}
// Get gets a cached value by key. // Get gets a cached value by key.
func Get(ctx context.Context, key string) (any, time.Time, error) { func Get(ctx context.Context, key string) (any, error) {
return std.Get(ctx, key) return std.Get(ctx, key)
} }

View File

@ -15,22 +15,22 @@ type memCache struct {
sync.RWMutex sync.RWMutex
} }
func (c *memCache) Get(ctx context.Context, key string) (interface{}, time.Time, error) { func (c *memCache) Get(ctx context.Context, key string) (any, error) {
c.RWMutex.RLock() c.RWMutex.RLock()
defer c.RWMutex.RUnlock() defer c.RWMutex.RUnlock()
item, found := c.items[key] item, found := c.items[key]
if !found { if !found {
return nil, time.Time{}, errors.ErrNotFound return nil, errors.ErrNotFound
} }
if item.Expired() { if item.Expired() {
return nil, time.Time{}, errors.ErrExpired return nil, errors.ErrExpired
} }
return item.Value, time.Unix(0, item.Expiration), nil return item.Value, nil
} }
func (c *memCache) Put(ctx context.Context, key string, val interface{}, d time.Duration) error { func (c *memCache) Put(ctx context.Context, key string, val any, d time.Duration) error {
var e int64 var e int64
if d == DefaultExpiration { if d == DefaultExpiration {
d = c.opts.Expiration d = c.opts.Expiration

View File

@ -4,7 +4,7 @@ import "time"
// Item represents an item stored in the cache. // Item represents an item stored in the cache.
type Item struct { type Item struct {
Value interface{} Value any
Expiration int64 Expiration int64
} }

View File

@ -6,6 +6,7 @@ const (
Invalid = 1001 //payload invalid Invalid = 1001 //payload invalid
Exists = 1002 //already exists Exists = 1002 //already exists
Unavailable = 1003 //service unavailable Unavailable = 1003 //service unavailable
Incompatible = 1004 //type incompatible
Timeout = 2001 //timeout Timeout = 2001 //timeout
Expired = 2002 //expired Expired = 2002 //expired
TokenExpired = 4002 //token expired TokenExpired = 4002 //token expired
@ -29,4 +30,5 @@ var (
ErrUnavailable = New(Unavailable, "service unavailable") ErrUnavailable = New(Unavailable, "service unavailable")
ErrNetworkUnreachable = New(NetworkUnreachable, "network unreachable") ErrNetworkUnreachable = New(NetworkUnreachable, "network unreachable")
ErrConnectionRefused = New(ConnectionRefused, "connection refused") ErrConnectionRefused = New(ConnectionRefused, "connection refused")
ErrIncompatible = New(Incompatible, "incompatible")
) )

View File

@ -31,6 +31,16 @@ type RestFieldOptions struct {
Format string `protobuf:"bytes,5,opt,name=format,proto3" json:"format,omitempty"` Format string `protobuf:"bytes,5,opt,name=format,proto3" json:"format,omitempty"`
Props string `protobuf:"bytes,6,opt,name=props,proto3" json:"props,omitempty"` Props string `protobuf:"bytes,6,opt,name=props,proto3" json:"props,omitempty"`
Rule string `protobuf:"bytes,7,opt,name=rule,proto3" json:"rule,omitempty"` Rule string `protobuf:"bytes,7,opt,name=rule,proto3" json:"rule,omitempty"`
Live string `protobuf:"bytes,8,opt,name=live,proto3" json:"live,omitempty"`
Dropdown string `protobuf:"bytes,9,opt,name=dropdown,proto3" json:"dropdown,omitempty"`
Enum string `protobuf:"bytes,10,opt,name=enum,proto3" json:"enum,omitempty"`
Match string `protobuf:"bytes,11,opt,name=match,proto3" json:"match,omitempty"`
Invisible string `protobuf:"bytes,12,opt,name=invisible,proto3" json:"invisible,omitempty"`
Tooltip string `protobuf:"bytes,13,opt,name=tooltip,proto3" json:"tooltip,omitempty"`
Uploaduri string `protobuf:"bytes,14,opt,name=uploaduri,proto3" json:"uploaduri,omitempty"`
Description string `protobuf:"bytes,15,opt,name=description,proto3" json:"description,omitempty"`
Readonly string `protobuf:"bytes,16,opt,name=readonly,proto3" json:"readonly,omitempty"`
Endofnow string `protobuf:"bytes,17,opt,name=endofnow,proto3" json:"endofnow,omitempty"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -114,6 +124,76 @@ func (x *RestFieldOptions) GetRule() string {
return "" return ""
} }
func (x *RestFieldOptions) GetLive() string {
if x != nil {
return x.Live
}
return ""
}
func (x *RestFieldOptions) GetDropdown() string {
if x != nil {
return x.Dropdown
}
return ""
}
func (x *RestFieldOptions) GetEnum() string {
if x != nil {
return x.Enum
}
return ""
}
func (x *RestFieldOptions) GetMatch() string {
if x != nil {
return x.Match
}
return ""
}
func (x *RestFieldOptions) GetInvisible() string {
if x != nil {
return x.Invisible
}
return ""
}
func (x *RestFieldOptions) GetTooltip() string {
if x != nil {
return x.Tooltip
}
return ""
}
func (x *RestFieldOptions) GetUploaduri() string {
if x != nil {
return x.Uploaduri
}
return ""
}
func (x *RestFieldOptions) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *RestFieldOptions) GetReadonly() string {
if x != nil {
return x.Readonly
}
return ""
}
func (x *RestFieldOptions) GetEndofnow() string {
if x != nil {
return x.Endofnow
}
return ""
}
type RestMessageOptions struct { type RestMessageOptions struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Table string `protobuf:"bytes,1,opt,name=table,proto3" json:"table,omitempty"` Table string `protobuf:"bytes,1,opt,name=table,proto3" json:"table,omitempty"`
@ -198,7 +278,7 @@ var File_rest_proto protoreflect.FileDescriptor
const file_rest_proto_rawDesc = "" + const file_rest_proto_rawDesc = "" +
"\n" + "\n" +
"\n" + "\n" +
"rest.proto\x12\x04aeus\x1a google/protobuf/descriptor.proto\"\xbc\x01\n" + "rest.proto\x12\x04aeus\x1a google/protobuf/descriptor.proto\"\xc6\x03\n" +
"\x10RestFieldOptions\x12\x12\n" + "\x10RestFieldOptions\x12\x12\n" +
"\x04gorm\x18\x01 \x01(\tR\x04gorm\x12\x18\n" + "\x04gorm\x18\x01 \x01(\tR\x04gorm\x12\x18\n" +
"\acomment\x18\x02 \x01(\tR\acomment\x12\x1c\n" + "\acomment\x18\x02 \x01(\tR\acomment\x12\x1c\n" +
@ -206,7 +286,18 @@ const file_rest_proto_rawDesc = "" +
"\bposition\x18\x04 \x01(\tR\bposition\x12\x16\n" + "\bposition\x18\x04 \x01(\tR\bposition\x12\x16\n" +
"\x06format\x18\x05 \x01(\tR\x06format\x12\x14\n" + "\x06format\x18\x05 \x01(\tR\x06format\x12\x14\n" +
"\x05props\x18\x06 \x01(\tR\x05props\x12\x12\n" + "\x05props\x18\x06 \x01(\tR\x05props\x12\x12\n" +
"\x04rule\x18\a \x01(\tR\x04rule\"*\n" + "\x04rule\x18\a \x01(\tR\x04rule\x12\x12\n" +
"\x04live\x18\b \x01(\tR\x04live\x12\x1a\n" +
"\bdropdown\x18\t \x01(\tR\bdropdown\x12\x12\n" +
"\x04enum\x18\n" +
" \x01(\tR\x04enum\x12\x14\n" +
"\x05match\x18\v \x01(\tR\x05match\x12\x1c\n" +
"\tinvisible\x18\f \x01(\tR\tinvisible\x12\x18\n" +
"\atooltip\x18\r \x01(\tR\atooltip\x12\x1c\n" +
"\tuploaduri\x18\x0e \x01(\tR\tuploaduri\x12 \n" +
"\vdescription\x18\x0f \x01(\tR\vdescription\x12\x1a\n" +
"\breadonly\x18\x10 \x01(\tR\breadonly\x12\x1a\n" +
"\bendofnow\x18\x11 \x01(\tR\bendofnow\"*\n" +
"\x12RestMessageOptions\x12\x14\n" + "\x12RestMessageOptions\x12\x14\n" +
"\x05table\x18\x01 \x01(\tR\x05table:M\n" + "\x05table\x18\x01 \x01(\tR\x05table:M\n" +
"\x05field\x12\x1d.google.protobuf.FieldOptions\x18\x96\x97\x03 \x01(\v2\x16.aeus.RestFieldOptionsR\x05field:O\n" + "\x05field\x12\x1d.google.protobuf.FieldOptions\x18\x96\x97\x03 \x01(\v2\x16.aeus.RestFieldOptionsR\x05field:O\n" +

View File

@ -21,6 +21,16 @@ message RestFieldOptions {
string format = 5; string format = 5;
string props = 6; string props = 6;
string rule= 7; string rule= 7;
string live = 8;
string dropdown = 9;
string enum = 10;
string match = 11;
string invisible = 12;
string tooltip = 13;
string uploaduri = 14;
string description = 15;
string readonly = 16;
string endofnow = 17;
} }
extend google.protobuf.MessageOptions { extend google.protobuf.MessageOptions {

View File

@ -104,7 +104,7 @@ func Geerate(app *types.Applicetion) (err error) {
} }
writer.Reset() writer.Reset()
} }
if err = writeFile(shortName+".go", []byte("package "+shortName)); err != nil { if err = writeFile(path.Join(shortName, shortName+".go"), []byte("package "+shortName)); err != nil {
return return
} }
err = scanDir(protoDir, "third_party", func(filename string) error { err = scanDir(protoDir, "third_party", func(filename string) error {

View File

@ -116,10 +116,39 @@ func (s *Server) notFoundHandle(ctx *gin.Context) {
ctx.JSON(http.StatusNotFound, newResponse(errors.NotFound, "Not Found", nil)) ctx.JSON(http.StatusNotFound, newResponse(errors.NotFound, "Not Found", nil))
} }
func (s *Server) CORSInterceptor() gin.HandlerFunc {
return func(c *gin.Context) {
if c.Request.Method == "OPTIONS" {
c.Writer.Header().Add("Vary", "Origin")
c.Writer.Header().Add("Vary", "Access-Control-Request-Method")
c.Writer.Header().Add("Vary", "Access-Control-Request-Headers")
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE")
h := c.Request.Header.Get("Access-Control-Request-Headers")
if h != "" {
c.Writer.Header().Set("Access-Control-Allow-Headers", h)
}
c.AbortWithStatus(204)
return
} else {
c.Writer.Header().Add("Vary", "Origin")
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
h := c.Request.Header.Get("Access-Control-Request-Headers")
if h != "" {
c.Writer.Header().Set("Access-Control-Allow-Headers", h)
}
}
c.Next()
}
}
func (s *Server) requestInterceptor() gin.HandlerFunc { func (s *Server) requestInterceptor() gin.HandlerFunc {
return func(ginCtx *gin.Context) { return func(ginCtx *gin.Context) {
ctx := ginCtx.Request.Context() ctx := ginCtx.Request.Context()
next := func(ctx context.Context) error { next := func(ctx context.Context) error {
ginCtx.Request = ginCtx.Request.WithContext(ctx)
ginCtx.Next() ginCtx.Next()
if err := ginCtx.Errors.Last(); err != nil { if err := ginCtx.Errors.Last(); err != nil {
return err.Err return err.Err
@ -139,8 +168,8 @@ func (s *Server) requestInterceptor() gin.HandlerFunc {
} }
md.Set(metadata.RequestProtocolKey, Protocol) md.Set(metadata.RequestProtocolKey, Protocol)
md.Set(metadata.RequestPathKey, ginCtx.Request.URL.Path) md.Set(metadata.RequestPathKey, ginCtx.Request.URL.Path)
md.Set("method", ginCtx.Request.Method)
ctx = metadata.NewContext(ctx, md) ctx = metadata.NewContext(ctx, md)
ginCtx.Request = ginCtx.Request.WithContext(ctx)
if err := handler(ctx); err != nil { if err := handler(ctx); err != nil {
if se, ok := err.(*errors.Error); ok { if se, ok := err.(*errors.Error); ok {
ginCtx.AbortWithStatusJSON(http.StatusInternalServerError, newResponse(se.Code, se.Message, nil)) ginCtx.AbortWithStatusJSON(http.StatusInternalServerError, newResponse(se.Code, se.Message, nil))
@ -223,6 +252,9 @@ func New(cbs ...Option) *Server {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
} }
svr.engine = gin.New(svr.opts.ginOptions...) svr.engine = gin.New(svr.opts.ginOptions...)
if svr.opts.enableCORS {
svr.engine.Use(svr.CORSInterceptor())
}
svr.engine.Use(svr.requestInterceptor()) svr.engine.Use(svr.requestInterceptor())
return svr return svr
} }

View File

@ -25,6 +25,7 @@ type (
logger logger.Logger logger logger.Logger
context context.Context context context.Context
ginOptions []gin.OptionFunc ginOptions []gin.OptionFunc
enableCORS bool
} }
HandleFunc func(ctx *Context) (err error) HandleFunc func(ctx *Context) (err error)
@ -46,6 +47,12 @@ func WithNetwork(network string) Option {
} }
} }
func WithCORS() Option {
return func(o *options) {
o.enableCORS = true
}
}
func WithAddress(address string) Option { func WithAddress(address string) Option {
return func(o *options) { return func(o *options) {
o.address = address o.address = address