Refactored the large channel manager (approx. 900 lines) into smaller, more focused files to improve maintainability and readability. Target files: - manager.go: Lifecycle and registry. - types.go: Constants and internal state types. - worker.go: Concurrency workers for message processing. - sender.go: Outbound message handling, retries, and ephemeral state. - dispatcher.go: Message bus routing. - janitor.go: Background TTL state cleanup. - http.go: Shared HTTP server and webhook setup. Co-authored-by: hobbyistlabs-coder <267281733+hobbyistlabs-coder@users.noreply.github.com>
97 lines
2.1 KiB
Go
97 lines
2.1 KiB
Go
// PicoClaw - Ultra-lightweight personal AI agent
|
|
// License: MIT
|
|
// Copyright (c) 2026 PicoClaw contributors
|
|
|
|
package channels
|
|
|
|
import (
|
|
"context"
|
|
|
|
"jane/pkg/bus"
|
|
"jane/pkg/constants"
|
|
"jane/pkg/logger"
|
|
)
|
|
|
|
func dispatchLoop[M any](
|
|
ctx context.Context,
|
|
m *Manager,
|
|
subscribe func(context.Context) (M, bool),
|
|
getChannel func(M) string,
|
|
enqueue func(context.Context, *channelWorker, M) bool,
|
|
startMsg, stopMsg, unknownMsg, noWorkerMsg string,
|
|
) {
|
|
logger.InfoC("channels", startMsg)
|
|
|
|
for {
|
|
msg, ok := subscribe(ctx)
|
|
if !ok {
|
|
logger.InfoC("channels", stopMsg)
|
|
return
|
|
}
|
|
|
|
channel := getChannel(msg)
|
|
|
|
// Silently skip internal channels
|
|
if constants.IsInternalChannel(channel) {
|
|
continue
|
|
}
|
|
|
|
m.mu.RLock()
|
|
_, exists := m.channels[channel]
|
|
w, wExists := m.workers[channel]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
logger.WarnCF("channels", unknownMsg, map[string]any{"channel": channel})
|
|
continue
|
|
}
|
|
|
|
if wExists && w != nil {
|
|
if !enqueue(ctx, w, msg) {
|
|
return
|
|
}
|
|
} else if exists {
|
|
logger.WarnCF("channels", noWorkerMsg, map[string]any{"channel": channel})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *Manager) dispatchOutbound(ctx context.Context) {
|
|
dispatchLoop(
|
|
ctx, m,
|
|
m.bus.SubscribeOutbound,
|
|
func(msg bus.OutboundMessage) string { return msg.Channel },
|
|
func(ctx context.Context, w *channelWorker, msg bus.OutboundMessage) bool {
|
|
select {
|
|
case w.queue <- msg:
|
|
return true
|
|
case <-ctx.Done():
|
|
return false
|
|
}
|
|
},
|
|
"Outbound dispatcher started",
|
|
"Outbound dispatcher stopped",
|
|
"Unknown channel for outbound message",
|
|
"Channel has no active worker, skipping message",
|
|
)
|
|
}
|
|
|
|
func (m *Manager) dispatchOutboundMedia(ctx context.Context) {
|
|
dispatchLoop(
|
|
ctx, m,
|
|
m.bus.SubscribeOutboundMedia,
|
|
func(msg bus.OutboundMediaMessage) string { return msg.Channel },
|
|
func(ctx context.Context, w *channelWorker, msg bus.OutboundMediaMessage) bool {
|
|
select {
|
|
case w.mediaQueue <- msg:
|
|
return true
|
|
case <-ctx.Done():
|
|
return false
|
|
}
|
|
},
|
|
"Outbound media dispatcher started",
|
|
"Outbound media dispatcher stopped",
|
|
"Unknown channel for outbound media message",
|
|
"Channel has no active worker, skipping media message",
|
|
)
|
|
}
|