Refactor messages handling
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
be83334e3a
commit
9b5ad472c7
6 changed files with 231 additions and 87 deletions
|
@ -1,13 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
room "git.fromouter.space/mcg/cardgage/room/api"
|
||||
"git.fromouter.space/mcg/draft"
|
||||
)
|
||||
|
||||
type draftBot struct {
|
||||
// DraftBot is the functional part of draftbot
|
||||
type DraftBot struct {
|
||||
API BotInterface
|
||||
Name string
|
||||
Rooms map[string]roomInfo
|
||||
|
@ -25,15 +23,18 @@ type BotInterface interface {
|
|||
Send(room.BotMessage)
|
||||
}
|
||||
|
||||
func newDraftBot(botAPI BotInterface, name string) *draftBot {
|
||||
return &draftBot{
|
||||
// NewDraftBot creates a new draft bot instance with the given name
|
||||
// and communication interface
|
||||
func NewDraftBot(botAPI BotInterface, name string) *DraftBot {
|
||||
return &DraftBot{
|
||||
API: botAPI,
|
||||
Name: name,
|
||||
Sessions: make(map[string]session),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *draftBot) onMessage(msg room.ServerMessage) {
|
||||
// OnMessage is the function to be called when messages are received
|
||||
func (d *DraftBot) OnMessage(msg room.ServerMessage) {
|
||||
switch msg.Type {
|
||||
case room.MsgMessage:
|
||||
if *logAll {
|
||||
|
@ -53,10 +54,11 @@ func (d *draftBot) onMessage(msg room.ServerMessage) {
|
|||
"roomid", msg.RoomID,
|
||||
"content", msg.Event.Message)
|
||||
}
|
||||
d.handleEvent(msg.RoomID, *msg.Event)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *draftBot) sendMessage(roomid string, msg room.Message) {
|
||||
func (d *DraftBot) sendMessage(roomid string, msg room.Message) {
|
||||
d.API.Send(room.BotMessage{
|
||||
RoomID: roomid,
|
||||
Type: room.MsgMessage,
|
||||
|
@ -64,96 +66,61 @@ func (d *draftBot) sendMessage(roomid string, msg room.Message) {
|
|||
})
|
||||
}
|
||||
|
||||
func (d *draftBot) handleMessage(roomid string, msg room.Message) {
|
||||
func (d *DraftBot) handleMessage(roomid string, msg room.Message) {
|
||||
// Get session in room
|
||||
session, ok := d.Sessions[roomid]
|
||||
if !ok {
|
||||
// Room does not have a currently running session, ignore unless it's the owner asking for specific stuff
|
||||
//TODO
|
||||
|
||||
d.commands(commandMap{
|
||||
// Owner wants to create a session
|
||||
"create": d.cmdfnOnlyOwner(d.cmdCreateSession),
|
||||
})(roomid, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if player is in the draft
|
||||
player, ok := session.Players[msg.From]
|
||||
_, ok = session.Players[msg.From]
|
||||
if !ok {
|
||||
// Player not in draft, are they asking to join?
|
||||
switch msg.Type {
|
||||
// Player is asking to join
|
||||
case "join":
|
||||
// Players can only join if session didn't start yet
|
||||
if session.started {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "session-already-started",
|
||||
Message: "You can't join a running session",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if there are still open slots
|
||||
if len(session.Players)+1 > len(session.Pod.Players) {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "session-full",
|
||||
Message: "There aren't any spots left",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Add player to the list
|
||||
session.Players[msg.From] = nil
|
||||
|
||||
d.sendMessage(roomid, room.Message{
|
||||
Channel: "draft",
|
||||
Type: "player-joined-session",
|
||||
Data: msg.From,
|
||||
Message: fmt.Sprintf("%s joined the draft session (%d players, %d missing)", msg.From, len(session.Players), len(session.Pod.Players)-len(session.Players)),
|
||||
})
|
||||
|
||||
// Player wants something else
|
||||
default:
|
||||
// Tell them can either join or GTFO
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "not-joined-err",
|
||||
Data: "not joined",
|
||||
Message: "You must join the session to do anything",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
d.commands(commandMap{
|
||||
// Player wants to join the session
|
||||
"join": d.cmdJoinSession,
|
||||
})(roomid, msg)
|
||||
return
|
||||
}
|
||||
|
||||
switch msg.Type {
|
||||
// Player has picked a card
|
||||
case "pick":
|
||||
// Get picked card
|
||||
picked := msg.Data.(string)
|
||||
// Players in the draft session
|
||||
d.commands(commandMap{
|
||||
// Player has picked a card
|
||||
"pick": d.cmdPickCard,
|
||||
|
||||
// Try to pick on player struct
|
||||
err := player.Pick(draft.Card{ID: picked})
|
||||
if err != nil {
|
||||
if err == draft.ErrNotInPack {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "invalid-pick",
|
||||
})
|
||||
} else {
|
||||
// Technically not needed, as Pick can only throw ErrNotInPack right now
|
||||
}
|
||||
return
|
||||
// Owner wants to start the session
|
||||
"start": d.cmdfnOnlyOwner(d.cmdStartSession),
|
||||
})(roomid, msg)
|
||||
}
|
||||
|
||||
func (d *DraftBot) handleEvent(roomid string, evt room.Event) {
|
||||
switch evt.Type {
|
||||
|
||||
// Got added to a new room
|
||||
case room.EvtNewRoom:
|
||||
// Add room to the list
|
||||
d.Rooms[evt.Room.Id] = roomInfo{
|
||||
Name: evt.Room.Name,
|
||||
Owner: evt.Room.Creator,
|
||||
}
|
||||
d.sendMessage(roomid, room.Message{
|
||||
Channel: "draft",
|
||||
Type: "card-picked",
|
||||
Data: struct {
|
||||
Player string
|
||||
}{
|
||||
msg.From,
|
||||
},
|
||||
Message: fmt.Sprintf("%s picked a card from his pack", msg.From),
|
||||
})
|
||||
|
||||
// A room got closed
|
||||
case room.EvtRoomClosed:
|
||||
// Check if there's a session there
|
||||
session, ok := d.Sessions[roomid]
|
||||
if ok {
|
||||
// Close session
|
||||
session.exit <- true
|
||||
// Remove session from list
|
||||
delete(d.Sessions, roomid)
|
||||
}
|
||||
// Remove room from list
|
||||
delete(d.Rooms, roomid)
|
||||
}
|
||||
}
|
||||
|
|
133
draftbot/draftbot.messages.go
Normal file
133
draftbot/draftbot.messages.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
room "git.fromouter.space/mcg/cardgage/room/api"
|
||||
"git.fromouter.space/mcg/draft"
|
||||
)
|
||||
|
||||
type commandHandler func(roomid string, msg room.Message)
|
||||
type commandMap map[string]commandHandler
|
||||
|
||||
func (d *DraftBot) commands(commands commandMap) commandHandler {
|
||||
return func(roomid string, msg room.Message) {
|
||||
action, ok := commands[msg.Type]
|
||||
if !ok {
|
||||
cmdlist := []string{}
|
||||
for cmd := range commands {
|
||||
cmdlist = append(cmdlist, cmd)
|
||||
}
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "command-unavailable",
|
||||
Message: fmt.Sprintf("Available commands (at this state) are: %s", cmdlist),
|
||||
})
|
||||
return
|
||||
}
|
||||
action(roomid, msg)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DraftBot) cmdJoinSession(roomid string, msg room.Message) {
|
||||
// Get session
|
||||
session, _ := d.Sessions[roomid]
|
||||
|
||||
// Players can only join if session didn't start yet
|
||||
if session.started {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "session-already-started",
|
||||
Message: "You can't join a running session",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Check if there are still open slots
|
||||
if len(session.Players)+1 > len(session.Pod.Players) {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "session-full",
|
||||
Message: "There aren't any spots left",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Add player to the list
|
||||
session.Players[msg.From] = nil
|
||||
|
||||
d.sendMessage(roomid, room.Message{
|
||||
Channel: "draft",
|
||||
Type: "player-joined-session",
|
||||
Data: msg.From,
|
||||
Message: fmt.Sprintf("%s joined the draft session (%d players, %d missing)", msg.From, len(session.Players), len(session.Pod.Players)-len(session.Players)),
|
||||
})
|
||||
}
|
||||
|
||||
func (d *DraftBot) cmdPickCard(roomid string, msg room.Message) {
|
||||
// Get session
|
||||
session, _ := d.Sessions[roomid]
|
||||
|
||||
// Get player
|
||||
player, _ := session.Players[msg.From]
|
||||
|
||||
// Get picked card
|
||||
picked := msg.Data.(string)
|
||||
|
||||
// Try to pick on player struct
|
||||
err := player.Pick(draft.Card{ID: picked})
|
||||
if err != nil {
|
||||
if err == draft.ErrNotInPack {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "invalid-pick",
|
||||
})
|
||||
} else {
|
||||
// Technically not needed, as Pick can only throw ErrNotInPack right now
|
||||
}
|
||||
return
|
||||
}
|
||||
d.sendMessage(roomid, room.Message{
|
||||
Channel: "draft",
|
||||
Type: "card-picked",
|
||||
Data: struct {
|
||||
Player string
|
||||
}{
|
||||
msg.From,
|
||||
},
|
||||
Message: fmt.Sprintf("%s picked a card from his pack", msg.From),
|
||||
})
|
||||
}
|
||||
|
||||
func (d *DraftBot) cmdCreateSession(roomid string, msg room.Message) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
func (d *DraftBot) cmdStartSession(roomid string, msg room.Message) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
func (d *DraftBot) cmdfnOnlyOwner(wrapped commandHandler) commandHandler {
|
||||
return func(roomid string, msg room.Message) {
|
||||
// Get room the message was sent from
|
||||
roomData, ok := d.Rooms[roomid]
|
||||
if !ok {
|
||||
// Message from a room we're not in?
|
||||
// Ignore it for now
|
||||
return
|
||||
}
|
||||
|
||||
// Make sure the message is coming from the room owner
|
||||
if msg.From != roomData.Owner {
|
||||
d.sendMessage(roomid, room.Message{
|
||||
To: msg.From,
|
||||
Type: "no-session",
|
||||
Message: "Sorry, only the owner can speak to me when no session is active",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Check done, call wrapped function
|
||||
wrapped(roomid, msg)
|
||||
}
|
||||
}
|
42
draftbot/draftbot_test.go
Normal file
42
draftbot/draftbot_test.go
Normal file
|
@ -0,0 +1,42 @@
|
|||
package main_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.fromouter.space/mcg/cardgage/client/bot"
|
||||
room "git.fromouter.space/mcg/cardgage/room/api"
|
||||
draft "git.fromouter.space/mcg/mlp-server-tools/draftbot"
|
||||
)
|
||||
|
||||
type MockServer struct {
|
||||
in chan room.ServerMessage
|
||||
out chan room.BotMessage
|
||||
}
|
||||
|
||||
func makeMockServer() *MockServer {
|
||||
in := make(chan room.ServerMessage)
|
||||
out := make(chan room.BotMessage)
|
||||
srv := &MockServer{
|
||||
in: in,
|
||||
out: out,
|
||||
}
|
||||
return srv
|
||||
}
|
||||
|
||||
func (m *MockServer) Send(msg room.BotMessage) {
|
||||
m.out <- msg
|
||||
}
|
||||
|
||||
func (m *MockServer) Bind(fn bot.MessageHandler) {
|
||||
for msg := range m.in {
|
||||
fn(msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDraftSession(t *testing.T) {
|
||||
mock := makeMockServer()
|
||||
draftbot := draft.NewDraftBot(mock, "bot")
|
||||
go mock.Bind(draftbot.OnMessage)
|
||||
|
||||
//TODO sample session
|
||||
}
|
|
@ -4,7 +4,7 @@ go 1.12
|
|||
|
||||
require (
|
||||
git.fromouter.space/Artificiale/moa v0.0.1-p2
|
||||
git.fromouter.space/mcg/cardgage v0.0.2
|
||||
git.fromouter.space/mcg/cardgage v0.0.4
|
||||
git.fromouter.space/mcg/draft v0.0.2
|
||||
github.com/go-kit/kit v0.8.0
|
||||
)
|
||||
|
|
|
@ -5,6 +5,8 @@ git.fromouter.space/mcg/cardgage v0.0.1-p2 h1:u65ofEmtDHHQ8nbai97DW9kcrYa4x0I3NH
|
|||
git.fromouter.space/mcg/cardgage v0.0.1-p2/go.mod h1:vCmJ9HRdRGSWg2YQW9oNG7geYACdgWYmzL+zZdrsYhQ=
|
||||
git.fromouter.space/mcg/cardgage v0.0.2 h1:u3Wz+UJx0wEix7vlqMlDX9Kg8nplCy8A0+nIKdNNPp0=
|
||||
git.fromouter.space/mcg/cardgage v0.0.2/go.mod h1:vCmJ9HRdRGSWg2YQW9oNG7geYACdgWYmzL+zZdrsYhQ=
|
||||
git.fromouter.space/mcg/cardgage v0.0.4 h1:LHMUeNMh0QiMkM3TgsLe9l5sDmanQrej6UiWSVTb67c=
|
||||
git.fromouter.space/mcg/cardgage v0.0.4/go.mod h1:vCmJ9HRdRGSWg2YQW9oNG7geYACdgWYmzL+zZdrsYhQ=
|
||||
git.fromouter.space/mcg/draft v0.0.2 h1:OT1uztgfCZnZCOg3uOtjQKH2WdwRAxNdYr4KXklVgXY=
|
||||
git.fromouter.space/mcg/draft v0.0.2/go.mod h1:QQmDm9FgAZL3b2/pIDd4Eo608SxMiCQQe5vIybe/CDY=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
|
|
|
@ -81,8 +81,8 @@ func runBot(name string, games, tags []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
draftbot := newDraftBot(wsbot, name)
|
||||
wsbot.Listen(draftbot.onMessage)
|
||||
draftbot := NewDraftBot(wsbot, name)
|
||||
wsbot.Listen(draftbot.OnMessage)
|
||||
|
||||
return errors.New("eof")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue