summaryrefslogtreecommitdiff
path: root/spartan/response.go
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-04-29 16:24:38 -0600
committertjpcc <tjp@ctrl-c.club>2023-04-29 16:24:38 -0600
commit039c58c9d00a4a5886fa99d7c7d472e6d02d6a67 (patch)
tree2b19ed023e956617ee3206a4528ad62317316942 /spartan/response.go
parentaa6bdb0649c2f2a63b4deae8c4984a660cd0400a (diff)
initial spartan server support
Diffstat (limited to 'spartan/response.go')
-rw-r--r--spartan/response.go96
1 files changed, 96 insertions, 0 deletions
diff --git a/spartan/response.go b/spartan/response.go
new file mode 100644
index 0000000..edc1db6
--- /dev/null
+++ b/spartan/response.go
@@ -0,0 +1,96 @@
+package spartan
+
+import (
+ "bytes"
+ "io"
+ "sync"
+
+ "tildegit.org/tjp/gus"
+)
+
+// The spartan response types.
+const (
+ StatusSuccess gus.Status = 2
+ StatusRedirect gus.Status = 3
+ StatusClientError gus.Status = 4
+ StatusServerError gus.Status = 5
+)
+
+// Success builds a successful spartan response.
+func Success(mediatype string, body io.Reader) *gus.Response {
+ return &gus.Response{
+ Status: StatusSuccess,
+ Meta: mediatype,
+ Body: body,
+ }
+}
+
+// Redirect builds a spartan redirect response.
+func Redirect(url string) *gus.Response {
+ return &gus.Response{
+ Status: StatusRedirect,
+ Meta: url,
+ }
+}
+
+// ClientError builds a "client error" spartan response.
+func ClientError(err error) *gus.Response {
+ return &gus.Response{
+ Status: StatusClientError,
+ Meta: err.Error(),
+ }
+}
+
+// ServerError builds a "server error" spartan response.
+func ServerError(err error) *gus.Response {
+ return &gus.Response{
+ Status: StatusServerError,
+ Meta: err.Error(),
+ }
+}
+
+// NewResponseReader builds a reader for a response.
+func NewResponseReader(response *gus.Response) gus.ResponseReader {
+ return &responseReader{
+ Response: response,
+ once: &sync.Once{},
+ }
+}
+
+type responseReader struct {
+ *gus.Response
+ reader io.Reader
+ once *sync.Once
+}
+
+func (rdr *responseReader) Read(b []byte) (int, error) {
+ rdr.ensureReader()
+ return rdr.reader.Read(b)
+}
+
+func (rdr *responseReader) WriteTo(dst io.Writer) (int64, error) {
+ rdr.ensureReader()
+ return rdr.reader.(io.WriterTo).WriteTo(dst)
+}
+
+func (rdr *responseReader) ensureReader() {
+ rdr.once.Do(func() {
+ hdr := bytes.NewBuffer(rdr.headerLine())
+ if rdr.Body != nil {
+ rdr.reader = io.MultiReader(hdr, rdr.Body)
+ } else {
+ rdr.reader = hdr
+ }
+ })
+}
+
+func (rdr *responseReader) headerLine() []byte {
+ meta := rdr.Meta.(string)
+ buf := make([]byte, len(meta)+4)
+ buf[0] = byte(rdr.Status) + '0'
+ buf[1] = ' '
+ copy(buf[2:], meta)
+ buf[len(buf)-2] = '\r'
+ buf[len(buf)-1] = '\n'
+ return buf
+}