Skip to content

Commit 187a95d

Browse files
jkbczjsierp
andauthored
add http input handler (#11)
* add http input handler * improve frontend rendering * rename existing input_handler to keyboard_input_handler * add websocket connection * send keepalive websocket messages * remove comments, logs --------- Co-authored-by: Jan Sierpina <jan.sierpina@solvti.com>
1 parent 0ee7275 commit 187a95d

7 files changed

Lines changed: 165 additions & 5 deletions

File tree

go.mod

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,7 @@ require (
77
golang.org/x/term v0.33.0
88
)
99

10-
require golang.org/x/sys v0.34.0 // indirect
10+
require (
11+
github.com/gorilla/websocket v1.5.3 // indirect
12+
golang.org/x/sys v0.34.0 // indirect
13+
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
22
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
3+
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
4+
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
35
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
46
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
57
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=

http_input_handler.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"log"
6+
"net/http"
7+
8+
_ "embed"
9+
10+
"github.com/google/uuid"
11+
"github.com/gorilla/websocket"
12+
)
13+
14+
//go:embed index.html
15+
var frontend []byte
16+
17+
var upgrader = websocket.Upgrader{
18+
CheckOrigin: func(r *http.Request) bool {
19+
return true
20+
},
21+
}
22+
23+
type HttpInputHandler struct {
24+
playerService PlayerService
25+
server *http.Server
26+
mux *http.ServeMux
27+
playerIdMap map[uuid.UUID]int
28+
}
29+
30+
func NewHttpInputHandler(ps PlayerService) *HttpInputHandler {
31+
handler := &HttpInputHandler{
32+
playerService: ps,
33+
playerIdMap: map[uuid.UUID]int{},
34+
35+
mux: http.NewServeMux(),
36+
}
37+
38+
handler.mux.HandleFunc("GET /", handler.serveFrontend)
39+
handler.mux.HandleFunc("GET /ws", handler.serveWebsocket)
40+
41+
return handler
42+
}
43+
44+
func (k *HttpInputHandler) Listen(addr string) {
45+
k.server = &http.Server{
46+
Addr: addr,
47+
Handler: k.mux,
48+
}
49+
k.server.ListenAndServe()
50+
}
51+
52+
func (h *HttpInputHandler) serveFrontend(w http.ResponseWriter, req *http.Request) {
53+
w.Write(frontend)
54+
}
55+
56+
func (h *HttpInputHandler) serveWebsocket(w http.ResponseWriter, req *http.Request) {
57+
conn, err := upgrader.Upgrade(w, req, nil)
58+
if err != nil {
59+
log.Println("Error upgrading connection:", err)
60+
return
61+
}
62+
defer conn.Close()
63+
64+
playerId := uuid.New()
65+
h.playerService.Join(playerId)
66+
67+
for {
68+
_, msg, err := conn.ReadMessage()
69+
if err != nil {
70+
log.Println("Error reading message:", err)
71+
break
72+
}
73+
74+
switch string(msg) {
75+
case "l":
76+
h.playerService.TurnLeft(playerId)
77+
case "r":
78+
h.playerService.TurnRight(playerId)
79+
}
80+
}
81+
}
82+
83+
func (k *HttpInputHandler) Close() {
84+
if k.server == nil {
85+
return
86+
}
87+
k.server.Shutdown(context.Background())
88+
}

index.html

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
6+
<title>Full Screen Buttons</title>
7+
<style>
8+
html, body {
9+
height: 100%; /* Ensures html and body take full viewport height */
10+
margin: 0; /* Removes default body margin */
11+
overflow: hidden; /* Prevents scrolling if content exceeds viewport */
12+
}
13+
14+
.container {
15+
display: flex; /* Enables flexbox layout */
16+
height: 100%; /* Makes the container fill the entire height of the body */
17+
width: 100%; /* Makes the container fill the entire width of the body */
18+
}
19+
20+
.button {
21+
width: 100%; /* Each button takes an equal share of the available space */
22+
height: 100%;
23+
border: none; /* Removes default button border */
24+
font-size: 64px; /* Adjust font size as needed */
25+
color: white; /* Text color */
26+
cursor: pointer; /* Indicates it's clickable */
27+
touch-action: manipulation;
28+
}
29+
30+
.button:first-child {
31+
background-color: #4CAF50; /* Green for the first button */
32+
}
33+
34+
.button:last-child {
35+
background-color: #008CBA; /* Blue for the second button */
36+
}
37+
</style>
38+
</head>
39+
<body>
40+
<div class="container">
41+
<button onclick="sendAction('l')" class="button">Left</button>
42+
<button onclick="sendAction('r')" class="button">Right</button>
43+
</div>
44+
<script>
45+
const ws = new WebSocket("/ws")
46+
const wsMsgIntervalMs = 100;
47+
let intervalId
48+
let isOpen = false;
49+
function sendAction(action) {
50+
if(isOpen) {
51+
ws.send(action)
52+
}
53+
}
54+
ws.addEventListener("open", (event) => {
55+
intervalId = setInterval(() => {
56+
ws.send("_")
57+
}, wsMsgIntervalMs)
58+
isOpen = true;
59+
});
60+
61+
ws.addEventListener("close", (event) => {
62+
clearInterval(intervalId)
63+
})
64+
65+
</script>
66+
</body>
67+
</html>

main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,9 @@ func main() {
1010
go keyboard.Listen()
1111
defer keyboard.Close()
1212

13+
httpServer := NewHttpInputHandler(game)
14+
defer httpServer.Close()
15+
go httpServer.Listen(":8080")
16+
1317
game.Run()
1418
}

renderer.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"fmt"
5-
"log"
65
"os"
76

87
"golang.org/x/term"
@@ -109,8 +108,6 @@ func NewRenderer() *Renderer {
109108
if width > height && width > 100 {
110109
gameCols -= scoreboardWidth
111110
scoreboard = true
112-
} else {
113-
log.Println("Terminal too small for scoreboard, hiding it.")
114111
}
115112

116113
r := Renderer{
@@ -175,7 +172,6 @@ func (r *Renderer) bufferScoreboard(g *Game, b [][]character) {
175172
}
176173

177174
for i, p := range scoreboard {
178-
log.Println(p.Id)
179175
name := PlayerNames[p.Id]
180176
scoreText := fmt.Sprintf("%s: %d", name, 100)
181177
for j, char := range scoreText {

0 commit comments

Comments
 (0)