261 lines
7.0 KiB
Go
261 lines
7.0 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
|
|
"maunium.net/go/mautrix"
|
|
"maunium.net/go/mautrix/event"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
type Dealer struct {
|
|
RoomsList map[id.RoomID]*Match
|
|
PlayerRooms map[id.UserID]id.RoomID
|
|
Client *mautrix.Client
|
|
QueueRoom id.RoomID
|
|
HomeserverDomain string
|
|
}
|
|
|
|
func (d *Dealer) ConnectToMatrix(homeserver, uname, passwd string) {
|
|
log.Println("Logging into", homeserver, "as", uname)
|
|
client, err := mautrix.NewClient(homeserver, "", "")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
client.Store = NewLazyMemStore("dealer_state")
|
|
_, err = client.Login(&mautrix.ReqLogin{
|
|
Type: "m.login.password",
|
|
Identifier: mautrix.UserIdentifier{Type: mautrix.IdentifierTypeUser, User: uname},
|
|
Password: passwd,
|
|
StoreCredentials: true,
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fmt.Println("Login successful")
|
|
d.Client = client
|
|
}
|
|
|
|
func (d *Dealer) RegisterHandlers() {
|
|
syncer := d.Client.Syncer.(*mautrix.DefaultSyncer)
|
|
syncer.OnEventType(event.StateMember, func(source mautrix.EventSource, evt *event.Event) {
|
|
if evt.Sender == d.Client.UserID {
|
|
return
|
|
}
|
|
if evt.RoomID == d.QueueRoom {
|
|
d.QueueEvent(evt)
|
|
return
|
|
}
|
|
proom, ok := d.PlayerRooms[evt.Sender]
|
|
if ok {
|
|
log.Printf("membership event for player room %v", proom)
|
|
if evt.Content.AsMember().Membership.IsLeaveOrBan() {
|
|
delete(d.PlayerRooms, evt.Sender)
|
|
return
|
|
}
|
|
}
|
|
if evt.Content.AsMember().IsDirect {
|
|
//intention to create player room
|
|
if evt.Content.AsMember().Membership.IsInviteOrJoin() {
|
|
d.PlayerRooms[evt.Sender] = evt.RoomID
|
|
_, err := d.Client.JoinRoomByID(evt.RoomID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} else if evt.Content.AsMember().Membership.IsLeaveOrBan() {
|
|
delete(d.PlayerRooms, evt.Sender)
|
|
}
|
|
return
|
|
}
|
|
match, ok := d.RoomsList[evt.RoomID]
|
|
if !ok {
|
|
log.Printf("received membership event for non active game: %v", evt)
|
|
return
|
|
}
|
|
if evt.Sender != match.P1 && evt.Sender != match.P2 && evt.Sender != d.Client.UserID {
|
|
log.Println("membership event for non player")
|
|
return
|
|
}
|
|
members, err := d.Client.JoinedMembers(evt.RoomID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
match.JoinOrLeave(members.Joined, evt.Content.AsMember())
|
|
})
|
|
syncer.OnEventType(event.EventMessage, func(source mautrix.EventSource, evt *event.Event) {
|
|
playerRoom, pok := d.PlayerRooms[evt.Sender]
|
|
if pok {
|
|
log.Printf("received direct message in room %v", playerRoom)
|
|
var roominfo PlayerRoomInfo
|
|
_ = d.Client.StateEvent(playerRoom, event.Type{"snen.player", event.StateEventType}, "player_info", &roominfo)
|
|
if roominfo.CurrentGame != "" {
|
|
//parse as gamecommand
|
|
match := d.RoomsList[roominfo.CurrentGame]
|
|
if match.Game == nil {
|
|
d.Client.SendText(playerRoom, "can't accept game commands yet")
|
|
return
|
|
}
|
|
resp := match.ParseAction(evt.Content.AsMessage().Body)
|
|
if resp.Body != "" {
|
|
_, err := d.Client.SendText(playerRoom, resp.Body)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
d.Client.SendText(roominfo.CurrentGame, fmt.Sprintf("%v played %v", evt.Sender, evt.Content.AsMessage().Body))
|
|
|
|
if !resp.Private {
|
|
d.Client.SendText(roominfo.CurrentGame, fmt.Sprintf("Result: %v", resp.Body))
|
|
}
|
|
}
|
|
} else {
|
|
//parse as out of game command
|
|
log.Println("out of game command received")
|
|
//TODO make this better
|
|
msg := evt.Content.AsMessage().Body
|
|
msg_s := strings.Split(msg, " ")
|
|
if msg_s[0] == "direct" {
|
|
d.NewMatch(evt.Sender, id.NewUserID(msg_s[1], d.HomeserverDomain))
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
}
|
|
match, ok := d.RoomsList[evt.RoomID]
|
|
if !ok {
|
|
log.Println("received message event for non active game")
|
|
return
|
|
}
|
|
if !match.IsPlayer(evt.Sender) {
|
|
log.Println("ignoring message event from non player")
|
|
return
|
|
}
|
|
//parse as in game command i.e. chat
|
|
})
|
|
}
|
|
|
|
func (d *Dealer) SetupRooms(domain string) {
|
|
room := "#tomequeue:" + domain
|
|
// try creating the room first
|
|
res, createErr := d.Client.CreateRoom(&mautrix.ReqCreateRoom{
|
|
Preset: "public_chat",
|
|
Visibility: "public",
|
|
RoomAliasName: "tomequeue",
|
|
})
|
|
if createErr != nil {
|
|
//okay let's try joining the room first
|
|
res, err := d.Client.JoinRoom(room, "", nil)
|
|
if err != nil {
|
|
log.Println("unable to create or join queue room")
|
|
log.Printf("Create err: %v", createErr)
|
|
panic(err)
|
|
}
|
|
log.Printf("succesfully joined %v", res.RoomID)
|
|
d.QueueRoom = res.RoomID
|
|
return
|
|
}
|
|
resJoin, err := d.Client.JoinRoomByID(res.RoomID)
|
|
if err != nil {
|
|
log.Println("error joined recently created queue room")
|
|
panic(err)
|
|
}
|
|
log.Printf("succesfully created and joined %v", resJoin.RoomID)
|
|
d.QueueRoom = resJoin.RoomID
|
|
//load player rooms
|
|
joinedResp, err := d.Client.JoinedRooms()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for _, r := range joinedResp.JoinedRooms {
|
|
tags, err := d.Client.GetTags(r)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
_, ok := tags.Tags["tome_player_room"]
|
|
if !ok {
|
|
continue
|
|
}
|
|
memberListResp, err := d.Client.JoinedMembers(r)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
keys := make([]id.UserID, 0, len(memberListResp.Joined))
|
|
for k := range memberListResp.Joined {
|
|
keys = append(keys, k)
|
|
}
|
|
if len(keys) != 2 {
|
|
log.Printf("tagged player room %v has more then 2 members")
|
|
continue
|
|
}
|
|
for _, k := range keys {
|
|
if k != d.Client.UserID {
|
|
d.PlayerRooms[k] = r
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func (d *Dealer) NewMatch(p1, p2 id.UserID) *Match {
|
|
//creates a new matrix room for the match
|
|
match := NewMatch()
|
|
roomname := fmt.Sprintf("tome_match_%v", match.ID)
|
|
createRes, err := d.Client.CreateRoom(&mautrix.ReqCreateRoom{
|
|
Preset: "public_chat",
|
|
RoomAliasName: roomname,
|
|
Invite: []id.UserID{p1, p2},
|
|
})
|
|
if err != nil {
|
|
log.Println("error creating matrix room for match")
|
|
panic(err)
|
|
}
|
|
match.MatrixRoom = createRes.RoomID
|
|
match.P1 = p1
|
|
match.P1Room = d.PlayerRooms[p1]
|
|
match.P2 = p2
|
|
match.P2Room = d.PlayerRooms[p2]
|
|
match.Dealer = d.Client.UserID
|
|
d.RoomsList[createRes.RoomID] = match
|
|
|
|
d.Client.SendStateEvent(match.P1Room, event.Type{"snen.player", event.StateEventType}, "player_info", PlayerRoomInfo{
|
|
CurrentGame: match.MatrixRoom,
|
|
CurrentDeck: []int{},
|
|
})
|
|
d.Client.SendStateEvent(match.P2Room, event.Type{"snen.player", event.StateEventType}, "player_info", PlayerRoomInfo{
|
|
CurrentGame: match.MatrixRoom,
|
|
CurrentDeck: []int{},
|
|
})
|
|
|
|
return match
|
|
}
|
|
|
|
func (d *Dealer) QueueEvent(evt *event.Event) {
|
|
mem := evt.Content.AsMember()
|
|
if mem.Membership == event.MembershipJoin {
|
|
log.Printf("Player %v has queued", evt.Sender)
|
|
_, ok := d.PlayerRooms[evt.Sender]
|
|
if !ok {
|
|
//open up DM with player
|
|
createRes, err := d.Client.CreateRoom(&mautrix.ReqCreateRoom{
|
|
Preset: "private_chat",
|
|
Invite: []id.UserID{evt.Sender},
|
|
IsDirect: true,
|
|
})
|
|
if err != nil {
|
|
log.Println("error creating matrix room for player")
|
|
panic(err)
|
|
}
|
|
d.PlayerRooms[evt.Sender] = createRes.RoomID
|
|
err = d.Client.AddTag(createRes.RoomID, "tome_player_room", 0.0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
} else if mem.Membership.IsLeaveOrBan() {
|
|
log.Printf("Player %v has dequeued", evt.Sender)
|
|
}
|
|
return
|
|
}
|