-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
133 lines (112 loc) · 3.19 KB
/
response.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package esl
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"log/slog"
"strconv"
"strings"
)
type response struct {
contentType string // Content-Type
text string // Reply-Text
jobUUID string // Job-UUID
body []byte // Body
}
// ContentType returns the content type of the response.
func (r response) ContentType() string {
return r.contentType
}
// Text returns the text value of the response.
func (r response) Text() string {
return r.text
}
// JobUUID returns the job UUID of the response.
func (r response) JobUUID() string {
return r.jobUUID
}
// ContentLength returns the length of the response body in bytes.
func (r response) ContentLength() int {
return len(r.body)
}
// Body returns the body of the response as a string.
func (r response) Body() string {
return string(r.body)
}
// AsErr checks the content type of the response and returns an error if it matches a specific case.
func (r response) AsErr() error {
switch r.contentType {
case disconnectNotice:
return io.EOF
case commandReply:
if strings.HasPrefix(r.text, "-ERR") {
return errors.New(r.text)
}
case "api/response":
if bytes.HasPrefix(r.body, []byte("-ERR")) {
return errors.New(string(r.body))
}
}
return nil
}
// WriteTo writes the response to the provided io.Writer.
//
// It writes the response headers to the writer, including the Content-Type,
// Reply-Text, Job-UUID, and Content-Length if applicable. It then writes the
// response body to the writer.
func (r response) WriteTo(w io.Writer) (int64, error) {
//nolint:errcheck // writing to buffer
return writeTo(w, func(buf *bufio.Writer) {
buf.WriteString("Content-Type: ")
buf.WriteString(r.contentType)
if r.text != "" {
buf.WriteByte('\n')
buf.WriteString("Reply-Text: ")
buf.WriteString(r.text)
}
if r.jobUUID != "" {
buf.WriteString("\nJob-UUID: ")
buf.WriteString(r.jobUUID)
}
if length := len(r.body); length > 0 {
buf.WriteString("\nContent-Length: ")
buf.WriteString(strconv.Itoa(length))
buf.WriteString("\n\n")
buf.Write(r.body)
}
})
}
// String returns the string representation of the response.
func (r response) String() string {
return writeStr(r)
}
// LogValue returns a slog.Value object that represents the log attributes for the response.
func (r response) LogValue() slog.Value {
attr := make([]slog.Attr, 0, 3)
attr = append(attr, slog.String("type", r.contentType))
if r.jobUUID != "" {
attr = append(attr, slog.String("job-uuid", r.jobUUID))
}
if err := r.AsErr(); err != nil {
attr = append(attr, slog.String("error", err.Error()))
} else if length := r.ContentLength(); length > 0 {
attr = append(attr, slog.Int("length", length))
}
return slog.GroupValue(attr...)
}
// isZero checks if the response is zero.
func (r response) isZero() bool {
return r.contentType == ""
}
// toEvent converts a response to an Event struct.
//
// It expects the response to have a content type of "text/event-plain".
// It returns an Event struct and an error if the content type is not supported.
func (r response) toEvent() (Event, error) {
if ct := r.ContentType(); ct != eventPlain {
return Event{}, fmt.Errorf("unsupported event content type: %s", ct)
}
return parseEvent(r.body)
}