package main import ( "flag" "fmt" "io/ioutil" "log" "net/http" "os" "strings" "time" "github.com/nats-io/nats.go" ) // printHelp outputs the usage information. func printHelp() { fmt.Println("Usage: HTTP-to-NATS proxy server") fmt.Println("\nThe following environment variables are supported:") fmt.Println(" NATS_URL - NATS connection URL (default: nats://127.0.0.1:4222)") fmt.Println(" NATS_USER - NATS username for authentication (optional)") fmt.Println(" NATS_PASSWORD - NATS password for authentication (optional)") fmt.Println(" HTTP_PORT - HTTP port to listen on (default: 8080)") } func main() { helpFlag := flag.Bool("help", false, "Display help information about available environment variables") flag.Parse() if *helpFlag { printHelp() os.Exit(0) } // Read NATS connection info from environment variables natsURL := os.Getenv("NATS_URL") if natsURL == "" { natsURL = nats.DefaultURL // defaults to "nats://127.0.0.1:4222" } natsUser := os.Getenv("NATS_USER") natsPassword := os.Getenv("NATS_PASSWORD") // Read HTTP port from environment variables httpPort := os.Getenv("HTTP_PORT") if httpPort == "" { httpPort = "8080" } // Set up NATS connection options if authentication info is provided. var opts []nats.Option if natsUser != "" && natsPassword != "" { opts = append(opts, nats.UserInfo(natsUser, natsPassword)) } nc, err := nats.Connect(natsURL, opts...) if err != nil { log.Fatal("Error connecting to NATS:", err) } defer nc.Close() // HTTP handler function http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // Read the entire request body body, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, "Error reading request body", http.StatusInternalServerError) return } defer r.Body.Close() // Drop the leading slash, replace remaining slashes with dots to form the subject subject := strings.ReplaceAll(strings.TrimPrefix(r.URL.Path, "/"), "/", ".") // Prefix the subject with "http." to follow the convention msg := nats.Msg{ Subject: fmt.Sprintf("http.%s", subject), Data: body, Header: nats.Header{}, } log.Println("Forwarding request to subject:", msg.Subject) // Copy HTTP headers to the NATS message headers for key, values := range r.Header { for _, value := range values { msg.Header.Add(key, value) } } // Send request to NATS and wait for reply (timeout: 30 seconds) reply, err := nc.RequestMsg(&msg, 30*time.Second) if err != nil { http.Error(w, "Error processing request", http.StatusInternalServerError) log.Println("Error processing the request:", err) return } // Copy headers from the NATS reply to the HTTP response for key, values := range reply.Header { for _, value := range values { w.Header().Add(key, value) } } // Write NATS reply body to HTTP response w.Write(reply.Data) }) fmt.Println("Server is running on http://localhost:" + httpPort) log.Fatal(http.ListenAndServe(":"+httpPort, nil)) }