groupme/main.go

209 lines
5.8 KiB
Go
Raw Normal View History

// mautrix-groupme - A Matrix-GroupMe puppeting bridge.
// Copyright (C) 2022 Sumner Evans, Karmanyaah Malhotra
2018-08-12 19:26:05 +00:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package main
import (
_ "embed"
"sync"
2018-08-26 19:53:13 +00:00
"maunium.net/go/mautrix/bridge"
"maunium.net/go/mautrix/bridge/commands"
"maunium.net/go/mautrix/bridge/status"
2020-05-08 19:32:22 +00:00
"maunium.net/go/mautrix/id"
"maunium.net/go/mautrix/util/configupgrade"
"github.com/beeper/groupme-lib"
2019-01-11 19:17:31 +00:00
"github.com/beeper/groupme/config"
"github.com/beeper/groupme/database"
)
// Information to find out exactly which commit the bridge was built from.
// These are filled at build time with the -X linker flag.
var (
2020-06-03 17:59:44 +00:00
Tag = "unknown"
Commit = "unknown"
BuildTime = "unknown"
)
//go:embed example-config.yaml
var ExampleConfig string
type GMBridge struct {
bridge.Bridge
Config *config.Config
DB *database.Database
Provisioning *ProvisioningAPI
Formatter *Formatter
Metrics *MetricsHandler
2020-05-08 19:32:22 +00:00
usersByMXID map[id.UserID]*User
usersByGMID map[groupme.ID]*User
usersLock sync.Mutex
spaceRooms map[id.RoomID]*User
spaceRoomsLock sync.Mutex
2020-05-08 19:32:22 +00:00
managementRooms map[id.RoomID]*User
managementRoomsLock sync.Mutex
2020-05-08 19:32:22 +00:00
portalsByMXID map[id.RoomID]*Portal
portalsByGMID map[database.PortalKey]*Portal
portalsLock sync.Mutex
puppets map[groupme.ID]*Puppet
2020-05-08 19:32:22 +00:00
puppetsByCustomMXID map[id.UserID]*Puppet
puppetsLock sync.Mutex
}
func (br *GMBridge) Init() {
br.CommandProcessor = commands.NewProcessor(&br.Bridge)
br.RegisterCommands()
Segment.log = br.Log.Sub("Segment")
Segment.key = br.Config.SegmentKey
if Segment.IsEnabled() {
Segment.log.Infoln("Segment metrics are enabled")
}
br.DB = database.New(br.Bridge.DB, br.Log.Sub("Database"))
ss := br.Config.Bridge.Provisioning.SharedSecret
2020-02-09 18:32:14 +00:00
if len(ss) > 0 && ss != "disable" {
br.Provisioning = &ProvisioningAPI{bridge: br}
2020-02-09 18:32:14 +00:00
}
br.Formatter = NewFormatter(br)
br.Metrics = NewMetricsHandler(br.Config.Metrics.Listen, br.Log.Sub("Metrics"), br.DB)
br.MatrixHandler.TrackEventDuration = br.Metrics.TrackMatrixEvent
}
func (bridge *GMBridge) Start() {
2020-02-09 18:32:14 +00:00
if bridge.Provisioning != nil {
bridge.Log.Debugln("Initializing provisioning API")
bridge.Provisioning.Init()
}
go bridge.StartUsers()
if bridge.Config.Metrics.Enabled {
go bridge.Metrics.Start()
}
2019-11-10 19:22:11 +00:00
}
func (bridge *GMBridge) UpdateBotProfile() {
bridge.Log.Debugln("Updating bot profile")
2018-08-16 16:20:07 +00:00
botConfig := bridge.Config.AppService.Bot
var err error
2020-05-08 19:32:22 +00:00
var mxc id.ContentURI
2018-08-16 16:20:07 +00:00
if botConfig.Avatar == "remove" {
2020-05-08 19:32:22 +00:00
err = bridge.Bot.SetAvatarURL(mxc)
2018-08-16 16:20:07 +00:00
} else if len(botConfig.Avatar) > 0 {
2020-05-08 19:32:22 +00:00
mxc, err = id.ParseContentURI(botConfig.Avatar)
if err == nil {
err = bridge.Bot.SetAvatarURL(mxc)
}
2018-08-16 16:20:07 +00:00
}
if err != nil {
bridge.Log.Warnln("Failed to update bot avatar:", err)
}
if botConfig.Displayname == "remove" {
err = bridge.Bot.SetDisplayName("")
2018-08-16 16:20:07 +00:00
} else if len(botConfig.Avatar) > 0 {
err = bridge.Bot.SetDisplayName(botConfig.Displayname)
2018-08-16 16:20:07 +00:00
}
if err != nil {
bridge.Log.Warnln("Failed to update bot displayname:", err)
}
}
func (br *GMBridge) StartUsers() {
br.Log.Debugln("Starting users")
foundAnySessions := false
for _, user := range br.GetAllUsers() {
if user.GMID.String() != "" {
foundAnySessions = true
}
2021-02-21 05:58:50 +00:00
go user.Connect()
}
if !foundAnySessions {
br.SendGlobalBridgeState(status.BridgeState{StateEvent: status.StateUnconfigured}.Fill(nil))
}
br.Log.Debugln("Starting custom puppets")
for _, loopuppet := range br.GetAllPuppetsWithCustomMXID() {
2019-05-31 20:07:33 +00:00
go func(puppet *Puppet) {
puppet.log.Debugln("Starting custom puppet", puppet.CustomMXID)
err := puppet.StartCustomMXID(true)
if err != nil {
puppet.log.Errorln("Failed to start custom puppet:", err)
}
2019-05-31 20:07:33 +00:00
}(loopuppet)
}
}
func (br *GMBridge) Stop() {
br.Metrics.Stop()
// TODO anything needed to disconnect the users?
for _, user := range br.usersByGMID {
if user.Client == nil {
continue
}
br.Log.Debugln("Disconnecting", user.MXID)
}
}
func (br *GMBridge) GetExampleConfig() string {
return ExampleConfig
}
2021-02-13 05:53:35 +00:00
func (br *GMBridge) GetConfigPtr() interface{} {
br.Config = &config.Config{
BaseConfig: &br.Bridge.Config,
}
br.Config.BaseConfig.Bridge = &br.Config.Bridge
return br.Config
}
func main() {
br := &GMBridge{
usersByMXID: make(map[id.UserID]*User),
usersByGMID: make(map[groupme.ID]*User),
spaceRooms: make(map[id.RoomID]*User),
managementRooms: make(map[id.RoomID]*User),
portalsByMXID: make(map[id.RoomID]*Portal),
portalsByGMID: make(map[database.PortalKey]*Portal),
puppets: make(map[groupme.ID]*Puppet),
puppetsByCustomMXID: make(map[id.UserID]*Puppet),
2021-02-28 20:02:34 +00:00
}
br.Bridge = bridge.Bridge{
Name: "groupme-matrix",
URL: "https://github.com/beeper/groupme",
Description: "A Matrix-GroupMe puppeting bridge.",
Version: "0.1.0",
ProtocolName: "GroupMe",
2021-02-28 20:02:34 +00:00
CryptoPickleKey: "github.com/beeper/groupme",
ConfigUpgrader: &configupgrade.StructUpgrader{
SimpleUpgrader: configupgrade.SimpleUpgrader(config.DoUpgrade),
Blocks: config.SpacedBlocks,
Base: ExampleConfig,
},
Child: br,
}
br.InitVersion(Tag, Commit, BuildTime)
br.Main()
}