From 450250c4198db3930226fadc96accfe5f21e629e Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Fri, 26 Jan 2024 13:07:42 +0800 Subject: [PATCH] :test_tube: Add SSE test tools --- .gitignore | 1 - .idea/RoadSign.iml | 6 ++++ .idea/misc.xml | 6 ++++ config/example.toml | 28 ++++++++++++++++++ pkg/navi/responder.go | 47 ++++++++++++++++++++----------- pkg/navi/route.go | 4 +-- pkg/navi/struct.go | 11 ++++++-- pkg/sideload/view/index.html | 4 +-- pkg/sideload/view/public/vite.svg | 1 - test/data/sse/index.html | 27 ++++++++++++++++++ test/data/sse/server.py | 28 ++++++++++++++++++ 11 files changed, 138 insertions(+), 25 deletions(-) create mode 100644 .idea/misc.xml create mode 100644 config/example.toml delete mode 100644 pkg/sideload/view/public/vite.svg create mode 100644 test/data/sse/index.html create mode 100644 test/data/sse/server.py diff --git a/.gitignore b/.gitignore index a8273db..71983f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -/config /letsencrypt .DS_Store \ No newline at end of file diff --git a/.idea/RoadSign.iml b/.idea/RoadSign.iml index 5e764c4..9dda0dd 100644 --- a/.idea/RoadSign.iml +++ b/.idea/RoadSign.iml @@ -1,9 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..53e6b55 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/config/example.toml b/config/example.toml new file mode 100644 index 0000000..34b11f7 --- /dev/null +++ b/config/example.toml @@ -0,0 +1,28 @@ +id = "example-region" + +[[locations]] +id = "example-sse" +host = ["localhost:8000"] +path = ["/sse"] +[[locations.destinations]] +id = "example-sse-destination" +uri = "http://localhost:5000?sse=enable" +[[locations.transformers]] +type = "replacePath" +options = { pattern = "/sse", value = "" } + +[[locations]] +id = "example-websocket" +host = ["localhost:8000"] +path = ["/ws"] +[[locations.destinations]] +id = "example-websocket-destination" +uri = "http://localhost:8765" + +[[locations]] +id = "example-location" +host = ["localhost:8000"] +path = ["/"] +[[locations.destinations]] +id = "example-destination" +uri = "files://test/data" \ No newline at end of file diff --git a/pkg/navi/responder.go b/pkg/navi/responder.go index ba1e120..7cb2932 100644 --- a/pkg/navi/responder.go +++ b/pkg/navi/responder.go @@ -3,36 +3,46 @@ package navi import ( "errors" "fmt" + "github.com/fasthttp/websocket" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/proxy" + "github.com/gofiber/fiber/v2/utils" + "github.com/rs/zerolog/log" + "github.com/samber/lo" + "github.com/spf13/viper" + "github.com/valyala/fasthttp" "io/fs" "net/http" "path/filepath" "strconv" "strings" "time" - - "github.com/fasthttp/websocket" - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/middleware/proxy" - "github.com/gofiber/fiber/v2/utils" - "github.com/samber/lo" - "github.com/spf13/viper" - "github.com/valyala/fasthttp" ) -func makeHypertextResponse(c *fiber.Ctx, dest *Destination) error { +func makeUnifiedResponse(c *fiber.Ctx, dest *Destination) error { if websocket.FastHTTPIsWebSocketUpgrade(c.Context()) { // Handle websocket return makeWebsocketResponse(c, dest) } else { - // Handle normal request - timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond - return proxy.Do(c, dest.MakeUri(c), &fasthttp.Client{ - ReadTimeout: timeout, - WriteTimeout: timeout, - }) + _, queries := dest.GetRawUri() + if len(queries.Get("sse")) > 0 { + // Handle server-side event + return makeSeverSideEventResponse(c, dest) + } else { + // Handle normal http request + return makeHypertextResponse(c, dest) + } } } +func makeHypertextResponse(c *fiber.Ctx, dest *Destination) error { + timeout := time.Duration(viper.GetInt64("performance.network_timeout")) * time.Millisecond + return proxy.Do(c, dest.MakeUri(c), &fasthttp.Client{ + ReadTimeout: timeout, + WriteTimeout: timeout, + }) +} + var wsUpgrader = websocket.FastHTTPUpgrader{} func makeWebsocketResponse(c *fiber.Ctx, dest *Destination) error { @@ -58,7 +68,7 @@ func makeWebsocketResponse(c *fiber.Ctx, dest *Destination) error { for { mode, message, err := remote.ReadMessage() if err != nil { - fmt.Println(err) + log.Warn().Err(err).Msg("An error occurred during the websocket proxying...") return } else { signal <- struct { @@ -88,6 +98,11 @@ func makeWebsocketResponse(c *fiber.Ctx, dest *Destination) error { }) } +func makeSeverSideEventResponse(c *fiber.Ctx, dest *Destination) error { + // TODO Impl SSE with https://github.com/gofiber/recipes/blob/master/sse/main.go + return fiber.NewError(fiber.StatusNotImplemented, "Server-side-events was not available now.") +} + func makeFileResponse(c *fiber.Ctx, dest *Destination) error { uri, queries := dest.GetRawUri() root := http.Dir(uri) diff --git a/pkg/navi/route.go b/pkg/navi/route.go index 4f3cc32..fd4bd03 100644 --- a/pkg/navi/route.go +++ b/pkg/navi/route.go @@ -7,14 +7,14 @@ import ( ) type RoadApp struct { - Regions []*Region `json:"regions"` + Regions []*Region `json:"regions"` Traces []RoadTrace `json:"traces"` } func (v *RoadApp) Forward(ctx *fiber.Ctx, dest *Destination) error { switch dest.GetType() { case DestinationHypertext: - return makeHypertextResponse(ctx, dest) + return makeUnifiedResponse(ctx, dest) case DestinationStaticFile: return makeFileResponse(ctx, dest) default: diff --git a/pkg/navi/struct.go b/pkg/navi/struct.go index f2a110f..3926470 100644 --- a/pkg/navi/struct.go +++ b/pkg/navi/struct.go @@ -41,8 +41,12 @@ type Destination struct { Transformers []transformers.TransformerConfig `json:"transformers" toml:"transformers"` } +func (v *Destination) GetProtocol() string { + return strings.SplitN(v.Uri, "://", 2)[0] +} + func (v *Destination) GetType() DestinationType { - protocol := strings.SplitN(v.Uri, "://", 2)[0] + protocol := v.GetProtocol() switch protocol { case "http", "https": return DestinationHypertext @@ -56,7 +60,7 @@ func (v *Destination) GetRawUri() (string, url.Values) { uri := strings.SplitN(v.Uri, "://", 2)[1] data := strings.SplitN(uri, "?", 2) data = append(data, " ") // Make data array least have two element - qs, _ := url.ParseQuery(data[0]) + qs, _ := url.ParseQuery(data[1]) return data[0], qs } @@ -71,8 +75,9 @@ func (v *Destination) MakeUri(ctx *fiber.Ctx) string { path := string(ctx.Request().URI().Path()) hash := string(ctx.Request().URI().Hash()) + uri, _ := v.GetRawUri() - return v.Uri + path + + return uri + path + lo.Ternary(len(queries) > 0, "?"+strings.Join(queries, "&"), "") + lo.Ternary(len(hash) > 0, "#"+hash, "") } diff --git a/pkg/sideload/view/index.html b/pkg/sideload/view/index.html index 7021737..c7d1a70 100644 --- a/pkg/sideload/view/index.html +++ b/pkg/sideload/view/index.html @@ -2,9 +2,9 @@ - + - Vite + Solid + TS + RoadSign Sideload
diff --git a/pkg/sideload/view/public/vite.svg b/pkg/sideload/view/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/pkg/sideload/view/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/test/data/sse/index.html b/test/data/sse/index.html new file mode 100644 index 0000000..165148a --- /dev/null +++ b/test/data/sse/index.html @@ -0,0 +1,27 @@ + + + + + + + SSE Example + + +

Server-Sent Events Example

+
+ + + + diff --git a/test/data/sse/server.py b/test/data/sse/server.py new file mode 100644 index 0000000..429ea6f --- /dev/null +++ b/test/data/sse/server.py @@ -0,0 +1,28 @@ +import time + +from flask import Flask, render_template, Response + +app = Flask(__name__, template_folder=".") + + +# Generator function to simulate real-time updates +def event_stream(): + count = 0 + while True: + time.sleep(1) + count += 1 + yield f"data: {count}\n\n" + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/sse') +def sse(): + return Response(event_stream(), content_type='text/event-stream') + + +if __name__ == '__main__': + app.run(debug=True, threaded=True)