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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
room "git.fromouter.space/mcg/cardgage/room/api"
|
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
|
API BotInterface
|
||||||
Name string
|
Name string
|
||||||
Rooms map[string]roomInfo
|
Rooms map[string]roomInfo
|
||||||
|
@ -25,15 +23,18 @@ type BotInterface interface {
|
||||||
Send(room.BotMessage)
|
Send(room.BotMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDraftBot(botAPI BotInterface, name string) *draftBot {
|
// NewDraftBot creates a new draft bot instance with the given name
|
||||||
return &draftBot{
|
// and communication interface
|
||||||
|
func NewDraftBot(botAPI BotInterface, name string) *DraftBot {
|
||||||
|
return &DraftBot{
|
||||||
API: botAPI,
|
API: botAPI,
|
||||||
Name: name,
|
Name: name,
|
||||||
Sessions: make(map[string]session),
|
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 {
|
switch msg.Type {
|
||||||
case room.MsgMessage:
|
case room.MsgMessage:
|
||||||
if *logAll {
|
if *logAll {
|
||||||
|
@ -53,10 +54,11 @@ func (d *draftBot) onMessage(msg room.ServerMessage) {
|
||||||
"roomid", msg.RoomID,
|
"roomid", msg.RoomID,
|
||||||
"content", msg.Event.Message)
|
"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{
|
d.API.Send(room.BotMessage{
|
||||||
RoomID: roomid,
|
RoomID: roomid,
|
||||||
Type: room.MsgMessage,
|
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
|
// Get session in room
|
||||||
session, ok := d.Sessions[roomid]
|
session, ok := d.Sessions[roomid]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Room does not have a currently running session, ignore unless it's the owner asking for specific stuff
|
// 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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if player is in the draft
|
// Check if player is in the draft
|
||||||
player, ok := session.Players[msg.From]
|
_, ok = session.Players[msg.From]
|
||||||
if !ok {
|
if !ok {
|
||||||
// Player not in draft, are they asking to join?
|
// Player not in draft, are they asking to join?
|
||||||
switch msg.Type {
|
d.commands(commandMap{
|
||||||
// Player is asking to join
|
// Player wants to join the session
|
||||||
case "join":
|
"join": d.cmdJoinSession,
|
||||||
// Players can only join if session didn't start yet
|
})(roomid, msg)
|
||||||
if session.started {
|
|
||||||
d.sendMessage(roomid, room.Message{
|
|
||||||
To: msg.From,
|
|
||||||
Type: "session-already-started",
|
|
||||||
Message: "You can't join a running session",
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are still open slots
|
// Players in the draft session
|
||||||
if len(session.Players)+1 > len(session.Pod.Players) {
|
d.commands(commandMap{
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch msg.Type {
|
|
||||||
// Player has picked a card
|
// Player has picked a card
|
||||||
case "pick":
|
"pick": d.cmdPickCard,
|
||||||
// Get picked card
|
|
||||||
picked := msg.Data.(string)
|
|
||||||
|
|
||||||
// Try to pick on player struct
|
// Owner wants to start the session
|
||||||
err := player.Pick(draft.Card{ID: picked})
|
"start": d.cmdfnOnlyOwner(d.cmdStartSession),
|
||||||
if err != nil {
|
})(roomid, msg)
|
||||||
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
|
|
||||||
|
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",
|
// A room got closed
|
||||||
Type: "card-picked",
|
case room.EvtRoomClosed:
|
||||||
Data: struct {
|
// Check if there's a session there
|
||||||
Player string
|
session, ok := d.Sessions[roomid]
|
||||||
}{
|
if ok {
|
||||||
msg.From,
|
// Close session
|
||||||
},
|
session.exit <- true
|
||||||
Message: fmt.Sprintf("%s picked a card from his pack", msg.From),
|
// 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 (
|
require (
|
||||||
git.fromouter.space/Artificiale/moa v0.0.1-p2
|
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
|
git.fromouter.space/mcg/draft v0.0.2
|
||||||
github.com/go-kit/kit v0.8.0
|
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.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 h1:u3Wz+UJx0wEix7vlqMlDX9Kg8nplCy8A0+nIKdNNPp0=
|
||||||
git.fromouter.space/mcg/cardgage v0.0.2/go.mod h1:vCmJ9HRdRGSWg2YQW9oNG7geYACdgWYmzL+zZdrsYhQ=
|
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 h1:OT1uztgfCZnZCOg3uOtjQKH2WdwRAxNdYr4KXklVgXY=
|
||||||
git.fromouter.space/mcg/draft v0.0.2/go.mod h1:QQmDm9FgAZL3b2/pIDd4Eo608SxMiCQQe5vIybe/CDY=
|
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=
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
draftbot := newDraftBot(wsbot, name)
|
draftbot := NewDraftBot(wsbot, name)
|
||||||
wsbot.Listen(draftbot.onMessage)
|
wsbot.Listen(draftbot.OnMessage)
|
||||||
|
|
||||||
return errors.New("eof")
|
return errors.New("eof")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue