mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2025-12-13 17:10:36 +00:00
176 lines
4.5 KiB
Go
176 lines
4.5 KiB
Go
package eventbroker
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// EventSource represents where an event originated from
|
|
type EventSource string
|
|
|
|
const (
|
|
EventSourceDatabase EventSource = "database"
|
|
EventSourceWebSocket EventSource = "websocket"
|
|
EventSourceFrontend EventSource = "frontend"
|
|
EventSourceSystem EventSource = "system"
|
|
EventSourceInternal EventSource = "internal"
|
|
)
|
|
|
|
// EventStatus represents the current state of an event
|
|
type EventStatus string
|
|
|
|
const (
|
|
EventStatusPending EventStatus = "pending"
|
|
EventStatusProcessing EventStatus = "processing"
|
|
EventStatusCompleted EventStatus = "completed"
|
|
EventStatusFailed EventStatus = "failed"
|
|
)
|
|
|
|
// Event represents a single event in the system with complete metadata
|
|
type Event struct {
|
|
// Identification
|
|
ID string `json:"id" db:"id"`
|
|
|
|
// Source & Classification
|
|
Source EventSource `json:"source" db:"source"`
|
|
Type string `json:"type" db:"type"` // Pattern: schema.entity.operation
|
|
|
|
// Status Tracking
|
|
Status EventStatus `json:"status" db:"status"`
|
|
RetryCount int `json:"retry_count" db:"retry_count"`
|
|
Error string `json:"error,omitempty" db:"error"`
|
|
|
|
// Payload
|
|
Payload json.RawMessage `json:"payload" db:"payload"`
|
|
|
|
// Context Information
|
|
UserID int `json:"user_id" db:"user_id"`
|
|
SessionID string `json:"session_id" db:"session_id"`
|
|
InstanceID string `json:"instance_id" db:"instance_id"`
|
|
|
|
// Database Context
|
|
Schema string `json:"schema" db:"schema"`
|
|
Entity string `json:"entity" db:"entity"`
|
|
Operation string `json:"operation" db:"operation"` // create, update, delete, read
|
|
|
|
// Timestamps
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
ProcessedAt *time.Time `json:"processed_at,omitempty" db:"processed_at"`
|
|
CompletedAt *time.Time `json:"completed_at,omitempty" db:"completed_at"`
|
|
|
|
// Extensibility
|
|
Metadata map[string]interface{} `json:"metadata" db:"metadata"`
|
|
}
|
|
|
|
// NewEvent creates a new event with defaults
|
|
func NewEvent(source EventSource, eventType string) *Event {
|
|
return &Event{
|
|
ID: uuid.New().String(),
|
|
Source: source,
|
|
Type: eventType,
|
|
Status: EventStatusPending,
|
|
CreatedAt: time.Now(),
|
|
Metadata: make(map[string]interface{}),
|
|
RetryCount: 0,
|
|
}
|
|
}
|
|
|
|
// EventType generates a type string from schema, entity, and operation
|
|
// Pattern: schema.entity.operation (e.g., "public.users.create")
|
|
func EventType(schema, entity, operation string) string {
|
|
return fmt.Sprintf("%s.%s.%s", schema, entity, operation)
|
|
}
|
|
|
|
// MarkProcessing marks the event as being processed
|
|
func (e *Event) MarkProcessing() {
|
|
e.Status = EventStatusProcessing
|
|
now := time.Now()
|
|
e.ProcessedAt = &now
|
|
}
|
|
|
|
// MarkCompleted marks the event as successfully completed
|
|
func (e *Event) MarkCompleted() {
|
|
e.Status = EventStatusCompleted
|
|
now := time.Now()
|
|
e.CompletedAt = &now
|
|
}
|
|
|
|
// MarkFailed marks the event as failed with an error message
|
|
func (e *Event) MarkFailed(err error) {
|
|
e.Status = EventStatusFailed
|
|
e.Error = err.Error()
|
|
now := time.Now()
|
|
e.CompletedAt = &now
|
|
}
|
|
|
|
// IncrementRetry increments the retry counter
|
|
func (e *Event) IncrementRetry() {
|
|
e.RetryCount++
|
|
}
|
|
|
|
// SetPayload sets the event payload from any value by marshaling to JSON
|
|
func (e *Event) SetPayload(v interface{}) error {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal payload: %w", err)
|
|
}
|
|
e.Payload = data
|
|
return nil
|
|
}
|
|
|
|
// GetPayload unmarshals the payload into the provided value
|
|
func (e *Event) GetPayload(v interface{}) error {
|
|
if len(e.Payload) == 0 {
|
|
return fmt.Errorf("payload is empty")
|
|
}
|
|
if err := json.Unmarshal(e.Payload, v); err != nil {
|
|
return fmt.Errorf("failed to unmarshal payload: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Clone creates a deep copy of the event
|
|
func (e *Event) Clone() *Event {
|
|
clone := *e
|
|
|
|
// Deep copy metadata
|
|
if e.Metadata != nil {
|
|
clone.Metadata = make(map[string]interface{})
|
|
for k, v := range e.Metadata {
|
|
clone.Metadata[k] = v
|
|
}
|
|
}
|
|
|
|
// Deep copy timestamps
|
|
if e.ProcessedAt != nil {
|
|
t := *e.ProcessedAt
|
|
clone.ProcessedAt = &t
|
|
}
|
|
if e.CompletedAt != nil {
|
|
t := *e.CompletedAt
|
|
clone.CompletedAt = &t
|
|
}
|
|
|
|
return &clone
|
|
}
|
|
|
|
// Validate performs basic validation on the event
|
|
func (e *Event) Validate() error {
|
|
if e.ID == "" {
|
|
return fmt.Errorf("event ID is required")
|
|
}
|
|
if e.Source == "" {
|
|
return fmt.Errorf("event source is required")
|
|
}
|
|
if e.Type == "" {
|
|
return fmt.Errorf("event type is required")
|
|
}
|
|
if e.InstanceID == "" {
|
|
return fmt.Errorf("instance ID is required")
|
|
}
|
|
return nil
|
|
}
|