From f65c34ea78775fd26133c6901ef30af793aec931 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 22 Mar 2024 14:37:21 +0100 Subject: [PATCH] Added streaming --- Response.go | 10 ++++++++++ Server_test.go | 8 ++++++++ examples/stream/main.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 examples/stream/main.go diff --git a/Response.go b/Response.go index 49bbd33..fbdd14f 100644 --- a/Response.go +++ b/Response.go @@ -7,6 +7,7 @@ import ( // Response is the interface for an HTTP response. type Response interface { + Flush() Header(key string) string SetHeader(key string, value string) Write([]byte) (int, error) @@ -18,6 +19,15 @@ type response struct { http.ResponseWriter } +// Flush flushes the response buffers to the client. +func (res response) Flush() { + flusher, ok := res.ResponseWriter.(http.Flusher) + + if ok { + flusher.Flush() + } +} + // Header returns the header value for the given key. func (res response) Header(key string) string { return res.ResponseWriter.Header().Get(key) diff --git a/Server_test.go b/Server_test.go index 18d317f..9950993 100644 --- a/Server_test.go +++ b/Server_test.go @@ -52,6 +52,13 @@ func TestRouter(t *testing.T) { return ctx.File("testdata/file.txt") }) + s.Get("/flush", func(ctx server.Context) error { + ctx.Response().WriteString("Hello 1\n") + ctx.Response().WriteString("Hello 2\n") + ctx.Response().Flush() + return nil + }) + s.Get("/echo", func(ctx server.Context) error { return ctx.Copy(ctx.Request()) }) @@ -123,6 +130,7 @@ func TestRouter(t *testing.T) { {Method: "GET", URL: "/error", Body: "", Status: http.StatusUnauthorized, Response: "Not logged in"}, {Method: "GET", URL: "/error2", Body: "", Status: http.StatusUnauthorized, Response: "Not logged in\nMissing auth token"}, {Method: "GET", URL: "/file", Body: "", Status: http.StatusOK, Response: "Hello File"}, + {Method: "GET", URL: "/flush", Body: "", Status: http.StatusOK, Response: "Hello 1\nHello 2\n"}, {Method: "GET", URL: "/not-found", Body: "", Status: http.StatusNotFound, Response: http.StatusText(http.StatusNotFound)}, {Method: "GET", URL: "/request/data", Body: "", Status: http.StatusOK, Response: "GET HTTP/1.1 example.com /request/data"}, {Method: "GET", URL: "/request/header", Body: "", Status: http.StatusOK, Response: ""}, diff --git a/examples/stream/main.go b/examples/stream/main.go new file mode 100644 index 0000000..4d43d74 --- /dev/null +++ b/examples/stream/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "time" + + "git.akyoto.dev/go/server" +) + +func main() { + s := server.New() + + s.Get("/", func(ctx server.Context) error { + ticker := time.NewTicker(time.Second) + + for { + select { + case <-ctx.Request().Context().Done(): + return nil + + case <-ticker.C: + ctx.Response().WriteString("Hello\n") + ctx.Response().Flush() + } + } + }) + + s.Run(":8080") +}