typing: support TG <-> Matrix

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-08-06 15:02:39 -06:00
parent 7fd280ea10
commit e0194f7621
7 changed files with 87 additions and 19 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ require (
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/net v0.27.0
maunium.net/go/mautrix v0.19.1-0.20240806185340-213f9df4a467
maunium.net/go/mautrix v0.19.1-0.20240807155838-eabab275895d
)
require (
+2 -2
View File
@@ -112,8 +112,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M=
maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA=
maunium.net/go/mautrix v0.19.1-0.20240806185340-213f9df4a467 h1:QptF4mA070qVG2isInl2HjtPOZ1TTqf0zM38uHPeWM8=
maunium.net/go/mautrix v0.19.1-0.20240806185340-213f9df4a467/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q=
maunium.net/go/mautrix v0.19.1-0.20240807155838-eabab275895d h1:+PtYgqxswmN5UM9XSLKO88TjYJHApwWn0j4fAnCslxg=
maunium.net/go/mautrix v0.19.1-0.20240807155838-eabab275895d/go.mod h1:ZWyxoQxRTBxzWIMs0kQCVogZIY0clTu33h102veCT/Q=
nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0=
nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
+25 -2
View File
@@ -129,6 +129,19 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge
dispatcher.OnEditChannelMessage(func(ctx context.Context, e tg.Entities, update *tg.UpdateEditChannelMessage) error {
return client.onMessageEdit(ctx, update)
})
dispatcher.OnUserTyping(func(ctx context.Context, e tg.Entities, update *tg.UpdateUserTyping) error {
return client.handleTyping(ids.PeerTypeUser.AsPortalKey(update.UserID, login.ID), update.UserID, update.Action)
})
dispatcher.OnChatUserTyping(func(ctx context.Context, e tg.Entities, update *tg.UpdateChatUserTyping) error {
if update.FromID.TypeID() != tg.PeerUserTypeID {
log.Warn().Str("from_id_type", update.FromID.TypeName()).Msg("unsupported from_id type")
return nil
}
return client.handleTyping(ids.PeerTypeChat.AsPortalKey(update.ChatID, login.ID), update.FromID.(*tg.PeerUser).UserID, update.Action)
})
dispatcher.OnChannelUserTyping(func(ctx context.Context, e tg.Entities, update *tg.UpdateChannelUserTyping) error {
return client.handleTyping(ids.PeerTypeChannel.AsPortalKey(update.ChannelID, ""), update.FromID.(*tg.PeerUser).UserID, update.Action)
})
client.ScopedStore = tc.Store.GetScopedStore(telegramUserID)
@@ -202,9 +215,19 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge
var portalKey networkid.PortalKey
if strings.HasPrefix(group, "C/") || strings.HasPrefix(group, "c/") {
portalKey = networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%s", ids.PeerTypeChannel, group[2:]))}
chatID, err := strconv.ParseInt(submatches[1][2:], 10, 64)
if err != nil {
log.Err(err).Msg("error parsing channel ID")
return url
}
portalKey = ids.PeerTypeChannel.AsPortalKey(chatID, "")
} else {
portalKey = networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%s", ids.PeerTypeUser, group))}
userID, err := strconv.ParseInt(submatches[1], 10, 64)
if err != nil {
log.Err(err).Msg("error parsing user ID")
return url
}
portalKey = ids.PeerTypeUser.AsPortalKey(userID, login.ID)
}
portal, err := tc.Bridge.DB.Portal.GetByKey(ctx, portalKey)
+2 -1
View File
@@ -34,7 +34,8 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med
ctx = log.WithContext(ctx)
log.Info().Msg("handling direct download")
logins, err := tc.Bridge.GetUserLoginsInPortal(ctx, info.PeerType.AsPortalKey(info.ChatID))
// TODO fix this
logins, err := tc.Bridge.GetUserLoginsInPortal(ctx, info.PeerType.AsPortalKey(info.ChatID, ""))
if err != nil {
return nil, err
} else if len(logins) == 0 {
+17 -5
View File
@@ -68,16 +68,28 @@ func (pt PeerType) AsByte() byte {
}
}
func (pt PeerType) AsPortalKey(chatID int64) networkid.PortalKey {
return networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%d", pt, chatID))}
func (pt PeerType) AsPortalKey(chatID int64, receiver networkid.UserLoginID) networkid.PortalKey {
portalKey := networkid.PortalKey{
ID: networkid.PortalID(fmt.Sprintf("%s:%d", pt, chatID)),
}
if pt == PeerTypeUser || pt == PeerTypeChat {
portalKey.Receiver = receiver
}
return portalKey
}
func MakePortalKey(peer tg.PeerClass) networkid.PortalKey {
func MakePortalKey(peer tg.PeerClass, receiver networkid.UserLoginID) networkid.PortalKey {
switch v := peer.(type) {
case *tg.PeerUser:
return networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%d", PeerTypeUser, v.UserID))}
return networkid.PortalKey{
ID: networkid.PortalID(fmt.Sprintf("%s:%d", PeerTypeUser, v.UserID)),
Receiver: receiver,
}
case *tg.PeerChat:
return networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%d", PeerTypeChat, v.ChatID))}
return networkid.PortalKey{
ID: networkid.PortalID(fmt.Sprintf("%s:%d", PeerTypeChat, v.ChatID)),
Receiver: receiver,
}
case *tg.PeerChannel:
return networkid.PortalKey{ID: networkid.PortalID(fmt.Sprintf("%s:%d", PeerTypeChannel, v.ChannelID))}
default:
+10 -3
View File
@@ -182,7 +182,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
DB: &database.Message{
ID: ids.MakeMessageID(tgMessageID),
MXID: msg.Event.ID,
Room: networkid.PortalKey{ID: msg.Portal.ID},
Room: msg.Portal.PortalKey,
SenderID: t.userID,
Timestamp: time.Unix(int64(tgDate), 0),
Metadata: &MessageMetadata{
@@ -401,6 +401,13 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
}
func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.MatrixTyping) error {
// TODO
return nil
inputPeer, err := t.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil {
return err
}
_, err = t.client.API().MessagesSetTyping(ctx, &tg.MessagesSetTypingRequest{
Peer: inputPeer,
Action: &tg.SendMessageTypingAction{},
})
return err
}
+30 -5
View File
@@ -55,7 +55,7 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, update IGetMess
Stringer("peer_id", msg.PeerID)
},
Sender: sender,
PortalKey: ids.MakePortalKey(msg.PeerID),
PortalKey: ids.MakePortalKey(msg.PeerID, t.loginID),
CreatePortal: true,
Timestamp: time.Unix(int64(msg.Date), 0),
},
@@ -69,7 +69,7 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, update IGetMess
chatInfoChange := simplevent.ChatInfoChange{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatInfoChange,
PortalKey: ids.MakePortalKey(msg.PeerID),
PortalKey: ids.MakePortalKey(msg.PeerID, t.loginID),
Sender: sender,
Timestamp: time.Unix(int64(msg.Date), 0),
LogContext: func(c zerolog.Context) zerolog.Context {
@@ -279,7 +279,7 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage)
Int("message_id", msg.ID)
},
Sender: sender,
PortalKey: ids.MakePortalKey(msg.PeerID),
PortalKey: ids.MakePortalKey(msg.PeerID, t.loginID),
Timestamp: time.Unix(int64(msg.EditDate), 0),
},
ID: ids.MakeMessageID(msg.ID),
@@ -305,6 +305,27 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage)
return nil
}
func (t *TelegramClient) handleTyping(portal networkid.PortalKey, userID int64, action tg.SendMessageActionClass) error {
if userID == t.telegramUserID {
return nil
}
timeout := time.Duration(6) * time.Second
if action.TypeID() != tg.SendMessageTypingActionTypeID {
timeout = 0
}
t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Typing{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventTyping,
PortalKey: portal,
Sender: bridgev2.EventSender{
SenderLogin: ids.MakeUserLoginID(userID),
Sender: ids.MakeUserID(userID),
},
},
Timeout: timeout,
})
return nil
}
func (t *TelegramClient) handleTelegramReactions(ctx context.Context, msg *tg.Message) {
log := zerolog.Ctx(ctx).With().
@@ -353,7 +374,7 @@ func (t *TelegramClient) handleTelegramReactions(ctx context.Context, msg *tg.Me
// return
// TODO should calls to this be limited?
} else if peer, err := t.inputPeerForPortalID(ctx, ids.MakePortalKey(msg.PeerID).ID); err != nil {
} else if peer, err := t.inputPeerForPortalID(ctx, ids.MakePortalKey(msg.PeerID, t.loginID).ID); err != nil {
log.Err(err).Msg("failed to get input peer")
return
} else {
@@ -447,7 +468,11 @@ func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID netw
}
switch peerType {
case ids.PeerTypeUser:
return &tg.InputPeerUser{UserID: id}, nil
if ghost, err := t.main.Bridge.DB.Ghost.GetByID(ctx, ids.MakeUserID(id)); err != nil {
return nil, err
} else {
return &tg.InputPeerUser{UserID: id, AccessHash: ghost.Metadata.(*GhostMetadata).AccessHash}, nil
}
case ids.PeerTypeChat:
return &tg.InputPeerChat{ChatID: id}, nil
case ids.PeerTypeChannel: