basic htmx with server sending content to the client over a websocket is now working. This only worked when text message where being sent so the websocket handling had to be made configurable with a 'text' boolean field.
This commit is contained in:
parent
77cffde408
commit
39cf088a41
@ -258,7 +258,7 @@ func main() {
|
|||||||
log.Println("WebSocket connection error:", err)
|
log.Println("WebSocket connection error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wsConn := websocketutil.NewWebSocketConn(conn)
|
wsConn := websocketutil.NewWebSocketConn(conn, false)
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
|
|
||||||
serverInfo, err := comms.AgentInitialization(wsConn, comms.NewAgentInfo())
|
serverInfo, err := comms.AgentInitialization(wsConn, comms.NewAgentInfo())
|
||||||
|
@ -9,12 +9,11 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
_ "net/http/pprof"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func parsePublicId(path string) (publicId string, _ error) {
|
func parsePublicId(path string) (publicId string, _ error) {
|
||||||
@ -97,6 +96,8 @@ func main() {
|
|||||||
log.Printf("Using username '%s' and password '%s'", userPassword.Username, userPassword.Password)
|
log.Printf("Using username '%s' and password '%s'", userPassword.Username, userPassword.Password)
|
||||||
|
|
||||||
admin := converge.NewAdmin()
|
admin := converge.NewAdmin()
|
||||||
|
|
||||||
|
// For agents connecting
|
||||||
registrationService := websocketutil.WebSocketService{
|
registrationService := websocketutil.WebSocketService{
|
||||||
Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) {
|
Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) {
|
||||||
publicId, err := parsePublicId(r.URL.Path)
|
publicId, err := parsePublicId(r.URL.Path)
|
||||||
@ -112,6 +113,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For users connecting with ssh
|
||||||
clientService := websocketutil.WebSocketService{
|
clientService := websocketutil.WebSocketService{
|
||||||
Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) {
|
Handler: func(w http.ResponseWriter, r *http.Request, conn net.Conn) {
|
||||||
publicId, err := parsePublicId(r.URL.Path)
|
publicId, err := parsePublicId(r.URL.Path)
|
||||||
@ -127,9 +130,16 @@ func main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for the web browser getting live status updates.
|
||||||
|
sessionService := websocketutil.WebSocketService{
|
||||||
|
Handler: sessionHandler,
|
||||||
|
Text: true,
|
||||||
|
}
|
||||||
|
|
||||||
// websocket endpoints
|
// websocket endpoints
|
||||||
http.HandleFunc("/agent/", registrationService.Handle)
|
http.HandleFunc("/agent/", registrationService.Handle)
|
||||||
http.HandleFunc("/client/", clientService.Handle)
|
http.HandleFunc("/client/", clientService.Handle)
|
||||||
|
http.HandleFunc("/ws/sessions", sessionService.Handle)
|
||||||
|
|
||||||
// create filehandler with templating for html files.
|
// create filehandler with templating for html files.
|
||||||
http.Handle("/docs/", http.StripPrefix("/docs/", http.HandlerFunc(pageHandler)))
|
http.Handle("/docs/", http.StripPrefix("/docs/", http.HandlerFunc(pageHandler)))
|
||||||
|
@ -32,7 +32,7 @@ func pageHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
case "index.html":
|
case "index.html":
|
||||||
templates.AboutTab().Render(r.Context(), w)
|
templates.AboutTab().Render(r.Context(), w)
|
||||||
case "usage.html":
|
case "usage.html":
|
||||||
templates.UsageTab(secure, r.URL.Host, username).Render(r.Context(), w)
|
templates.UsageTab(secure, r.Host, username).Render(r.Context(), w)
|
||||||
case "downloads.html":
|
case "downloads.html":
|
||||||
templates.DownloadsTab().Render(r.Context(), w)
|
templates.DownloadsTab().Render(r.Context(), w)
|
||||||
case "sessions.html":
|
case "sessions.html":
|
||||||
|
55
cmd/converge/sessionhandler.go
Normal file
55
cmd/converge/sessionhandler.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Message struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func sessionHandler(w http.ResponseWriter, r *http.Request, conn net.Conn) {
|
||||||
|
log.Println("Got sessions websocket connection")
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
message := Message{
|
||||||
|
Type: "update",
|
||||||
|
Content: `
|
||||||
|
<div id="mycontent">
|
||||||
|
New data: ` + strconv.Itoa(i) + `
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
_, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR marshalling json: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//conn.Write(data)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
b := make([]byte, 1024)
|
||||||
|
_, err := conn.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
_, err = conn.Write([]byte(message.Content))
|
||||||
|
if err == nil {
|
||||||
|
_, err = conn.Write([]byte("\n"))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("ERROR sending message: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@ func handleConnection(conn net.Conn, wsURL string, insecure bool) {
|
|||||||
log.Println("WebSocket connection error:", err)
|
log.Println("WebSocket connection error:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wsConn := websocketutil.NewWebSocketConn(_wsConn)
|
wsConn := websocketutil.NewWebSocketConn(_wsConn, false)
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
|
|
||||||
iowrappers.SynchronizeStreams(wsConn, conn)
|
iowrappers.SynchronizeStreams(wsConn, conn)
|
||||||
|
@ -70,7 +70,7 @@ func main() {
|
|||||||
log.Println("WebSocket connection error:", err)
|
log.Println("WebSocket connection error:", err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
wsConn := websocketutil.NewWebSocketConn(_wsConn)
|
wsConn := websocketutil.NewWebSocketConn(_wsConn, false)
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
|
|
||||||
iowrappers.SynchronizeStreams(wsConn, Stdio{})
|
iowrappers.SynchronizeStreams(wsConn, Stdio{})
|
||||||
|
@ -35,7 +35,7 @@ func main() {
|
|||||||
|
|
||||||
func handleWebSocket(w http.ResponseWriter, r *http.Request, tcpConn net.Conn) {
|
func handleWebSocket(w http.ResponseWriter, r *http.Request, tcpConn net.Conn) {
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
wsConn := websocketutil.NewWebSocketConn(conn)
|
wsConn := websocketutil.NewWebSocketConn(conn, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error upgrading to WebSocket:", err)
|
log.Println("Error upgrading to WebSocket:", err)
|
||||||
return
|
return
|
||||||
|
@ -7,3 +7,6 @@ services:
|
|||||||
context: .
|
context: .
|
||||||
ports:
|
ports:
|
||||||
- 8000:8000
|
- 8000:8000
|
||||||
|
environment:
|
||||||
|
CONVERGE_USERNAME: abc
|
||||||
|
CONVERGE_PASSWORD: "123"
|
||||||
|
@ -17,9 +17,17 @@ templ BasePage(tab int) {
|
|||||||
<link rel="stylesheet" href="../static/css/bootstrap.min.css"
|
<link rel="stylesheet" href="../static/css/bootstrap.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
<script src="../static/js/htmx.1.9.12.js"></script>
|
||||||
|
<script src="../static/js/htmx.ws.1.9.12.js"></script>
|
||||||
|
|
||||||
<title>Converge</title>
|
<title>Converge</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<script>
|
||||||
|
htmx.logAll();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script src="../static/js/bootstrap.bundle.min.js"
|
<script src="../static/js/bootstrap.bundle.min.js"
|
||||||
crossorigin="anonymous"></script>
|
crossorigin="anonymous"></script>
|
||||||
|
@ -2,9 +2,12 @@ package templates
|
|||||||
|
|
||||||
|
|
||||||
templ Sessions() {
|
templ Sessions() {
|
||||||
<div>
|
<div hx-ext="ws" ws-connect="ws://localhost:8000/ws/sessions">
|
||||||
To be done
|
<div id="mycontent">
|
||||||
|
Initial content
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ templ Usage(secure string, host string, username string) {
|
|||||||
</p>
|
</p>
|
||||||
<pre>{`
|
<pre>{`
|
||||||
# linux
|
# linux
|
||||||
`}curl http{secure}://{host}/docs/agent > agent{`
|
`}curl http{secure}://{host}/static/agent > agent{`
|
||||||
chmod 755 agent
|
chmod 755 agent
|
||||||
`}./agent --id ID ws{secure}://{host}{`
|
`}./agent --id ID ws{secure}://{host}{`
|
||||||
|
|
||||||
# windows
|
# windows
|
||||||
`}curl http{secure}://{host}/docs/agent.exe > agent.exe{`
|
`}curl http{secure}://{host}/static/agent.exe > agent.exe{`
|
||||||
`}agent --id ID ws{secure}://{host}{`
|
`}agent --id ID ws{secure}://{host}{`
|
||||||
`}</pre>
|
`}</pre>
|
||||||
<p>
|
<p>
|
||||||
|
@ -9,6 +9,11 @@ import (
|
|||||||
type WebSocketConn struct {
|
type WebSocketConn struct {
|
||||||
conn *websocket.Conn
|
conn *websocket.Conn
|
||||||
buf []byte
|
buf []byte
|
||||||
|
text bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWebSocketConn(conn *websocket.Conn, text bool) *WebSocketConn {
|
||||||
|
return &WebSocketConn{conn: conn, text: text}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (websocketConn *WebSocketConn) Read(p []byte) (n int, err error) {
|
func (websocketConn *WebSocketConn) Read(p []byte) (n int, err error) {
|
||||||
@ -26,12 +31,12 @@ func (websocketConn *WebSocketConn) Read(p []byte) (n int, err error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebSocketConn(conn *websocket.Conn) *WebSocketConn {
|
|
||||||
return &WebSocketConn{conn: conn}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (websocketConn *WebSocketConn) Write(p []byte) (n int, err error) {
|
func (websocketConn *WebSocketConn) Write(p []byte) (n int, err error) {
|
||||||
err = websocketConn.conn.WriteMessage(websocket.BinaryMessage, p)
|
messageType := websocket.BinaryMessage
|
||||||
|
if websocketConn.text {
|
||||||
|
messageType = websocket.TextMessage
|
||||||
|
}
|
||||||
|
err = websocketConn.conn.WriteMessage(messageType, p)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
n = len(p)
|
n = len(p)
|
||||||
}
|
}
|
||||||
@ -73,5 +78,5 @@ func ConnectWebSocket(conn net.Conn, urlStr string) (net.Conn, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewWebSocketConn(wsConn), nil
|
return NewWebSocketConn(wsConn, false), nil
|
||||||
}
|
}
|
||||||
|
@ -22,13 +22,14 @@ var upgrader = websocket.Upgrader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleWebSocket(w http.ResponseWriter, r *http.Request,
|
func handleWebSocket(w http.ResponseWriter, r *http.Request,
|
||||||
handler func(w http.ResponseWriter, r *http.Request, websockerConnection net.Conn)) {
|
handler func(w http.ResponseWriter, r *http.Request, websockerConnection net.Conn),
|
||||||
|
text bool) {
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("Error upgrading to WebSocket:", err)
|
log.Println("Error upgrading to WebSocket:", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
wsConn := NewWebSocketConn(conn)
|
wsConn := NewWebSocketConn(conn, text)
|
||||||
defer wsConn.Close()
|
defer wsConn.Close()
|
||||||
|
|
||||||
handler(w, r, wsConn)
|
handler(w, r, wsConn)
|
||||||
@ -36,8 +37,9 @@ func handleWebSocket(w http.ResponseWriter, r *http.Request,
|
|||||||
|
|
||||||
type WebSocketService struct {
|
type WebSocketService struct {
|
||||||
Handler func(w http.ResponseWriter, r *http.Request, conn net.Conn)
|
Handler func(w http.ResponseWriter, r *http.Request, conn net.Conn)
|
||||||
|
Text bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (endpoint *WebSocketService) Handle(w http.ResponseWriter, r *http.Request) {
|
func (endpoint *WebSocketService) Handle(w http.ResponseWriter, r *http.Request) {
|
||||||
handleWebSocket(w, r, endpoint.Handler)
|
handleWebSocket(w, r, endpoint.Handler, endpoint.Text)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user