- 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).
65 lines
1.9 KiB
Go
65 lines
1.9 KiB
Go
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
|
||
} |