You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

420 lines
14 KiB

// Package events provides domain event types and a dispatcher for the ORLY relay.
// Domain events represent significant occurrences in the system that other components
// may want to react to, enabling loose coupling between components.
package events
import (
"time"
"git.mleku.dev/mleku/nostr/encoders/event"
)
// DomainEvent is the base interface for all domain events.
type DomainEvent interface {
// OccurredAt returns when the event occurred.
OccurredAt() time.Time
// EventType returns a string identifier for the event type.
EventType() string
}
// Base provides common fields for all domain events.
type Base struct {
occurredAt time.Time
eventType string
}
// OccurredAt returns when the event occurred.
func (b Base) OccurredAt() time.Time { return b.occurredAt }
// EventType returns the event type identifier.
func (b Base) EventType() string { return b.eventType }
// newBase creates a new Base with the current time.
func newBase(eventType string) Base {
return Base{
occurredAt: time.Now(),
eventType: eventType,
}
}
// =============================================================================
// Event Storage Events
// =============================================================================
// EventSavedType is the event type for EventSaved.
const EventSavedType = "event.saved"
// EventSaved is emitted when a Nostr event is successfully saved to the database.
type EventSaved struct {
Base
Event *event.E // The saved event
Serial uint64 // The assigned serial number
IsAdmin bool // Whether the author is an admin
IsOwner bool // Whether the author is an owner
}
// NewEventSaved creates a new EventSaved domain event.
func NewEventSaved(ev *event.E, serial uint64, isAdmin, isOwner bool) *EventSaved {
return &EventSaved{
Base: newBase(EventSavedType),
Event: ev,
Serial: serial,
IsAdmin: isAdmin,
IsOwner: isOwner,
}
}
// EventDeletedType is the event type for EventDeleted.
const EventDeletedType = "event.deleted"
// EventDeleted is emitted when a Nostr event is deleted.
type EventDeleted struct {
Base
EventID []byte // The deleted event ID
DeletedBy []byte // Pubkey that requested deletion
Serial uint64 // The serial of the deleted event
}
// NewEventDeleted creates a new EventDeleted domain event.
func NewEventDeleted(eventID, deletedBy []byte, serial uint64) *EventDeleted {
return &EventDeleted{
Base: newBase(EventDeletedType),
EventID: eventID,
DeletedBy: deletedBy,
Serial: serial,
}
}
// =============================================================================
// ACL Events
// =============================================================================
// FollowListUpdatedType is the event type for FollowListUpdated.
const FollowListUpdatedType = "acl.followlist.updated"
// FollowListUpdated is emitted when an admin's follow list changes.
type FollowListUpdated struct {
Base
AdminPubkey []byte // The admin whose follow list changed
AddedFollows [][]byte // Pubkeys that were added
RemovedFollows [][]byte // Pubkeys that were removed
}
// NewFollowListUpdated creates a new FollowListUpdated domain event.
func NewFollowListUpdated(adminPubkey []byte, added, removed [][]byte) *FollowListUpdated {
return &FollowListUpdated{
Base: newBase(FollowListUpdatedType),
AdminPubkey: adminPubkey,
AddedFollows: added,
RemovedFollows: removed,
}
}
// ACLMembershipChangedType is the event type for ACLMembershipChanged.
const ACLMembershipChangedType = "acl.membership.changed"
// ACLMembershipChanged is emitted when a pubkey's access level changes.
type ACLMembershipChanged struct {
Base
Pubkey []byte // The affected pubkey
PrevLevel string // Previous access level
NewLevel string // New access level
Reason string // Reason for the change
}
// NewACLMembershipChanged creates a new ACLMembershipChanged domain event.
func NewACLMembershipChanged(pubkey []byte, prevLevel, newLevel, reason string) *ACLMembershipChanged {
return &ACLMembershipChanged{
Base: newBase(ACLMembershipChangedType),
Pubkey: pubkey,
PrevLevel: prevLevel,
NewLevel: newLevel,
Reason: reason,
}
}
// =============================================================================
// Policy Events
// =============================================================================
// PolicyConfigUpdatedType is the event type for PolicyConfigUpdated.
const PolicyConfigUpdatedType = "policy.config.updated"
// PolicyConfigUpdated is emitted when the policy configuration changes.
type PolicyConfigUpdated struct {
Base
UpdatedBy []byte // Pubkey that made the update
Changes map[string]interface{} // Changed configuration keys
}
// NewPolicyConfigUpdated creates a new PolicyConfigUpdated domain event.
func NewPolicyConfigUpdated(updatedBy []byte, changes map[string]interface{}) *PolicyConfigUpdated {
return &PolicyConfigUpdated{
Base: newBase(PolicyConfigUpdatedType),
UpdatedBy: updatedBy,
Changes: changes,
}
}
// PolicyFollowsUpdatedType is the event type for PolicyFollowsUpdated.
const PolicyFollowsUpdatedType = "policy.follows.updated"
// PolicyFollowsUpdated is emitted when policy follow lists are refreshed.
type PolicyFollowsUpdated struct {
Base
AdminPubkey []byte // The admin whose follows were processed
FollowCount int // Number of follows in the updated list
Follows [][]byte // The follow pubkeys (may be nil for large lists)
}
// NewPolicyFollowsUpdated creates a new PolicyFollowsUpdated domain event.
func NewPolicyFollowsUpdated(adminPubkey []byte, followCount int, follows [][]byte) *PolicyFollowsUpdated {
return &PolicyFollowsUpdated{
Base: newBase(PolicyFollowsUpdatedType),
AdminPubkey: adminPubkey,
FollowCount: followCount,
Follows: follows,
}
}
// =============================================================================
// Sync Events
// =============================================================================
// RelayGroupConfigChangedType is the event type for RelayGroupConfigChanged.
const RelayGroupConfigChangedType = "sync.relaygroup.changed"
// RelayGroupConfigChanged is emitted when relay group configuration changes.
type RelayGroupConfigChanged struct {
Base
Event *event.E // The kind 39105 event
}
// NewRelayGroupConfigChanged creates a new RelayGroupConfigChanged domain event.
func NewRelayGroupConfigChanged(ev *event.E) *RelayGroupConfigChanged {
return &RelayGroupConfigChanged{
Base: newBase(RelayGroupConfigChangedType),
Event: ev,
}
}
// ClusterMembershipChangedType is the event type for ClusterMembershipChanged.
const ClusterMembershipChangedType = "sync.cluster.membership.changed"
// ClusterMembershipChanged is emitted when cluster membership changes.
type ClusterMembershipChanged struct {
Base
Event *event.E // The kind 39108 event
Action string // "join" or "leave"
}
// NewClusterMembershipChanged creates a new ClusterMembershipChanged domain event.
func NewClusterMembershipChanged(ev *event.E, action string) *ClusterMembershipChanged {
return &ClusterMembershipChanged{
Base: newBase(ClusterMembershipChangedType),
Event: ev,
Action: action,
}
}
// SyncSerialUpdatedType is the event type for SyncSerialUpdated.
const SyncSerialUpdatedType = "sync.serial.updated"
// SyncSerialUpdated is emitted when the sync manager's serial is updated.
type SyncSerialUpdated struct {
Base
Serial uint64 // The new serial number
}
// NewSyncSerialUpdated creates a new SyncSerialUpdated domain event.
func NewSyncSerialUpdated(serial uint64) *SyncSerialUpdated {
return &SyncSerialUpdated{
Base: newBase(SyncSerialUpdatedType),
Serial: serial,
}
}
// =============================================================================
// Authentication Events
// =============================================================================
// UserAuthenticatedType is the event type for UserAuthenticated.
const UserAuthenticatedType = "auth.user.authenticated"
// UserAuthenticated is emitted when a user successfully authenticates.
type UserAuthenticated struct {
Base
Pubkey []byte // The authenticated pubkey
AccessLevel string // The granted access level
IsFirstTime bool // Whether this is a first-time user
ConnectionID string // The connection ID
}
// NewUserAuthenticated creates a new UserAuthenticated domain event.
func NewUserAuthenticated(pubkey []byte, accessLevel string, isFirstTime bool, connID string) *UserAuthenticated {
return &UserAuthenticated{
Base: newBase(UserAuthenticatedType),
Pubkey: pubkey,
AccessLevel: accessLevel,
IsFirstTime: isFirstTime,
ConnectionID: connID,
}
}
// =============================================================================
// Connection Events
// =============================================================================
// ConnectionOpenedType is the event type for ConnectionOpened.
const ConnectionOpenedType = "connection.opened"
// ConnectionOpened is emitted when a new WebSocket connection is established.
type ConnectionOpened struct {
Base
ConnectionID string // Unique connection identifier
RemoteAddr string // Client IP:port
}
// NewConnectionOpened creates a new ConnectionOpened domain event.
func NewConnectionOpened(connID, remoteAddr string) *ConnectionOpened {
return &ConnectionOpened{
Base: newBase(ConnectionOpenedType),
ConnectionID: connID,
RemoteAddr: remoteAddr,
}
}
// ConnectionClosedType is the event type for ConnectionClosed.
const ConnectionClosedType = "connection.closed"
// ConnectionClosed is emitted when a WebSocket connection is closed.
type ConnectionClosed struct {
Base
ConnectionID string // Unique connection identifier
Duration time.Duration // How long the connection was open
EventsReceived int // Number of events received
EventsPublished int // Number of events published
}
// NewConnectionClosed creates a new ConnectionClosed domain event.
func NewConnectionClosed(connID string, duration time.Duration, received, published int) *ConnectionClosed {
return &ConnectionClosed{
Base: newBase(ConnectionClosedType),
ConnectionID: connID,
Duration: duration,
EventsReceived: received,
EventsPublished: published,
}
}
// =============================================================================
// Subscription Events
// =============================================================================
// SubscriptionCreatedType is the event type for SubscriptionCreated.
const SubscriptionCreatedType = "subscription.created"
// SubscriptionCreated is emitted when a new REQ subscription is created.
type SubscriptionCreated struct {
Base
SubscriptionID string // The subscription ID from REQ
ConnectionID string // The connection this subscription belongs to
FilterCount int // Number of filters in the subscription
}
// NewSubscriptionCreated creates a new SubscriptionCreated domain event.
func NewSubscriptionCreated(subID, connID string, filterCount int) *SubscriptionCreated {
return &SubscriptionCreated{
Base: newBase(SubscriptionCreatedType),
SubscriptionID: subID,
ConnectionID: connID,
FilterCount: filterCount,
}
}
// SubscriptionClosedType is the event type for SubscriptionClosed.
const SubscriptionClosedType = "subscription.closed"
// SubscriptionClosed is emitted when a subscription is closed.
type SubscriptionClosed struct {
Base
SubscriptionID string // The subscription ID
ConnectionID string // The connection this subscription belonged to
EventsMatched int // Number of events that matched this subscription
}
// NewSubscriptionClosed creates a new SubscriptionClosed domain event.
func NewSubscriptionClosed(subID, connID string, eventsMatched int) *SubscriptionClosed {
return &SubscriptionClosed{
Base: newBase(SubscriptionClosedType),
SubscriptionID: subID,
ConnectionID: connID,
EventsMatched: eventsMatched,
}
}
// =============================================================================
// NIP-43 Events
// =============================================================================
// MemberJoinedType is the event type for MemberJoined.
const MemberJoinedType = "nip43.member.joined"
// MemberJoined is emitted when a new member joins via NIP-43.
type MemberJoined struct {
Base
Pubkey []byte // The new member's pubkey
InviteCode string // The invite code used (if any)
}
// NewMemberJoined creates a new MemberJoined domain event.
func NewMemberJoined(pubkey []byte, inviteCode string) *MemberJoined {
return &MemberJoined{
Base: newBase(MemberJoinedType),
Pubkey: pubkey,
InviteCode: inviteCode,
}
}
// MemberLeftType is the event type for MemberLeft.
const MemberLeftType = "nip43.member.left"
// MemberLeft is emitted when a member leaves via NIP-43.
type MemberLeft struct {
Base
Pubkey []byte // The departed member's pubkey
}
// NewMemberLeft creates a new MemberLeft domain event.
func NewMemberLeft(pubkey []byte) *MemberLeft {
return &MemberLeft{
Base: newBase(MemberLeftType),
Pubkey: pubkey,
}
}
// =============================================================================
// Event Type Registry
// =============================================================================
// AllEventTypes returns all registered event type constants.
func AllEventTypes() []string {
return []string{
EventSavedType,
EventDeletedType,
FollowListUpdatedType,
ACLMembershipChangedType,
PolicyConfigUpdatedType,
PolicyFollowsUpdatedType,
RelayGroupConfigChangedType,
ClusterMembershipChangedType,
SyncSerialUpdatedType,
UserAuthenticatedType,
ConnectionOpenedType,
ConnectionClosedType,
SubscriptionCreatedType,
SubscriptionClosedType,
MemberJoinedType,
MemberLeftType,
}
}