package bus import ( "context" "time" runtimeevents "github.com/sipeed/picoclaw/pkg/events" ) const busEventPublishTimeout = 100 * time.Millisecond type busPublishFailedPayload struct { Stream string `json:"stream"` Error string `json:"error"` } type busClosePayload struct { Drained int `json:"drained,omitempty"` } func (mb *MessageBus) publishFailure(stream string, scope runtimeevents.Scope, err error) { if mb == nil || err == nil { return } publisher, ok := mb.eventPublisher.Load().(EventPublisher) if !ok || publisher == nil { return } ctx, cancel := context.WithTimeout(context.Background(), busEventPublishTimeout) defer cancel() publisher.Publish(ctx, runtimeevents.Event{ Kind: runtimeevents.KindBusPublishFailed, Source: runtimeevents.Source{Component: "bus", Name: stream}, Scope: scope, Severity: runtimeevents.SeverityError, Payload: busPublishFailedPayload{ Stream: stream, Error: err.Error(), }, }) } func (mb *MessageBus) publishCloseEvent(kind runtimeevents.Kind, drained int) { if mb == nil { return } publisher, ok := mb.eventPublisher.Load().(EventPublisher) if !ok || publisher == nil { return } ctx, cancel := context.WithTimeout(context.Background(), busEventPublishTimeout) defer cancel() publisher.Publish(ctx, runtimeevents.Event{ Kind: kind, Source: runtimeevents.Source{Component: "bus"}, Severity: runtimeevents.SeverityInfo, Payload: busClosePayload{Drained: drained}, }) } func runtimeScopeFromInboundContext(ctx InboundContext) runtimeevents.Scope { return runtimeevents.Scope{ Channel: ctx.Channel, Account: ctx.Account, ChatID: ctx.ChatID, TopicID: ctx.TopicID, SpaceID: ctx.SpaceID, SpaceType: ctx.SpaceType, ChatType: ctx.ChatType, SenderID: ctx.SenderID, MessageID: ctx.MessageID, } } func runtimeScopeFromAudioChunk(chunk AudioChunk) runtimeevents.Scope { return runtimeevents.Scope{ Channel: chunk.Channel, ChatID: chunk.ChatID, } } func runtimeScopeFromVoiceControl(ctrl VoiceControl) runtimeevents.Scope { return runtimeevents.Scope{ ChatID: ctrl.ChatID, } }