Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions api/request_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,11 @@ sessionLoop:
rp.sessionManager.Communicate(sessionId, receiverSessionId, msg, mc.MessageTypeJSON)
break sessionLoop

case mc.CodePlayerInteraction:
if err := rp.sessionManager.Communicate(sessionId, receiverSessionId, payload, mc.MessageTypeBytes); err != nil {
break sessionLoop
}

default:
respInvalidSignal := mc.NewMessage[mc.NoPayload](mc.CodeInvalidSignal)
respInvalidSignal.AddError("", "invalid code in the incoming payload")
Expand Down
25 changes: 23 additions & 2 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package main

import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/joho/godotenv"
"github.com/saeidalz13/battleship-backend/api"
Expand Down Expand Up @@ -42,6 +46,23 @@ func main() {
mux := http.NewServeMux()
mux.Handle("GET /battleship", requestProcessor)

log.Printf("Listening to port %s\n", port)
log.Fatalln(http.ListenAndServe("0.0.0.0:"+port, mux))
s := &http.Server{
Addr: ":" + port,
Handler: mux,
}

go func() {
log.Printf("Listening to port %s\n", port)
log.Fatalln(s.ListenAndServe())
}()

sigChan := make(chan os.Signal, 1)

signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
sig := <-sigChan
log.Println("Server termination signal from OS, graceful shutdown\treason:", sig)

ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
s.Shutdown(ctx)
}
4 changes: 4 additions & 0 deletions models/connection/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ func (m *Message[T]) AddPayload(payload T) {
func (m *Message[T]) AddError(errorDetails, message string) {
m.Error = NewRespErr(errorDetails, message)
}

type PlayerInteraction struct {
Content string `json:"content"`
}
3 changes: 3 additions & 0 deletions models/connection/signal.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ const (
CodeRematchCallAccepted
CodeRematchCallRejected
CodeRematch

// Players can send template texts and emojis to each other
CodePlayerInteraction
)

type Signal struct {
Expand Down
46 changes: 46 additions & 0 deletions test/ws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,52 @@ func TestReadyGame(t *testing.T) {
}
}

func TestPlayerInteraction(t *testing.T) {
msg := mc.NewMessage[mc.PlayerInteraction](mc.CodePlayerInteraction)
msg.AddPayload(mc.PlayerInteraction{Content: "salam!"})

tests := []Test[mc.Message[mc.PlayerInteraction], mc.Message[mc.PlayerInteraction]]{
{
name: "successful msg host to join",
expectedCode: mc.CodePlayerInteraction,
reqPayload: msg,
respPayload: mc.Message[mc.PlayerInteraction]{},
conn: HostConn,
otherConn: JoinConn,
},
{
name: "successful msg join to host",
expectedCode: mc.CodePlayerInteraction,
reqPayload: msg,
respPayload: mc.Message[mc.PlayerInteraction]{},
conn: JoinConn,
otherConn: HostConn,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
// Client writes to its own connection
if err := test.conn.WriteJSON(test.reqPayload); err != nil {
t.Fatal(err)
}

// Server writes it to ther other connection
if err := test.otherConn.ReadJSON(&test.respPayload); err != nil {
t.Fatal(err)
}

if test.respPayload.Code != test.expectedCode {
t.Fatalf("expected status: %d\t got: %d", test.expectedCode, test.respPayload.Code)
}

if !reflect.DeepEqual(test.reqPayload, test.respPayload) {
t.Fatalf("expected resp payload: %+v\n got: %+v", test.expectedRespPayload, test.respPayload)
}
})
}
}

func TestAttack(t *testing.T) {
tests := []Test[mc.Message[mc.ReqAttack], mc.Message[mc.RespAttack]]{
{
Expand Down