Skip to content

Commit 70d0d66

Browse files
committed
refactor: optimize the code structure and introduce log auditing
1 parent 4bf1a19 commit 70d0d66

31 files changed

+415
-4010
lines changed

core/llm_token_ratelimit/config.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ type KeyItem struct {
8686
Time Time `json:"time" yaml:"time"`
8787
}
8888

89-
type RuleItem struct {
89+
type SpecificItem struct {
9090
Identifier Identifier `json:"identifier" yaml:"identifier"`
9191
KeyItems []*KeyItem `json:"keyItems" yaml:"keyItems"`
9292
}
@@ -332,18 +332,18 @@ func (p TokenEncoderProvider) String() string {
332332
}
333333
}
334334

335-
func (ri *RuleItem) String() string {
336-
if ri == nil {
337-
return "RuleItem{nil}"
335+
func (si *SpecificItem) String() string {
336+
if si == nil {
337+
return "SpecificItem{nil}"
338338
}
339339

340340
var sb strings.Builder
341-
sb.WriteString("RuleItem{")
342-
sb.WriteString(fmt.Sprintf("Identifier:%s", ri.Identifier.String()))
341+
sb.WriteString("SpecificItem{")
342+
sb.WriteString(fmt.Sprintf("Identifier:%s", si.Identifier.String()))
343343

344-
if len(ri.KeyItems) > 0 {
344+
if len(si.KeyItems) > 0 {
345345
sb.WriteString(", KeyItems:[")
346-
for i, item := range ri.KeyItems {
346+
for i, item := range si.KeyItems {
347347
if i > 0 {
348348
sb.WriteString(", ")
349349
}

core/llm_token_ratelimit/config_test.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -359,24 +359,24 @@ func TestKeyItem_String(t *testing.T) {
359359
}
360360
}
361361

362-
func TestRuleItem_String(t *testing.T) {
362+
func TestSpecificItem_String(t *testing.T) {
363363
tests := []struct {
364364
name string
365-
ri *RuleItem
365+
ri *SpecificItem
366366
expected string
367367
}{
368-
{"nil ruleitem", nil, "RuleItem{nil}"},
368+
{"nil specificItem", nil, "SpecificItem{nil}"},
369369
{
370370
"empty keyitems",
371-
&RuleItem{
371+
&SpecificItem{
372372
Identifier: Identifier{Type: AllIdentifier, Value: ".*"},
373373
KeyItems: []*KeyItem{},
374374
},
375-
"RuleItem{Identifier:Identifier{Type:all, Value:.*}, KeyItems:[]}",
375+
"SpecificItem{Identifier:Identifier{Type:all, Value:.*}, KeyItems:[]}",
376376
},
377377
{
378378
"single keyitem",
379-
&RuleItem{
379+
&SpecificItem{
380380
Identifier: Identifier{Type: Header, Value: "user-id"},
381381
KeyItems: []*KeyItem{
382382
{
@@ -386,11 +386,11 @@ func TestRuleItem_String(t *testing.T) {
386386
},
387387
},
388388
},
389-
"RuleItem{Identifier:Identifier{Type:header, Value:user-id}, KeyItems:[KeyItem{Key:limit1, Token:Token{Number:1000, CountStrategy:total-tokens}, Time:Time{Value:3600 second}}]}",
389+
"SpecificItem{Identifier:Identifier{Type:header, Value:user-id}, KeyItems:[KeyItem{Key:limit1, Token:Token{Number:1000, CountStrategy:total-tokens}, Time:Time{Value:3600 second}}]}",
390390
},
391391
{
392392
"multiple keyitems",
393-
&RuleItem{
393+
&SpecificItem{
394394
Identifier: Identifier{Type: Header, Value: "api-key"},
395395
KeyItems: []*KeyItem{
396396
{
@@ -405,7 +405,7 @@ func TestRuleItem_String(t *testing.T) {
405405
},
406406
},
407407
},
408-
"RuleItem{Identifier:Identifier{Type:header, Value:api-key}, KeyItems:[KeyItem{Key:limit1, Token:Token{Number:500, CountStrategy:input-tokens}, Time:Time{Value:1800 second}}, KeyItem{Key:limit2, Token:Token{Number:300, CountStrategy:output-tokens}, Time:Time{Value:3600 second}}]}",
408+
"SpecificItem{Identifier:Identifier{Type:header, Value:api-key}, KeyItems:[KeyItem{Key:limit1, Token:Token{Number:500, CountStrategy:input-tokens}, Time:Time{Value:1800 second}}, KeyItem{Key:limit2, Token:Token{Number:300, CountStrategy:output-tokens}, Time:Time{Value:3600 second}}]}",
409409
},
410410
}
411411

@@ -425,8 +425,7 @@ rules:
425425
- id: "rule1"
426426
resource: "/api/chat"
427427
strategy: fixed-window
428-
ruleName: "chat-limit"
429-
ruleItems:
428+
specificItems:
430429
- identifier:
431430
type: header
432431
value: "user-id"
@@ -478,17 +477,17 @@ errorMessage: "Rate limit exceeded"
478477
t.Errorf("Expected FixedWindow strategy, got %v", rule.Strategy)
479478
}
480479

481-
if len(rule.RuleItems) != 1 {
482-
t.Errorf("Expected 1 rule item, got %d", len(rule.RuleItems))
480+
if len(rule.SpecificItems) != 1 {
481+
t.Errorf("Expected 1 rule item, got %d", len(rule.SpecificItems))
483482
}
484483

485-
ruleItem := rule.RuleItems[0]
486-
if ruleItem.Identifier.Type != Header {
487-
t.Errorf("Expected Header identifier type, got %v", ruleItem.Identifier.Type)
484+
specificItem := rule.SpecificItems[0]
485+
if specificItem.Identifier.Type != Header {
486+
t.Errorf("Expected Header identifier type, got %v", specificItem.Identifier.Type)
488487
}
489488

490-
if len(ruleItem.KeyItems) != 2 {
491-
t.Errorf("Expected 2 key items, got %d", len(ruleItem.KeyItems))
489+
if len(specificItem.KeyItems) != 2 {
490+
t.Errorf("Expected 2 key items, got %d", len(specificItem.KeyItems))
492491
}
493492

494493
// Test Redis config
@@ -516,7 +515,7 @@ func TestYAMLUnmarshalingErrors(t *testing.T) {
516515
"invalid identifier type",
517516
`
518517
rules:
519-
- ruleItems:
518+
- specificItems:
520519
- identifier:
521520
type: invalid
522521
`,
@@ -526,7 +525,7 @@ rules:
526525
"invalid count strategy",
527526
`
528527
rules:
529-
- ruleItems:
528+
- specificItems:
530529
- keyItems:
531530
- token:
532531
countStrategy: invalid-strategy
@@ -537,7 +536,7 @@ rules:
537536
"invalid time unit",
538537
`
539538
rules:
540-
- ruleItems:
539+
- specificItems:
541540
- keyItems:
542541
- time:
543542
unit: invalid-unit
@@ -600,8 +599,8 @@ func BenchmarkToken_String(b *testing.B) {
600599
}
601600
}
602601

603-
func BenchmarkRuleItem_String(b *testing.B) {
604-
ri := &RuleItem{
602+
func BenchmarkSpecificItem_String(b *testing.B) {
603+
ri := &SpecificItem{
605604
Identifier: Identifier{Type: Header, Value: "user-id"},
606605
KeyItems: []*KeyItem{
607606
{

core/llm_token_ratelimit/constant.go

Lines changed: 9 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ package llmtokenratelimit
1616

1717
// ================================= Config ====================================
1818
const (
19-
DefaultResource string = "default-resource"
2019
DefaultResourcePattern string = ".*"
21-
DefaultRuleName string = "overall-rule"
2220
DefaultIdentifierValuePattern string = ".*"
2321
DefaultKeyPattern string = ".*"
2422

@@ -48,13 +46,13 @@ const (
4846
KeyRequestInfos string = "SentinelLLMTokenRatelimitReqInfos"
4947
KeyUsedTokenInfos string = "SentinelLLMTokenRatelimitUsedTokenInfos"
5048
KeyMatchedRules string = "SentinelLLMTokenRatelimitMatchedRules"
51-
KeyLLMPrompts string = "SentinelLLMTokenRatelimitLLMPrompts"
5249
KeyResponseHeaders string = "SentinelLLMTokenRatelimitResponseHeaders"
50+
KeyRequestID string = "SentinelLLMTokenRatelimitRequestID"
5351
)
5452

5553
// ================================= RedisRatelimitKeyFormat ==================
5654
const (
57-
RedisRatelimitKeyFormat string = "sentinel-go:llm-token-ratelimit:%s:%s:%s:%d:%s" // ruleName, strategy, identifierType, timeWindow, tokenCountStrategy
55+
RedisRatelimitKeyFormat string = "sentinel-go:llm-token-ratelimit:resource-%s:%s:%s:%d:%s" // hashedResource, strategy, identifierType, timeWindow, tokenCountStrategy
5856
)
5957

6058
// ================================= ResponseHeader ==================
@@ -67,11 +65,13 @@ const (
6765

6866
// ================================= PETAStrategy =============================
6967
const (
70-
PETANoWaiting int64 = 0
71-
PETACorrectOK int64 = 1
72-
PETASlidingWindowKeyFormat string = "{shard-%s}:sliding-window:%s" // hashTag, redisRatelimitKey
73-
PETATokenBucketKeyFormat string = "{shard-%s}:token-bucket:%s" // hashTag, redisRatelimitKey
74-
PETARandomStringLength int = 16
68+
PETANoWaiting int64 = 0
69+
PETACorrectOK int64 = 0
70+
PETACorrectUnderestimateError int64 = 1
71+
PETACorrectOverestimateError int64 = 2
72+
PETASlidingWindowKeyFormat string = "{shard-%s}:sliding-window:%s" // hashTag, redisRatelimitKey
73+
PETATokenBucketKeyFormat string = "{shard-%s}:token-bucket:%s" // hashTag, redisRatelimitKey
74+
PETARandomStringLength int = 16
7575
)
7676

7777
// ================================= Generate Random String ===================
@@ -86,108 +86,3 @@ const (
8686
const (
8787
TokenEncoderKeyFormat string = "%s:token-encoder:%s:%s" // redisRatelimitKey, provider, model
8888
)
89-
90-
// ================================= RedisKeyForbiddenChars ===================
91-
var RedisKeyForbiddenChars = map[string]string{
92-
// Control characters
93-
" ": "space",
94-
"\n": "newline",
95-
"\r": "carriage return",
96-
"\t": "tab",
97-
"\x00": "null byte",
98-
"\x01": "start of heading",
99-
"\x02": "start of text",
100-
"\x03": "end of text",
101-
"\x04": "end of transmission",
102-
"\x05": "enquiry",
103-
"\x06": "acknowledge",
104-
"\x07": "bell",
105-
"\x08": "backspace",
106-
"\x0B": "vertical tab",
107-
"\x0C": "form feed",
108-
"\x0E": "shift out",
109-
"\x0F": "shift in",
110-
"\x10": "data link escape",
111-
"\x11": "device control 1",
112-
"\x12": "device control 2",
113-
"\x13": "device control 3",
114-
"\x14": "device control 4",
115-
"\x15": "negative acknowledge",
116-
"\x16": "synchronous idle",
117-
"\x17": "end of transmission block",
118-
"\x18": "cancel",
119-
"\x19": "end of medium",
120-
"\x1A": "substitute",
121-
"\x1B": "escape",
122-
"\x1C": "file separator",
123-
"\x1D": "group separator",
124-
"\x1E": "record separator",
125-
"\x1F": "unit separator",
126-
"\x7F": "delete",
127-
128-
// Special characters that may cause issues
129-
"*": "asterisk (reserved for wildcard)",
130-
"?": "question mark (reserved for wildcard)",
131-
"[": "left bracket (reserved for character class)",
132-
"]": "right bracket (reserved for character class)",
133-
"{": "left brace (reserved for quantifier)",
134-
"}": "right brace (reserved for quantifier)",
135-
"(": "left parenthesis (reserved for grouping)",
136-
")": "right parenthesis (reserved for grouping)",
137-
"|": "pipe (reserved for alternation)",
138-
"^": "caret (reserved for start anchor)",
139-
"$": "dollar (reserved for end anchor)",
140-
"+": "plus (reserved for quantifier)",
141-
".": "dot (reserved for any character)",
142-
"\\": "backslash (reserved for escape)",
143-
"/": "forward slash (potential path separator)",
144-
145-
// Redis protocol related characters
146-
"\r\n": "CRLF sequence",
147-
148-
// Unicode control characters (partial)
149-
"\u0080": "padding character",
150-
"\u0081": "high octet preset",
151-
"\u0082": "break permitted here",
152-
"\u0083": "no break here",
153-
"\u0084": "index",
154-
"\u0085": "next line",
155-
"\u0086": "start of selected area",
156-
"\u0087": "end of selected area",
157-
"\u0088": "character tabulation set",
158-
"\u0089": "character tabulation with justification",
159-
"\u008A": "line tabulation set",
160-
"\u008B": "partial line forward",
161-
"\u008C": "partial line backward",
162-
"\u008D": "reverse line feed",
163-
"\u008E": "single shift two",
164-
"\u008F": "single shift three",
165-
"\u0090": "device control string",
166-
"\u0091": "private use one",
167-
"\u0092": "private use two",
168-
"\u0093": "set transmit state",
169-
"\u0094": "cancel character",
170-
"\u0095": "message waiting",
171-
"\u0096": "start of guarded area",
172-
"\u0097": "end of guarded area",
173-
"\u0098": "start of string",
174-
"\u0099": "single graphic character introducer",
175-
"\u009A": "single character introducer",
176-
"\u009B": "control sequence introducer",
177-
"\u009C": "string terminator",
178-
"\u009D": "operating system command",
179-
"\u009E": "privacy message",
180-
"\u009F": "application program command",
181-
182-
// Other potentially problematic characters
183-
"\"": "double quote (potential JSON escape)",
184-
"'": "single quote (potential SQL injection)",
185-
"`": "backtick (potential command injection)",
186-
"<": "less than (potential XSS)",
187-
">": "greater than (potential XSS)",
188-
"&": "ampersand (potential HTML entity)",
189-
";": "semicolon (potential command separator)",
190-
":": "colon (potential protocol separator)",
191-
"=": "equals (potential assignment)",
192-
",": "comma (potential CSV separator)",
193-
}

core/llm_token_ratelimit/context.go

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,29 +57,13 @@ func (ctx *Context) Get(key string) interface{} {
5757
return nil
5858
}
5959

60-
func extractContextFromArgs(ctx *base.EntryContext) *Context {
61-
if ctx == nil || ctx.Input == nil || ctx.Input.Args == nil {
62-
return nil
63-
}
64-
for _, arg := range ctx.Input.Args {
65-
if llmCtx, ok := arg.(*Context); ok && llmCtx != nil {
66-
return llmCtx
67-
}
68-
}
69-
return nil
70-
}
71-
72-
func extractContextFromData(ctx *base.EntryContext) *Context {
73-
if ctx == nil || ctx.Data == nil {
74-
return nil
60+
func (ctx *Context) extractArgs(entryCtx *base.EntryContext) {
61+
if ctx == nil || entryCtx == nil || entryCtx.Input == nil || entryCtx.Input.Args == nil {
62+
return
7563
}
76-
for key, value := range ctx.Data {
77-
if key != KeyContext {
78-
continue
79-
}
80-
if llmCtx, ok := value.(*Context); ok && llmCtx != nil {
81-
return llmCtx
64+
for _, arg := range entryCtx.Input.Args {
65+
if reqInfos, ok := arg.(*RequestInfos); ok && reqInfos != nil {
66+
ctx.Set(KeyRequestInfos, reqInfos)
8267
}
8368
}
84-
return nil
8569
}

0 commit comments

Comments
 (0)