Start of the bot and it's matrix connection

This commit is contained in:
Gary Kramlich
2021-12-07 19:08:58 -06:00
parent 4be28617e0
commit be3982e585
5 changed files with 209 additions and 6 deletions

41
bridge/bot.go Normal file
View File

@@ -0,0 +1,41 @@
package bridge
import (
"maunium.net/go/mautrix/id"
)
func (b *Bridge) updateBotProfile() {
cfg := b.config.Appservice.Bot
// Set the bot's avatar.
if cfg.Avatar != "" {
var err error
var mxc id.ContentURI
if cfg.Avatar == "remove" {
err = b.bot.SetAvatarURL(mxc)
} else {
mxc, err = id.ParseContentURI(cfg.Avatar)
if err == nil {
err = b.bot.SetAvatarURL(mxc)
}
}
b.log.Warnln("failed to update the bot's avatar: %v", err)
}
// Update the bot's display name.
if cfg.Displayname != "" {
var err error
if cfg.Displayname == "remove" {
err = b.bot.SetDisplayName("")
} else {
err = b.bot.SetDisplayName(cfg.Displayname)
}
if err != nil {
b.log.Warnln("failed to update the bot's display name: %v", err)
}
}
}

View File

@@ -1,13 +1,22 @@
package bridge package bridge
import ( import (
"errors"
"fmt"
"time"
log "maunium.net/go/maulogger/v2" log "maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/appservice" "maunium.net/go/mautrix/appservice"
"gitlab.com/beeper/discord/config" "gitlab.com/beeper/discord/config"
"gitlab.com/beeper/discord/version" "gitlab.com/beeper/discord/version"
) )
const (
reconnectDelay = 10 * time.Second
)
type Bridge struct { type Bridge struct {
config *config.Config config *config.Config
@@ -15,6 +24,7 @@ type Bridge struct {
as *appservice.AppService as *appservice.AppService
eventProcessor *appservice.EventProcessor eventProcessor *appservice.EventProcessor
matrixHandler *matrixHandler
bot *appservice.IntentAPI bot *appservice.IntentAPI
} }
@@ -27,27 +37,83 @@ func New(cfg *config.Config) (*Bridge, error) {
logger.Infoln("Initializing version", version.String) logger.Infoln("Initializing version", version.String)
// Create the app service. // Create and initalize the app service.
appservice, err := cfg.CreateAppService() appservice, err := cfg.CreateAppService()
if err != nil { if err != nil {
return nil, err return nil, err
} }
appservice.Log = log.Sub("matrix") appservice.Log = log.Sub("matrix")
appservice.Init()
// Create the bot.
bot := appservice.BotIntent()
// Create the bridge. // Create the bridge.
bridge := &Bridge{ bridge := &Bridge{
as: appservice,
bot: bot,
config: cfg, config: cfg,
log: logger, log: logger,
as: appservice,
} }
// Setup the event processors
bridge.setupEvents()
return bridge, nil return bridge, nil
} }
func (b *Bridge) Start() { func (b *Bridge) connect() error {
b.log.Infoln("bridge started") b.log.Debugln("Checking connection to homeserver")
for {
resp, err := b.bot.Whoami()
if err != nil {
if errors.Is(err, mautrix.MUnknownToken) {
b.log.Fatalln("Access token invalid. Is the registration installed in your homeserver correctly?")
return fmt.Errorf("invalid access token")
}
b.log.Errorfln("Failed to connect to homeserver : %v", err)
b.log.Errorfln("reconnecting in %s", reconnectDelay)
time.Sleep(reconnectDelay)
} else if resp.UserID != b.bot.UserID {
b.log.Fatalln("Unexpected user ID in whoami call: got %s, expected %s", resp.UserID, b.bot.UserID)
return fmt.Errorf("expected user id %q but got %q", b.bot.UserID, resp.UserID)
} else {
break
}
}
b.log.Debugln("Connected to homeserver")
return nil
}
func (b *Bridge) Start() error {
b.log.Infoln("Bridge started")
if err := b.connect(); err != nil {
return err
}
b.log.Debugln("Starting application service HTTP server")
go b.as.Start()
b.log.Debugln("Starting event processor")
go b.eventProcessor.Start()
go b.updateBotProfile()
// Finally tell the appservice we're ready
b.as.Ready = true
return nil
} }
func (b *Bridge) Stop() { func (b *Bridge) Stop() {
b.log.Infoln("bridge stopped") b.log.Infoln("Bridge stopped")
} }

