2023-05-25 14:47:24 +02:00
package bot
import (
"fmt"
_ "github.com/mattn/go-sqlite3"
"golang.org/x/exp/slog"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/crypto/cryptohelper"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id"
)
type MatrixConfig struct {
Homeserver string
UserID string
UserAccessKey string
UserPassword string
RoomID string
DBPath string
Pickle string
2023-06-18 09:26:41 +02:00
AcceptInvites bool
2023-05-25 14:47:24 +02:00
}
type Matrix struct {
config MatrixConfig
client * mautrix . Client
cryptoHelper * cryptohelper . CryptoHelper
feedReader * Miniflux
logger * slog . Logger
}
func NewMatrix ( cfg MatrixConfig , mflx * Miniflux , logger * slog . Logger ) * Matrix {
return & Matrix {
config : cfg ,
feedReader : mflx ,
logger : logger ,
}
}
func ( m * Matrix ) Init ( ) error {
client , err := mautrix . NewClient ( m . config . Homeserver , id . UserID ( m . config . UserID ) , m . config . UserAccessKey )
if err != nil {
return err
}
var oei mautrix . OldEventIgnorer
oei . Register ( client . Syncer . ( mautrix . ExtensibleSyncer ) )
m . client = client
m . cryptoHelper , err = cryptohelper . NewCryptoHelper ( client , [ ] byte ( m . config . Pickle ) , m . config . DBPath )
if err != nil {
return err
}
m . cryptoHelper . LoginAs = & mautrix . ReqLogin {
Type : mautrix . AuthTypePassword ,
Identifier : mautrix . UserIdentifier { Type : mautrix . IdentifierTypeUser , User : m . config . UserID } ,
Password : m . config . UserPassword ,
}
if err := m . cryptoHelper . Init ( ) ; err != nil {
return err
}
m . client . Crypto = m . cryptoHelper
2023-06-18 09:26:41 +02:00
if m . config . AcceptInvites {
m . AddEventHandler ( m . InviteHandler ( ) )
}
2023-05-25 14:47:24 +02:00
return nil
}
func ( m * Matrix ) Run ( ) error {
go m . PostMessages ( )
go m . feedReader . Run ( )
if err := m . client . Sync ( ) ; err != nil {
return err
}
return nil
}
func ( m * Matrix ) Close ( ) error {
if err := m . client . Sync ( ) ; err != nil {
return err
}
if err := m . cryptoHelper . Close ( ) ; err != nil {
return err
}
return nil
}
func ( m * Matrix ) AddEventHandler ( eventType event . Type , handler mautrix . EventHandler ) {
syncer := m . client . Syncer . ( * mautrix . DefaultSyncer )
syncer . OnEventType ( eventType , handler )
}
func ( m * Matrix ) InviteHandler ( ) ( event . Type , mautrix . EventHandler ) {
return event . StateMember , func ( source mautrix . EventSource , evt * event . Event ) {
if evt . GetStateKey ( ) == m . client . UserID . String ( ) && evt . Content . AsMember ( ) . Membership == event . MembershipInvite && evt . RoomID . String ( ) == m . config . RoomID {
_ , err := m . client . JoinRoomByID ( evt . RoomID )
if err != nil {
m . logger . Error ( "failed to join room after invite" , slog . String ( "err" , err . Error ( ) ) , slog . String ( "room_id" , evt . RoomID . String ( ) ) , slog . String ( "inviter" , evt . Sender . String ( ) ) )
return
}
m . logger . Info ( "joined room after invite" , slog . String ( "room_id" , evt . RoomID . String ( ) ) , slog . String ( "inviter" , evt . Sender . String ( ) ) )
}
}
}
func ( m * Matrix ) PostMessages ( ) {
for entry := range m . feedReader . Feed ( ) {
m . logger . Info ( "received entry" , slog . String ( "title" , entry . Title ) , slog . String ( "url" , entry . URL ) )
2023-05-25 16:01:31 +02:00
message := fmt . Sprintf ( ` %s: [%s](%s) ` , entry . FeedTitle , entry . Title , entry . URL )
if entry . CommentsURL != "" {
message += fmt . Sprintf ( " - [Comments](%s)" , entry . CommentsURL )
}
formattedMessage := format . RenderMarkdown ( message , true , false )
2023-05-25 14:47:24 +02:00
2023-05-25 16:01:31 +02:00
if _ , err := m . client . SendMessageEvent ( id . RoomID ( m . config . RoomID ) , event . EventMessage , & formattedMessage ) ; err != nil {
2023-05-25 14:47:24 +02:00
m . logger . Error ( "failed to send message" , slog . String ( "err" , err . Error ( ) ) )
return
}
}
}