diff options
| author | Dax Raad <[email protected]> | 2025-05-30 20:47:56 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-05-30 20:48:36 -0400 |
| commit | f3da73553c45f17e04b1e77cb13eb0fca714d1bd (patch) | |
| tree | a24317a19e1ab2a89da50db669dc6894f15d00d1 /packages/tui/internal/status | |
| parent | 9a26b3058ffc1023e5c7e54b6d571c903d15888e (diff) | |
| download | opencode-f3da73553c45f17e04b1e77cb13eb0fca714d1bd.tar.gz opencode-f3da73553c45f17e04b1e77cb13eb0fca714d1bd.zip | |
sync
Diffstat (limited to 'packages/tui/internal/status')
| -rw-r--r-- | packages/tui/internal/status/status.go | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/packages/tui/internal/status/status.go b/packages/tui/internal/status/status.go new file mode 100644 index 000000000..3648a64ae --- /dev/null +++ b/packages/tui/internal/status/status.go @@ -0,0 +1,142 @@ +package status + +import ( + "context" + "fmt" + "log/slog" + "sync" + "time" + + "github.com/sst/opencode/internal/pubsub" +) + +type Level string + +const ( + LevelInfo Level = "info" + LevelWarn Level = "warn" + LevelError Level = "error" + LevelDebug Level = "debug" +) + +type StatusMessage struct { + Level Level `json:"level"` + Message string `json:"message"` + Timestamp time.Time `json:"timestamp"` + Critical bool `json:"critical"` + Duration time.Duration `json:"duration"` +} + +// StatusOption is a function that configures a status message +type StatusOption func(*StatusMessage) + +// WithCritical marks a status message as critical, causing it to be displayed immediately +func WithCritical(critical bool) StatusOption { + return func(msg *StatusMessage) { + msg.Critical = critical + } +} + +// WithDuration sets a custom display duration for a status message +func WithDuration(duration time.Duration) StatusOption { + return func(msg *StatusMessage) { + msg.Duration = duration + } +} + +const ( + EventStatusPublished pubsub.EventType = "status_published" +) + +type Service interface { + pubsub.Subscriber[StatusMessage] + + Info(message string, opts ...StatusOption) + Warn(message string, opts ...StatusOption) + Error(message string, opts ...StatusOption) + Debug(message string, opts ...StatusOption) +} + +type service struct { + broker *pubsub.Broker[StatusMessage] + mu sync.RWMutex +} + +var globalStatusService *service + +func InitService() error { + if globalStatusService != nil { + return fmt.Errorf("status service already initialized") + } + broker := pubsub.NewBroker[StatusMessage]() + globalStatusService = &service{ + broker: broker, + } + return nil +} + +func GetService() Service { + if globalStatusService == nil { + panic("status service not initialized. Call status.InitService() at application startup.") + } + return globalStatusService +} + +func (s *service) Info(message string, opts ...StatusOption) { + s.publish(LevelInfo, message, opts...) + slog.Info(message) +} + +func (s *service) Warn(message string, opts ...StatusOption) { + s.publish(LevelWarn, message, opts...) + slog.Warn(message) +} + +func (s *service) Error(message string, opts ...StatusOption) { + s.publish(LevelError, message, opts...) + slog.Error(message) +} + +func (s *service) Debug(message string, opts ...StatusOption) { + s.publish(LevelDebug, message, opts...) + slog.Debug(message) +} + +func (s *service) publish(level Level, messageText string, opts ...StatusOption) { + statusMsg := StatusMessage{ + Level: level, + Message: messageText, + Timestamp: time.Now(), + } + + // Apply all options + for _, opt := range opts { + opt(&statusMsg) + } + + s.broker.Publish(EventStatusPublished, statusMsg) +} + +func (s *service) Subscribe(ctx context.Context) <-chan pubsub.Event[StatusMessage] { + return s.broker.Subscribe(ctx) +} + +func Info(message string, opts ...StatusOption) { + GetService().Info(message, opts...) +} + +func Warn(message string, opts ...StatusOption) { + GetService().Warn(message, opts...) +} + +func Error(message string, opts ...StatusOption) { + GetService().Error(message, opts...) +} + +func Debug(message string, opts ...StatusOption) { + GetService().Debug(message, opts...) +} + +func Subscribe(ctx context.Context) <-chan pubsub.Event[StatusMessage] { + return GetService().Subscribe(ctx) +} |
