@ -2,9 +2,11 @@ package main
import (
import (
"context"
"context"
"errors"
"fmt"
"fmt"
"net/http"
"net/http"
"strings"
"strings"
"sync"
"time"
"time"
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown"
@ -15,18 +17,23 @@ import (
"maunium.net/go/mautrix/id"
"maunium.net/go/mautrix/id"
)
)
var (
DEVICE_ID = id . DeviceID ( "jfa-go" )
)
type MatrixDaemon struct {
type MatrixDaemon struct {
Stopped bool
Stopped bool
ShutdownChannel chan string
bot * mautrix . Client
bot * mautrix . Client
userID id . UserID
userID id . UserID
homeserver string
tokens map [ string ] UnverifiedUser // Map of tokens to users
tokens map [ string ] UnverifiedUser // Map of tokens to users
languages map [ id . RoomID ] string // Map of roomIDs to language codes
languages map [ id . RoomID ] string // Map of roomIDs to language codes
Encryption bool
Encryption bool
isEncrypted map [ id . RoomID ] bool
crypto * Crypto
crypto Crypto
app * appContext
app * appContext
start int64
start int64
cancellation sync . WaitGroup
cancel context . CancelFunc
}
}
type UnverifiedUser struct {
type UnverifiedUser struct {
@ -57,23 +64,33 @@ var matrixFilter = mautrix.Filter{
} ,
} ,
}
}
func ( d * MatrixDaemon ) renderUserID ( uid id . UserID ) id . UserID {
if uid [ 0 ] != '@' {
uid = "@" + uid
}
if ! strings . ContainsRune ( string ( uid ) , ':' ) {
uid = id . UserID ( string ( uid ) + ":" + d . homeserver )
}
return uid
}
func newMatrixDaemon ( app * appContext ) ( d * MatrixDaemon , err error ) {
func newMatrixDaemon ( app * appContext ) ( d * MatrixDaemon , err error ) {
matrix := app . config . Section ( "matrix" )
matrix := app . config . Section ( "matrix" )
homeserver := matrix . Key ( "homeserver" ) . String ( )
token := matrix . Key ( "token" ) . String ( )
token := matrix . Key ( "token" ) . String ( )
d = & MatrixDaemon {
d = & MatrixDaemon {
ShutdownChannel : make ( chan string ) ,
userID : id . UserID ( matrix . Key ( "user_id" ) . String ( ) ) ,
userID : id . UserID ( matrix . Key ( "user_id" ) . String ( ) ) ,
homeserver : matrix . Key ( "homeserver" ) . String ( ) ,
tokens : map [ string ] UnverifiedUser { } ,
tokens : map [ string ] UnverifiedUser { } ,
languages : map [ id . RoomID ] string { } ,
languages : map [ id . RoomID ] string { } ,
isEncrypted : map [ id . RoomID ] bool { } ,
app : app ,
app : app ,
start : time . Now ( ) . UnixNano ( ) / 1e6 ,
start : time . Now ( ) . UnixNano ( ) / 1e6 ,
}
}
d . bot , err = mautrix . NewClient ( homeserver , d . userID , token )
d . userID = d . renderUserID ( d . userID )
d . bot , err = mautrix . NewClient ( d . homeserver , d . userID , token )
if err != nil {
if err != nil {
return
return
}
}
d . bot . DeviceID = DEVICE_ID
// resp, err := d.bot.CreateFilter(&matrixFilter)
// resp, err := d.bot.CreateFilter(&matrixFilter)
// if err != nil {
// if err != nil {
// return
// return
@ -83,7 +100,6 @@ func newMatrixDaemon(app *appContext) (d *MatrixDaemon, err error) {
if user . Lang != "" {
if user . Lang != "" {
d . languages [ id . RoomID ( user . RoomID ) ] = user . Lang
d . languages [ id . RoomID ( user . RoomID ) ] = user . Lang
}
}
d . isEncrypted [ id . RoomID ( user . RoomID ) ] = user . Encrypted
}
}
err = InitMatrixCrypto ( d )
err = InitMatrixCrypto ( d )
return
return
@ -102,7 +118,7 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string
User : username ,
User : username ,
} ,
} ,
Password : password ,
Password : password ,
DeviceID : id. DeviceID ( "jfa-go-" + commit ) ,
DeviceID : DEVICE_ID ,
}
}
bot , err := mautrix . NewClient ( homeserver , id . UserID ( username ) , "" )
bot , err := mautrix . NewClient ( homeserver , id . UserID ( username ) , "" )
if err != nil {
if err != nil {
@ -116,22 +132,25 @@ func (d *MatrixDaemon) generateAccessToken(homeserver, username, password string
}
}
func ( d * MatrixDaemon ) run ( ) {
func ( d * MatrixDaemon ) run ( ) {
startTime := d . start
d . app . info . Println ( lm . StartDaemon , lm . Matrix )
syncer := d . bot . Syncer . ( * mautrix . DefaultSyncer )
syncer := d . bot . Syncer . ( * mautrix . DefaultSyncer )
HandleSyncerCrypto ( startTime , d , syncer )
syncer . OnEventType ( event . EventMessage , d . handleMessage )
syncer . OnEventType ( event . EventMessage , d . handleMessage )
if err := d . bot . Sync ( ) ; err != nil {
d . app . info . Printf ( lm . StartDaemon , lm . Matrix )
var syncCtx context . Context
syncCtx , d . cancel = context . WithCancel ( context . Background ( ) )
d . cancellation . Add ( 1 )
if err := d . bot . SyncWithContext ( syncCtx ) ; err != nil && ! errors . Is ( err , context . Canceled ) {
d . app . err . Printf ( lm . FailedSyncMatrix , err )
d . app . err . Printf ( lm . FailedSyncMatrix , err )
}
}
d . cancellation . Done ( )
}
}
func ( d * MatrixDaemon ) Shutdown ( ) {
func ( d * MatrixDaemon ) Shutdown ( ) {
CryptoShutdown ( d )
d . cancel ( )
d . bot. StopSync ( )
d . cancellation. Wait ( )
d . Stopped = true
d . Stopped = true
close ( d . ShutdownChannel )
}
}
func ( d * MatrixDaemon ) handleMessage ( ctx context . Context , evt * event . Event ) {
func ( d * MatrixDaemon ) handleMessage ( ctx context . Context , evt * event . Event ) {
@ -184,7 +203,7 @@ func (d *MatrixDaemon) commandLang(evt *event.Event, code, lang string) {
}
}
}
}
func ( d * MatrixDaemon ) CreateRoom ( userID string ) ( roomID id . RoomID , e ncrypted bool , e rr error ) {
func ( d * MatrixDaemon ) CreateRoom ( userID string ) ( roomID id . RoomID , e rr error ) {
var room * mautrix . RespCreateRoom
var room * mautrix . RespCreateRoom
room , err = d . bot . CreateRoom ( context . TODO ( ) , & mautrix . ReqCreateRoom {
room , err = d . bot . CreateRoom ( context . TODO ( ) , & mautrix . ReqCreateRoom {
Visibility : "private" ,
Visibility : "private" ,
@ -195,13 +214,14 @@ func (d *MatrixDaemon) CreateRoom(userID string) (roomID id.RoomID, encrypted bo
if err != nil {
if err != nil {
return
return
}
}
encrypted = EncryptRoom ( d , room , id . UserID ( userID ) )
// encrypted = EncryptRoom(d, room, id.UserID(userID))
roomID = room . RoomID
roomID = room . RoomID
err = EncryptRoom ( d , roomID )
return
return
}
}
func ( d * MatrixDaemon ) SendStart ( userID string ) ( ok bool ) {
func ( d * MatrixDaemon ) SendStart ( userID string ) ( ok bool ) {
roomID , e ncrypted, e rr := d . CreateRoom ( userID )
roomID , e rr := d . CreateRoom ( userID )
if err != nil {
if err != nil {
d . app . err . Printf ( lm . FailedCreateMatrixRoom , userID , err )
d . app . err . Printf ( lm . FailedCreateMatrixRoom , userID , err )
return
return
@ -211,10 +231,9 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
d . tokens [ pin ] = UnverifiedUser {
d . tokens [ pin ] = UnverifiedUser {
false ,
false ,
& MatrixUser {
& MatrixUser {
RoomID : string ( roomID ) ,
RoomID : string ( roomID ) ,
UserID : userID ,
UserID : userID ,
Lang : lang ,
Lang : lang ,
Encrypted : encrypted ,
} ,
} ,
}
}
err = d . sendToRoom (
err = d . sendToRoom (
@ -234,12 +253,13 @@ func (d *MatrixDaemon) SendStart(userID string) (ok bool) {
}
}
func ( d * MatrixDaemon ) sendToRoom ( content * event . MessageEventContent , roomID id . RoomID ) ( err error ) {
func ( d * MatrixDaemon ) sendToRoom ( content * event . MessageEventContent , roomID id . RoomID ) ( err error ) {
if encrypted , ok := d . isEncrypted [ roomID ] ; ok && encrypted {
return d . send ( content , roomID )
/ * if encrypted , ok := d . isEncrypted [ roomID ] ; ok && encrypted {
err = SendEncrypted ( d , content , roomID )
err = SendEncrypted ( d , content , roomID )
} else {
} else {
_ , err = d . bot . SendMessageEvent ( context . TODO ( ) , roomID , event . EventMessage , content , mautrix . ReqSendEvent { } )
_ , err = d . bot . SendMessageEvent ( context . TODO ( ) , roomID , event . EventMessage , content , mautrix . ReqSendEvent { } )
}
}
return
return * /
}
}
func ( d * MatrixDaemon ) send ( content * event . MessageEventContent , roomID id . RoomID ) ( err error ) {
func ( d * MatrixDaemon ) send ( content * event . MessageEventContent , roomID id . RoomID ) ( err error ) {