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)