Major changes: - Add Go backend (backend/) with microservices architecture - Enhanced master-agents-svc: reranker, content-classifier, stealth-crawler, proxy-manager, media-search, fastClassifier, language detection - New web-svc widgets: KnowledgeCard, ProductCard, ProfileCard, VideoCard, UnifiedCard, CardGallery, InlineImageGallery, SourcesPanel, RelatedQuestions - Improved discover-svc with discover-db integration - Docker deployment improvements (Caddyfile, vendor.sh, BUILD.md) - Library-svc: project_id schema migration - Remove deprecated finance-svc and travel-svc - Localization improvements across services Made-with: Cursor
114 lines
1.9 KiB
Go
114 lines
1.9 KiB
Go
package ndjson
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"io"
|
|
"sync"
|
|
)
|
|
|
|
type Writer struct {
|
|
w io.Writer
|
|
buf *bufio.Writer
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func NewWriter(w io.Writer) *Writer {
|
|
return &Writer{
|
|
w: w,
|
|
buf: bufio.NewWriter(w),
|
|
}
|
|
}
|
|
|
|
func (w *Writer) Write(v interface{}) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := w.buf.Write(data); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := w.buf.WriteByte('\n'); err != nil {
|
|
return err
|
|
}
|
|
|
|
return w.buf.Flush()
|
|
}
|
|
|
|
func (w *Writer) WriteRaw(data []byte) error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
|
|
if _, err := w.buf.Write(data); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := w.buf.WriteByte('\n'); err != nil {
|
|
return err
|
|
}
|
|
|
|
return w.buf.Flush()
|
|
}
|
|
|
|
func (w *Writer) Flush() error {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
return w.buf.Flush()
|
|
}
|
|
|
|
type StreamEvent struct {
|
|
Type string `json:"type"`
|
|
Block interface{} `json:"block,omitempty"`
|
|
BlockID string `json:"blockId,omitempty"`
|
|
Chunk string `json:"chunk,omitempty"`
|
|
Patch interface{} `json:"patch,omitempty"`
|
|
Data interface{} `json:"data,omitempty"`
|
|
}
|
|
|
|
func WriteBlock(w *Writer, block interface{}) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "block",
|
|
Block: block,
|
|
})
|
|
}
|
|
|
|
func WriteTextChunk(w *Writer, blockID, chunk string) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "textChunk",
|
|
BlockID: blockID,
|
|
Chunk: chunk,
|
|
})
|
|
}
|
|
|
|
func WriteUpdateBlock(w *Writer, blockID string, patch interface{}) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "updateBlock",
|
|
BlockID: blockID,
|
|
Patch: patch,
|
|
})
|
|
}
|
|
|
|
func WriteResearchComplete(w *Writer) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "researchComplete",
|
|
})
|
|
}
|
|
|
|
func WriteMessageEnd(w *Writer) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "messageEnd",
|
|
})
|
|
}
|
|
|
|
func WriteError(w *Writer, err error) error {
|
|
return w.Write(StreamEvent{
|
|
Type: "error",
|
|
Data: err.Error(),
|
|
})
|
|
}
|