opencode/packages/tui/internal/status/status.go

143 lines
3.2 KiB
Go
Raw Normal View History

2025-05-09 01:03:59 +08:00
package status
import (
2025-05-12 21:43:34 +08:00
"context"
"fmt"
2025-05-13 01:53:20 +08:00
"log/slog"
2025-05-12 21:43:34 +08:00
"sync"
2025-05-09 01:03:59 +08:00
"time"
2025-05-13 23:02:39 +08:00
"github.com/sst/opencode/internal/pubsub"
2025-05-09 01:03:59 +08:00
)
type Level string
const (
2025-05-12 21:43:34 +08:00
LevelInfo Level = "info"
LevelWarn Level = "warn"
2025-05-09 01:03:59 +08:00
LevelError Level = "error"
LevelDebug Level = "debug"
)
type StatusMessage struct {
2025-05-16 01:04:15 +08:00
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
}
2025-05-09 01:03:59 +08:00
}
2025-05-12 21:43:34 +08:00
const (
EventStatusPublished pubsub.EventType = "status_published"
)
2025-05-09 01:03:59 +08:00
type Service interface {
2025-05-12 21:43:34 +08:00
pubsub.Subscriber[StatusMessage]
2025-05-16 01:04:15 +08:00
Info(message string, opts ...StatusOption)
Warn(message string, opts ...StatusOption)
Error(message string, opts ...StatusOption)
Debug(message string, opts ...StatusOption)
2025-05-09 01:03:59 +08:00
}
type service struct {
2025-05-12 21:43:34 +08:00
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
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func (s *service) Info(message string, opts ...StatusOption) {
s.publish(LevelInfo, message, opts...)
2025-05-13 01:53:20 +08:00
slog.Info(message)
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func (s *service) Warn(message string, opts ...StatusOption) {
s.publish(LevelWarn, message, opts...)
2025-05-13 01:53:20 +08:00
slog.Warn(message)
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func (s *service) Error(message string, opts ...StatusOption) {
s.publish(LevelError, message, opts...)
2025-05-13 01:53:20 +08:00
slog.Error(message)
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func (s *service) Debug(message string, opts ...StatusOption) {
s.publish(LevelDebug, message, opts...)
2025-05-13 01:53:20 +08:00
slog.Debug(message)
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func (s *service) publish(level Level, messageText string, opts ...StatusOption) {
2025-05-09 01:03:59 +08:00
statusMsg := StatusMessage{
Level: level,
2025-05-12 21:43:34 +08:00
Message: messageText,
2025-05-09 01:03:59 +08:00
Timestamp: time.Now(),
}
2025-05-16 01:04:15 +08:00
// Apply all options
for _, opt := range opts {
opt(&statusMsg)
}
2025-05-12 21:43:34 +08:00
s.broker.Publish(EventStatusPublished, statusMsg)
2025-05-09 01:03:59 +08:00
}
2025-05-12 21:43:34 +08:00
func (s *service) Subscribe(ctx context.Context) <-chan pubsub.Event[StatusMessage] {
return s.broker.Subscribe(ctx)
}
2025-05-16 01:04:15 +08:00
func Info(message string, opts ...StatusOption) {
GetService().Info(message, opts...)
2025-05-12 21:43:34 +08:00
}
2025-05-16 01:04:15 +08:00
func Warn(message string, opts ...StatusOption) {
GetService().Warn(message, opts...)
2025-05-12 21:43:34 +08:00
}
2025-05-16 01:04:15 +08:00
func Error(message string, opts ...StatusOption) {
GetService().Error(message, opts...)
2025-05-09 01:03:59 +08:00
}
2025-05-16 01:04:15 +08:00
func Debug(message string, opts ...StatusOption) {
GetService().Debug(message, opts...)
2025-05-12 21:43:34 +08:00
}
func Subscribe(ctx context.Context) <-chan pubsub.Event[StatusMessage] {
return GetService().Subscribe(ctx)
}