feat(events): EventBus + domain-модель статусов
- internal/model: единый источник статусов задачи (Status, TraceStatus, машина переходов), без зависимости от storage. - internal/storage: совместимый мост (type Status = model.Status, re-export констант) — внешний код не меняется. - internal/events: шина событий (fan-out, блокирующий Publish с гарантией порядка), события задач/трейсов, отдельная логовая шина + LogWriter, Publisher/NilPublisher для внедрения в Core/Worker. - docs/ui-spec.md: спецификация десктопного UI (Fyne).
This commit is contained in:
65
internal/events/log.go
Normal file
65
internal/events/log.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// LogLine — строка лога для панели «Логи».
|
||||
type LogLine struct {
|
||||
Level string
|
||||
Text string
|
||||
}
|
||||
|
||||
func (LogLine) _event() {}
|
||||
|
||||
// LogBus — тип-обёртка над *Bus для логов.
|
||||
//
|
||||
// Логи идут отдельной шиной, чтобы большие объёмы текста не блокировали
|
||||
// доменные события и наоборот.
|
||||
type LogBus struct {
|
||||
*Bus
|
||||
}
|
||||
|
||||
// NewLogBus создаёт шину логов с буфером на подписчика.
|
||||
func NewLogBus(bufSize int) *LogBus {
|
||||
return &LogBus{Bus: New(bufSize)}
|
||||
}
|
||||
|
||||
// LogWriter — io.Writer, который публикует каждую строку лога как LogLine.
|
||||
// Предполагается использование через log.SetOutput в связке, чтобы всё
|
||||
// логирование приложения попадало и в панель «Логи».
|
||||
type LogWriter struct {
|
||||
bus *Bus
|
||||
mu sync.Mutex // защищает остаток частичной строки
|
||||
buf strings.Builder
|
||||
}
|
||||
|
||||
// NewLogWriter создаёт LogWriter, публикующий в шину логов события LogLine{Level:"log"}.
|
||||
func NewLogWriter(bus *LogBus) *LogWriter {
|
||||
return &LogWriter{bus: bus.Bus}
|
||||
}
|
||||
|
||||
// Write реализует io.Writer. Данные разрезаются по переводам строки:
|
||||
// каждая законченная строка публикуется отдельным событием.
|
||||
func (w *LogWriter) Write(p []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
w.buf.Write(p)
|
||||
data := w.buf.String()
|
||||
for {
|
||||
idx := strings.IndexByte(data, '\n')
|
||||
if idx < 0 {
|
||||
break
|
||||
}
|
||||
line := strings.TrimSuffix(data[:idx], "\r")
|
||||
data = data[idx+1:]
|
||||
if line != "" {
|
||||
w.bus.Publish(LogLine{Level: "log", Text: line})
|
||||
}
|
||||
}
|
||||
w.buf.Reset()
|
||||
w.buf.WriteString(data)
|
||||
return len(p), nil
|
||||
}
|
||||
Reference in New Issue
Block a user