mirror of
https://github.com/coder/coder.git
synced 2025-03-14 10:09:57 +00:00
96 lines
2.1 KiB
Go
96 lines
2.1 KiB
Go
package codersdk
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/coderd/tracing"
|
|
)
|
|
|
|
type ServerSentEvent struct {
|
|
Type ServerSentEventType `json:"type"`
|
|
Data interface{} `json:"data"`
|
|
}
|
|
|
|
type ServerSentEventType string
|
|
|
|
const (
|
|
ServerSentEventTypePing ServerSentEventType = "ping"
|
|
ServerSentEventTypeData ServerSentEventType = "data"
|
|
ServerSentEventTypeError ServerSentEventType = "error"
|
|
)
|
|
|
|
func ServerSentEventReader(ctx context.Context, rc io.ReadCloser) func() (*ServerSentEvent, error) {
|
|
_, span := tracing.StartSpan(ctx)
|
|
defer span.End()
|
|
|
|
reader := bufio.NewReader(rc)
|
|
nextLineValue := func(prefix string) ([]byte, error) {
|
|
var (
|
|
line string
|
|
err error
|
|
)
|
|
for {
|
|
line, err = reader.ReadString('\n')
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("reading next string: %w", err)
|
|
}
|
|
if strings.TrimSpace(line) != "" {
|
|
break
|
|
}
|
|
}
|
|
|
|
if !strings.HasPrefix(line, fmt.Sprintf("%s: ", prefix)) {
|
|
return nil, xerrors.Errorf("expecting %s prefix, got: %s", prefix, line)
|
|
}
|
|
s := strings.TrimPrefix(line, fmt.Sprintf("%s: ", prefix))
|
|
s = strings.TrimSpace(s)
|
|
return []byte(s), nil
|
|
}
|
|
|
|
nextEvent := func() (*ServerSentEvent, error) {
|
|
for {
|
|
t, err := nextLineValue("event")
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("reading next line value: %w", err)
|
|
}
|
|
|
|
switch ServerSentEventType(t) {
|
|
case ServerSentEventTypePing:
|
|
return &ServerSentEvent{
|
|
Type: ServerSentEventTypePing,
|
|
}, nil
|
|
case ServerSentEventTypeData:
|
|
d, err := nextLineValue("data")
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("reading next line value: %w", err)
|
|
}
|
|
|
|
return &ServerSentEvent{
|
|
Type: ServerSentEventTypeData,
|
|
Data: d,
|
|
}, nil
|
|
case ServerSentEventTypeError:
|
|
d, err := nextLineValue("data")
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("reading next line value: %w", err)
|
|
}
|
|
|
|
return &ServerSentEvent{
|
|
Type: ServerSentEventTypeError,
|
|
Data: d,
|
|
}, nil
|
|
default:
|
|
return nil, xerrors.Errorf("unknown event type: %s", t)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nextEvent
|
|
}
|