From 7e18c2436bca5ae5fa8c192d4542798049cbdbc1 Mon Sep 17 00:00:00 2001
From: Robby Zambito <contact@robbyzambito.me>
Date: Sat, 22 Feb 2025 09:55:42 -0500
Subject: Add client proxy

Add endpoint /proxy ... that can be used to proxy requests to other HTTP sites.
---
 main.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/main.go b/main.go
index c54b239..75b60f9 100644
--- a/main.go
+++ b/main.go
@@ -1,6 +1,7 @@
 package main
 
 import (
+	"bytes"
 	"flag"
 	"fmt"
 	"io/ioutil"
@@ -13,6 +14,7 @@ import (
 	"time"
 
 	"github.com/nats-io/nats.go"
+	"github.com/nats-io/nats.go/micro"
 )
 
 // printHelp outputs the usage information.
@@ -51,6 +53,25 @@ func URLToNATS(urlPath string) (string, error) {
 	return strings.Join(segments, "."), nil
 }
 
+// NATS subject to URL conversion
+func NATSToURL(natsSubject string) (string, error) {
+	tokens := strings.Split(natsSubject, ".")
+	for i, token := range tokens {
+		// Reverse the special character encoding
+		decoded := strings.ReplaceAll(token, "%2E", ".")
+		decoded = strings.ReplaceAll(decoded, "%2A", "*")
+		decoded = strings.ReplaceAll(decoded, "%3E", ">")
+
+		// Unescape remaining URL encoding
+		unescaped, err := url.PathUnescape(decoded)
+		if err != nil {
+			return "", fmt.Errorf("failed to unescape token: %w", err)
+		}
+		tokens[i] = unescaped
+	}
+	return "/" + strings.Join(tokens, "/"), nil
+}
+
 func main() {
 	helpFlag := flag.Bool("help", false, "Display help information about available environment variables")
 	flag.Parse()
@@ -188,6 +209,43 @@ func main() {
 		w.Write(reply.Data)
 	})
 
+	_, err = micro.AddService(nc, micro.Config{
+		Name:    "http-nats-proxy",
+		Version: "0.1.0",
+		Endpoint: &micro.EndpointConfig{
+			Subject: "http.*.*.proxy.>",
+			Handler: micro.HandlerFunc(func(natsReq micro.Request) {
+				// http.host.method.proxy.host.endpoint.>
+				httpPath := natsReq.Headers()["X-HTTP-Path"][0]
+				httpReqURL := fmt.Sprintf("https:/%s", strings.TrimPrefix(httpPath, "/proxy"))
+				httpBody := bytes.NewReader(natsReq.Data())
+				httpMethod := natsReq.Headers()["X-HTTP-Method"][0]
+
+				// Create a new request
+				httpReq, err := http.NewRequest(httpMethod, httpReqURL, httpBody)
+				if err != nil {
+					log.Fatal(err)
+				}
+				client := &http.Client{}
+				resp, err := client.Do(httpReq)
+				if err != nil {
+					log.Fatal(err)
+				}
+				defer resp.Body.Close()
+
+				resBody, err := ioutil.ReadAll(resp.Body)
+				if err != nil {
+					log.Fatal(err)
+				}
+
+				natsReq.Respond(resBody)
+			}),
+		},
+	})
+	if err != nil {
+		log.Fatal("Could not make NATS microservice:", err)
+	}
+
 	// Start the HTTP server
 	fmt.Println("Server is running on http://localhost:8080")
 	log.Fatal(http.ListenAndServe(":8080", nil))
-- 
cgit