feat: engine — template renderer, rule matcher, channel router
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"aiaa-notification-service/internal/cache"
|
||||
"aiaa-notification-service/internal/model"
|
||||
"aiaa-notification-service/internal/store"
|
||||
)
|
||||
|
||||
type Matcher struct {
|
||||
store *store.Store
|
||||
cache *cache.Cache
|
||||
}
|
||||
|
||||
func NewMatcher(s *store.Store, c *cache.Cache) *Matcher {
|
||||
return &Matcher{store: s, cache: c}
|
||||
}
|
||||
|
||||
func (m *Matcher) Match(ctx context.Context, sourceID int, event string) (*model.Rule, error) {
|
||||
// Try cache first
|
||||
if m.cache != nil {
|
||||
cr, err := m.cache.GetRule(ctx, sourceID, event)
|
||||
if err == nil {
|
||||
rule := &model.Rule{ID: cr.RuleID, TemplateID: cr.TemplateID, SourceID: sourceID, Event: event}
|
||||
if cr.Conditions != "" && cr.Conditions != "null" {
|
||||
raw := json.RawMessage(cr.Conditions)
|
||||
rule.Conditions = &raw
|
||||
}
|
||||
return rule, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to DB
|
||||
rule, err := m.store.GetRuleBySourceEvent(ctx, sourceID, event)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("match rule: %w", err)
|
||||
}
|
||||
|
||||
// Warm cache
|
||||
if m.cache != nil {
|
||||
tmpl, err := m.store.GetTemplate(ctx, rule.TemplateID)
|
||||
if err != nil {
|
||||
return rule, nil // rule found but template fetch failed — still return rule
|
||||
}
|
||||
cr := &cache.CachedRule{
|
||||
RuleID: rule.ID,
|
||||
TemplateID: rule.TemplateID,
|
||||
Content: tmpl.Content,
|
||||
}
|
||||
if rule.Conditions != nil {
|
||||
cr.Conditions = string(*rule.Conditions)
|
||||
}
|
||||
_ = m.cache.SetRule(ctx, sourceID, event, cr)
|
||||
}
|
||||
|
||||
return rule, nil
|
||||
}
|
||||
Reference in New Issue
Block a user