diff options
author | Anisse Astier <anisse@astier.eu> | 2019-05-13 10:08:41 +0200 |
---|---|---|
committer | Anisse Astier <anisse@astier.eu> | 2019-05-13 10:08:41 +0200 |
commit | 46cbc23d499ba1aebb16e36cd354689b0f15a667 (patch) | |
tree | b194ea3ad05c6a1b34799ab040fb10af44dd1e5d | |
download | websocktty-46cbc23d499ba1aebb16e36cd354689b0f15a667.tar.bz2 websocktty-46cbc23d499ba1aebb16e36cd354689b0f15a667.tar.xz websocktty-46cbc23d499ba1aebb16e36cd354689b0f15a667.zip |
Minimal client for QEMU websocket serial
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | go.mod | 6 | ||||
-rw-r--r-- | go.sum | 10 | ||||
-rw-r--r-- | main.go | 89 |
4 files changed, 106 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c13b75 --- /dev/null +++ b/README.md | |||
@@ -0,0 +1 @@ | |||
Minimal websocket serial client for QEMU websocket chardev. | |||
@@ -0,0 +1,6 @@ | |||
1 | module websocktty | ||
2 | |||
3 | require ( | ||
4 | github.com/gorilla/websocket v1.4.0 | ||
5 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 | ||
6 | ) | ||
@@ -0,0 +1,10 @@ | |||
1 | github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | ||
2 | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||
3 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
4 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 h1:iMGN4xG0cnqj3t+zOM8wUB0BiPKHEwSxEZCvzcbZuvk= | ||
5 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
6 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
7 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
8 | golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= | ||
9 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
10 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
@@ -0,0 +1,89 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "flag" | ||
5 | "fmt" | ||
6 | "log" | ||
7 | "net/http" | ||
8 | "net/url" | ||
9 | "os" | ||
10 | "os/signal" | ||
11 | "syscall" | ||
12 | "time" | ||
13 | |||
14 | "github.com/gorilla/websocket" | ||
15 | "golang.org/x/crypto/ssh/terminal" | ||
16 | ) | ||
17 | |||
18 | var addr = flag.String("addr", "localhost:8080", "http service address") | ||
19 | |||
20 | func main() { | ||
21 | flag.Parse() | ||
22 | log.SetFlags(0) | ||
23 | |||
24 | interrupt := make(chan os.Signal, 1) | ||
25 | signal.Notify(interrupt, os.Interrupt) | ||
26 | signal.Notify(interrupt, syscall.SIGTERM) | ||
27 | |||
28 | u := url.URL{Scheme: "ws", Host: *addr, Path: "/"} | ||
29 | log.Printf("connecting to %s. `kill -15 %d` to stop", u.String(), os.Getpid()) | ||
30 | |||
31 | proto := make(http.Header) | ||
32 | proto.Add("Sec-WebSocket-Protocol", "binary") | ||
33 | c, _, err := websocket.DefaultDialer.Dial(u.String(), proto) | ||
34 | if err != nil { | ||
35 | log.Fatal("dial:", err) | ||
36 | } | ||
37 | defer c.Close() | ||
38 | |||
39 | oldState, err := terminal.MakeRaw(0) | ||
40 | if err != nil { | ||
41 | fmt.Println("Cannot set input terminal in raw mode") | ||
42 | } | ||
43 | defer terminal.Restore(0, oldState) | ||
44 | |||
45 | done := make(chan struct{}) | ||
46 | |||
47 | go func() { | ||
48 | defer close(done) | ||
49 | for { | ||
50 | _, message, err := c.ReadMessage() | ||
51 | if err != nil { | ||
52 | log.Println("read:", err) | ||
53 | return | ||
54 | } | ||
55 | fmt.Fprintf(os.Stdout, "%s", message) | ||
56 | } | ||
57 | }() | ||
58 | |||
59 | for { | ||
60 | select { | ||
61 | case <-done: | ||
62 | return | ||
63 | case <-interrupt: | ||
64 | log.Println("interrupt") | ||
65 | |||
66 | // Cleanly close the connection by sending a close message and then | ||
67 | // waiting (with timeout) for the server to close the connection. | ||
68 | err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) | ||
69 | if err != nil { | ||
70 | log.Println("write close:", err) | ||
71 | return | ||
72 | } | ||
73 | select { | ||
74 | case <-done: | ||
75 | case <-time.After(time.Second): | ||
76 | } | ||
77 | return | ||
78 | default: | ||
79 | buf := make([]byte, 128) | ||
80 | n, err := os.Stdin.Read(buf) | ||
81 | err = c.WriteMessage(websocket.BinaryMessage, buf[:n]) | ||
82 | if err != nil { | ||
83 | log.Println("write:", err) | ||
84 | return | ||
85 | } | ||
86 | } | ||
87 | |||
88 | } | ||
89 | } | ||