// Copyright (c) 2022, Přemysl Eric Janouch // SPDX-License-Identifier: 0BSD package main import ( "context" "encoding/binary" "encoding/json" "fmt" "html/template" "io" "log" "net" "net/http" "os" "time" "golang.org/x/net/websocket" ) var ( addressBind string addressConnect string addressWS string ) func clientToRelay( ctx context.Context, ws *websocket.Conn, conn net.Conn) bool { var j string if err := websocket.Message.Receive(ws, &j); err != nil { log.Println("Command receive failed: " + err.Error()) return false } log.Printf("?> %s\n", j) var m RelayCommandMessage if err := json.Unmarshal([]byte(j), &m); err != nil { log.Println("Command unmarshalling failed: " + err.Error()) return false } b, ok := m.AppendTo(make([]byte, 4)) if !ok { log.Println("Command serialization failed") return false } binary.BigEndian.PutUint32(b[:4], uint32(len(b)-4)) if _, err := conn.Write(b); err != nil { log.Println("Command send failed: " + err.Error()) return false } log.Printf("-> %v\n", b) return true } func relayToClient( ctx context.Context, ws *websocket.Conn, conn net.Conn) bool { var length uint32 if err := binary.Read(conn, binary.BigEndian, &length); err != nil { log.Println("Event receive failed: " + err.Error()) return false } b := make([]byte, length) if _, err := io.ReadFull(conn, b); err != nil { log.Println("Event receive failed: " + err.Error()) return false } log.Printf(" xP `)) func handleDefault(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { staticHandler.ServeHTTP(w, r) return } wsURI := addressWS if wsURI == "" { wsURI = fmt.Sprintf("ws://%s/ws", r.Host) } if err := page.Execute(w, wsURI); err != nil { log.Println("Template execution failed: " + err.Error()) } } func main() { if len(os.Args) < 3 || len(os.Args) > 4 { log.Fatalf("usage: %s BIND CONNECT [WSURI]\n", os.Args[0]) } addressBind, addressConnect = os.Args[1], os.Args[2] if len(os.Args) > 3 { addressWS = os.Args[3] } http.Handle("/ws", websocket.Handler(handleWebSocket)) http.Handle("/", http.HandlerFunc(handleDefault)) s := &http.Server{ Addr: addressBind, ReadTimeout: 60 * time.Second, WriteTimeout: 60 * time.Second, MaxHeaderBytes: 32 << 10, } log.Fatal(s.ListenAndServe()) }