A ton of work getting towards dms.
This commit also points to my fork of discordgo which makes it look like the official client which is the only way to get the actually contents of a dm when not authorized as a bot.
This commit is contained in:
183
bridge/portal.go
183
bridge/portal.go
@@ -2,9 +2,12 @@ package bridge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
|
||||
log "maunium.net/go/maulogger/v2"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/appservice"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
@@ -12,7 +15,12 @@ import (
|
||||
"gitlab.com/beeper/discord/database"
|
||||
)
|
||||
|
||||
type PortalMatrixMessage struct {
|
||||
type portalDiscordMessage struct {
|
||||
msg interface{}
|
||||
user *User
|
||||
}
|
||||
|
||||
type portalMatrixMessage struct {
|
||||
evt *event.Event
|
||||
user *User
|
||||
}
|
||||
@@ -23,9 +31,18 @@ type Portal struct {
|
||||
bridge *Bridge
|
||||
log log.Logger
|
||||
|
||||
matrixMessages chan PortalMatrixMessage
|
||||
channelType discordgo.ChannelType
|
||||
|
||||
roomCreateLock sync.Mutex
|
||||
|
||||
discordMessages chan portalDiscordMessage
|
||||
matrixMessages chan portalMatrixMessage
|
||||
}
|
||||
|
||||
var (
|
||||
portalCreationDummyEvent = event.Type{Type: "fi.mau.dummy.portal_created", Class: event.MessageEventType}
|
||||
)
|
||||
|
||||
func (b *Bridge) loadPortal(dbPortal *database.Portal, key *database.PortalKey) *Portal {
|
||||
// If we weren't given a portal we'll attempt to create it if a key was
|
||||
// provided.
|
||||
@@ -63,13 +80,26 @@ func (b *Bridge) GetPortalByMXID(mxid id.RoomID) *Portal {
|
||||
return portal
|
||||
}
|
||||
|
||||
func (b *Bridge) GetPortalByID(key database.PortalKey) *Portal {
|
||||
b.portalsLock.Lock()
|
||||
defer b.portalsLock.Unlock()
|
||||
|
||||
portal, ok := b.portalsByID[key]
|
||||
if !ok {
|
||||
return b.loadPortal(b.db.Portal.GetByID(key), &key)
|
||||
}
|
||||
|
||||
return portal
|
||||
}
|
||||
|
||||
func (b *Bridge) NewPortal(dbPortal *database.Portal) *Portal {
|
||||
portal := &Portal{
|
||||
Portal: dbPortal,
|
||||
bridge: b,
|
||||
log: b.log.Sub(fmt.Sprintf("Portal/%s", dbPortal.Key)),
|
||||
|
||||
matrixMessages: make(chan PortalMatrixMessage, b.config.Bridge.PortalMessageBuffer),
|
||||
discordMessages: make(chan portalDiscordMessage, b.Config.Bridge.PortalMessageBuffer),
|
||||
matrixMessages: make(chan portalMatrixMessage, b.Config.Bridge.PortalMessageBuffer),
|
||||
}
|
||||
|
||||
go portal.messageLoop()
|
||||
@@ -91,13 +121,15 @@ func (p *Portal) messageLoop() {
|
||||
for {
|
||||
select {
|
||||
case msg := <-p.matrixMessages:
|
||||
p.log.Infoln("got message", msg)
|
||||
p.log.Infoln("got matrix message", msg)
|
||||
case msg := <-p.discordMessages:
|
||||
p.handleDiscordMessage(msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Portal) IsPrivateChat() bool {
|
||||
return false
|
||||
return (p.channelType == discordgo.ChannelTypeDM || p.channelType == discordgo.ChannelTypeGroupDM)
|
||||
}
|
||||
|
||||
func (p *Portal) MainIntent() *appservice.IntentAPI {
|
||||
@@ -107,3 +139,142 @@ func (p *Portal) MainIntent() *appservice.IntentAPI {
|
||||
|
||||
return p.bridge.bot
|
||||
}
|
||||
|
||||
func (p *Portal) createMatrixRoom(user *User, channel *discordgo.Channel) error {
|
||||
p.roomCreateLock.Lock()
|
||||
defer p.roomCreateLock.Unlock()
|
||||
|
||||
// If we have a matrix id the room should exist so we have nothing to do.
|
||||
if p.MXID != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.channelType = channel.Type
|
||||
|
||||
intent := p.MainIntent()
|
||||
if err := intent.EnsureRegistered(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.IsPrivateChat() {
|
||||
puppet := p.bridge.GetPuppetByID(p.Key.ID)
|
||||
puppet.SyncContact(user)
|
||||
|
||||
p.Name = puppet.DisplayName
|
||||
p.Avatar = puppet.Avatar
|
||||
p.AvatarURL = puppet.AvatarURL
|
||||
}
|
||||
|
||||
p.log.Infoln("Creating Matrix room. Info source:", p.Portal.Key.ID)
|
||||
|
||||
initialState := []*event.Event{}
|
||||
|
||||
creationContent := make(map[string]interface{})
|
||||
// if !portal.bridge.Config.Bridge.FederateRooms {
|
||||
creationContent["m.federate"] = false
|
||||
// }
|
||||
|
||||
var invite []id.UserID
|
||||
|
||||
if p.IsPrivateChat() {
|
||||
invite = append(invite, p.bridge.bot.UserID)
|
||||
}
|
||||
|
||||
resp, err := intent.CreateRoom(&mautrix.ReqCreateRoom{
|
||||
Visibility: "private",
|
||||
Name: p.Name,
|
||||
Topic: p.Topic,
|
||||
Preset: "private_chat",
|
||||
IsDirect: p.IsPrivateChat(),
|
||||
InitialState: initialState,
|
||||
CreationContent: creationContent,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.MXID = resp.RoomID
|
||||
p.Update()
|
||||
p.bridge.portalsLock.Lock()
|
||||
p.bridge.portalsByMXID[p.MXID] = p
|
||||
p.bridge.portalsLock.Unlock()
|
||||
|
||||
p.ensureUserInvited(user)
|
||||
|
||||
// if p.IsPrivateChat() {
|
||||
// puppet := user.bridge.GetPuppetByID(p.Key.ID)
|
||||
|
||||
// if p.bridge.Config.Bridge.Encryption.Default {
|
||||
// err = portal.bridge.Bot.EnsureJoined(portal.MXID)
|
||||
// if err != nil {
|
||||
// portal.log.Errorln("Failed to join created portal with bridge bot for e2be:", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// user.UpdateDirectChats(map[id.UserID][]id.RoomID{puppet.MXID: {portal.MXID}})
|
||||
// }
|
||||
|
||||
firstEventResp, err := p.MainIntent().SendMessageEvent(p.MXID, portalCreationDummyEvent, struct{}{})
|
||||
if err != nil {
|
||||
p.log.Errorln("Failed to send dummy event to mark portal creation:", err)
|
||||
} else {
|
||||
p.FirstEventID = firstEventResp.EventID
|
||||
p.Update()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Portal) handleDiscordMessage(msg portalDiscordMessage) {
|
||||
if p.MXID == "" {
|
||||
p.log.Debugln("Creating Matrix room from incoming message")
|
||||
|
||||
discordMsg := msg.msg.(*discordgo.MessageCreate)
|
||||
channel, err := msg.user.Session.Channel(discordMsg.ChannelID)
|
||||
if err != nil {
|
||||
p.log.Errorln("Failed to find channel for message:", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err := p.createMatrixRoom(msg.user, channel); err != nil {
|
||||
p.log.Errorln("Failed to create portal room:", err)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch msg.msg.(type) {
|
||||
case *discordgo.MessageCreate:
|
||||
p.handleMessage(msg.msg.(*discordgo.MessageCreate).Message)
|
||||
default:
|
||||
p.log.Warnln("unknown message type")
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Portal) ensureUserInvited(user *User) bool {
|
||||
return user.ensureInvited(p.MainIntent(), p.MXID, p.IsPrivateChat())
|
||||
}
|
||||
|
||||
func (p *Portal) handleMessage(msg *discordgo.Message) {
|
||||
if p.MXID == "" {
|
||||
p.log.Warnln("handle message called without a valid portal")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Check if we already got the message
|
||||
|
||||
p.log.Debugln("content", msg.Content)
|
||||
p.log.Debugln("embeds", msg.Embeds)
|
||||
p.log.Debugln("msg", msg)
|
||||
|
||||
content := &event.MessageEventContent{
|
||||
Body: msg.Content,
|
||||
MsgType: event.MsgText,
|
||||
}
|
||||
|
||||
resp, err := p.MainIntent().SendMessageEvent(p.MXID, event.EventMessage, content)
|
||||
p.log.Warnln("response:", resp)
|
||||
p.log.Warnln("error:", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user