feat: implement rule engine, worker pool, event bus, and readability scraping with enhanced logging and content sanitization.

This commit is contained in:
2026-08-25 00:31:32 -07:00
parent 5ea176d5ad
commit d440728ca5
29 changed files with 2788 additions and 204 deletions
+92
View File
@@ -0,0 +1,92 @@
package events
import (
"context"
"sync"
"git.pengzhan.dev/haopengzhan/rsspipe/internal/logger"
"git.pengzhan.dev/haopengzhan/rsspipe/internal/models"
"go.uber.org/zap"
)
type EventType string
const (
EventPostCreated EventType = "on_post_created"
EventPostUpdated EventType = "on_post_updated"
EventVariantUpdated EventType = "on_variant_updated"
EventManualTrigger EventType = "manual"
)
type Event struct {
Type EventType
Entry models.FeedEntry
VariantKey string // populated when Type == EventVariantUpdated
Depth int
DirectAttrs map[string]interface{}
}
type EventHandler func(ctx context.Context, evt Event) error
type EventBus struct {
mu sync.RWMutex
subscribers map[EventType][]EventHandler
log *zap.Logger
maxDepth int
}
func NewEventBus() *EventBus {
return &EventBus{
subscribers: make(map[EventType][]EventHandler),
log: logger.Named("eventbus"),
maxDepth: 5,
}
}
func (b *EventBus) Subscribe(eventType EventType, handler EventHandler) {
b.mu.Lock()
defer b.mu.Unlock()
b.subscribers[eventType] = append(b.subscribers[eventType], handler)
}
func (b *EventBus) Publish(ctx context.Context, evt Event) {
if evt.Depth > b.maxDepth {
b.log.Warn("Event dropped: recursion depth limit exceeded",
zap.String("type", string(evt.Type)),
zap.String("entry_id", evt.Entry.ID),
zap.Int("depth", evt.Depth),
)
return
}
b.mu.RLock()
handlers := append([]EventHandler{}, b.subscribers[evt.Type]...)
wildcardHandlers := append([]EventHandler{}, b.subscribers["*"]...)
b.mu.RUnlock()
b.log.Debug("Event published",
zap.String("type", string(evt.Type)),
zap.String("entry_id", evt.Entry.ID),
zap.String("variant_key", evt.VariantKey),
zap.Int("depth", evt.Depth),
zap.Int("subscriber_count", len(handlers)+len(wildcardHandlers)),
)
allHandlers := append(handlers, wildcardHandlers...)
for _, h := range allHandlers {
go func(fn EventHandler) {
defer func() {
if r := recover(); r != nil {
b.log.Error("Event handler panic recovered", zap.Any("panic", r))
}
}()
if err := fn(ctx, evt); err != nil {
b.log.Error("Event handler error",
zap.String("type", string(evt.Type)),
zap.String("entry_id", evt.Entry.ID),
zap.Error(err),
)
}
}(h)
}
}