87
bridge/matrix.go Normal file
View File

@@ -0,0 +1,87 @@
package bridge
import (
"maunium.net/go/maulogger/v2"
"maunium.net/go/mautrix/appservice"
"maunium.net/go/mautrix/event"
)
type matrixHandler struct {
as *appservice.AppService
bridge *Bridge
log maulogger.Logger
}
func (b *Bridge) setupEvents() {
b.eventProcessor = appservice.NewEventProcessor(b.as)
b.matrixHandler = &matrixHandler{
as: b.as,
bridge: b,
log: b.log.Sub("Matrix"),
}
b.eventProcessor.On(event.EventMessage, b.matrixHandler.handleMessage)
b.eventProcessor.On(event.StateMember, b.matrixHandler.handleMembership)
}
func (mh *MatrixHandler) join(evt *event.Event, intent *appservice.IntentAPI) *mautrix.RespJoinedMembers {
resp, err := intent.JoinRoomByID(evt.RoomID)
if err != nil {
mh.log.Debugfln("Failed to join room %s as %s with invite from %s: %v", evt.RoomID, intent.UserID, evt.Sender, err)
return nil
}
members, err := intent.JoinedMembers(resp.RoomID)
if err != nil {
intent.LeaveRoom(resp.RoomID)
mh.log.Debugfln("Failed to get members in room %s after accepting invite from %s as %s: %v", resp.RoomID, evt.Sender, intent.UserID, err)
return nil
}
if len(members.Joined) < 2 {
intent.LeaveRoom(resp.RoomID)
mh.log.Debugln("Leaving empty room", resp.RoomID, "after accepting invite from", evt.Sender, "as", intent.UserID)
return nil
}
return members
}
func (mh *matrixHandler) ignoreEvent(evt *event.Event) bool {
return false
}
func (mh *matrixHandler) handleMessage(evt *event.Event) {
if mh.ignoreEvent(evt) {
return
}
mh.log.Debugfln("received message from %q: %q", evt.Sender, evt.Content.AsMessage())
}
func (mh *matrixHandler) handleMembership(evt *event.Event) {
mh.log.Debugfln("recevied invite %#v\n", evt)
// Return early if we're supposed to ignore the event.
if mh.ignoreEvent(evt) {
return
}
// Grab the content of the event.
content := evt.Content.AsMessage()
// TODO: handle invites from ourselfs?
isSelf := id.UserID(evt.GetStateKey()) == evt.Sender
// Handle matrix invites.
if content.Membership == event.MembershipInvite && !isSelf {
//
}
}

View File

@@ -64,5 +64,12 @@ func (cfg *Config) CreateAppService() (*as.AppService, error) {
appservice.Host.Port = cfg.Appservice.Port appservice.Host.Port = cfg.Appservice.Port
appservice.DefaultHTTPRetries = 4 appservice.DefaultHTTPRetries = 4
reg, err := cfg.getRegistration()
if err != nil {
return nil, err
}
appservice.Registration = reg
return appservice, nil return appservice, nil
} }

View File

@@ -23,7 +23,9 @@ func (c *Cmd) Run(g *globals.Globals) error {
return err return err
} }
bridge.Start() if err := bridge.Start(); err != nil {
return err
}
ch := make(chan os.Signal) ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM) signal.Notify(ch, os.Interrupt, syscall.SIGTERM)