both way sync

This commit is contained in:
Karmanyaah Malhotra 2021-02-22 22:02:33 -05:00
parent f1c093896e
commit 5dbace10c6
3 changed files with 193 additions and 177 deletions

View File

@ -1,12 +1,12 @@
# Features & roadmap # Features & roadmap
* Matrix → GroupMe * Matrix → GroupMe
* [ ] Message content * [ ] Message content
* [ ] Plain text * [x] Plain text
* [ ] Formatted messages * [ ] Formatted messages
* [ ] Media/files * [ ] Media/files
* [ ] Replies * [ ] Replies
* [ ] Message redactions * [ ] Message redactions
* [ ] Presence * [ ] Presence - N/A
* [ ] Typing notifications * [ ] Typing notifications
* [ ] Read receipts * [ ] Read receipts
* [ ] Power level * [ ] Power level
@ -22,7 +22,7 @@
* [ ] Initial room metadata * [ ] Initial room metadata
* GroupMe → Matrix * GroupMe → Matrix
* [ ] Message content * [ ] Message content
* [ ] Plain text * [x] Plain text
* [ ] Formatted messages * [ ] Formatted messages
* [ ] Media/files * [ ] Media/files
* [ ] Location messages * [ ] Location messages
@ -30,9 +30,7 @@
* [ ] Replies * [ ] Replies
* [ ] Chat types * [ ] Chat types
* [ ] Private chat * [ ] Private chat
* [ ] Group chat * [x] Group chat
* [ ] Broadcast list<sup>[2]</sup>
* [ ] Message deletions
* [ ] Avatars * [ ] Avatars
* [ ] Presence * [ ] Presence
* [ ] Typing notifications * [ ] Typing notifications
@ -49,14 +47,14 @@
* [ ] Description * [ ] Description
* [ ] Initial group metadata * [ ] Initial group metadata
* [ ] User metadata changes * [ ] User metadata changes
* [ ] Display name<sup>[3]</sup> * [x] Display name
* [ ] Avatar * [ ] Avatar
* [ ] Initial user metadata * [ ] Initial user metadata
* [ ] Display name * [ ] Display name
* [ ] Avatar * [ ] Avatar
* Misc * Misc
* [ ] Automatic portal creation * [ ] Automatic portal creation
* [ ] At startup * [x] At startup
* [ ] When receiving invite * [ ] When receiving invite
* [ ] When receiving message * [ ] When receiving message
* [ ] Private chat creation by inviting Matrix puppet of WhatsApp user to new room * [ ] Private chat creation by inviting Matrix puppet of WhatsApp user to new room

2
go.mod
View File

@ -34,5 +34,3 @@ replace github.com/Rhymen/go-whatsapp => github.com/tulir/go-whatsapp v0.3.16
replace github.com/karmanyaahm/groupme => ../groupme replace github.com/karmanyaahm/groupme => ../groupme
replace maunium.net/go/mautrix => ../mautrix replace maunium.net/go/mautrix => ../mautrix
replace maunium.net/go/mautrix/i => ../mautrix_go/id

166
portal.go
View File

@ -131,7 +131,7 @@ func (bridge *Bridge) NewManualPortal(key database.PortalKey) *Portal {
bridge: bridge, bridge: bridge,
log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", key)), log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", key)),
recentlyHandled: [recentlyHandledLength]groupme.ID{}, recentlyHandled: [recentlyHandledLength]string{},
messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer), messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
} }
@ -146,7 +146,7 @@ func (bridge *Bridge) NewPortal(dbPortal *database.Portal) *Portal {
bridge: bridge, bridge: bridge,
log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", dbPortal.Key)), log: bridge.Log.Sub(fmt.Sprintf("Portal/%s", dbPortal.Key)),
recentlyHandled: [recentlyHandledLength]groupme.ID{}, recentlyHandled: [recentlyHandledLength]string{},
messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer), messages: make(chan PortalMessage, bridge.Config.Bridge.PortalMessageBuffer),
} }
@ -171,7 +171,7 @@ type Portal struct {
roomCreateLock sync.Mutex roomCreateLock sync.Mutex
recentlyHandled [recentlyHandledLength]groupme.ID recentlyHandled [recentlyHandledLength]string
recentlyHandledLock sync.Mutex recentlyHandledLock sync.Mutex
recentlyHandledIndex uint8 recentlyHandledIndex uint8
@ -266,8 +266,9 @@ func (portal *Portal) handleMessage(msg PortalMessage) {
func (portal *Portal) isRecentlyHandled(id groupme.ID) bool { func (portal *Portal) isRecentlyHandled(id groupme.ID) bool {
start := portal.recentlyHandledIndex start := portal.recentlyHandledIndex
for i := start; i != start; i = (i - 1) % recentlyHandledLength { idStr := id.String()
if portal.recentlyHandled[i] == id { for i := (start - 1) % recentlyHandledLength; i != start; i = (i - 1) % recentlyHandledLength {
if portal.recentlyHandled[i] == idStr {
return true return true
} }
} }
@ -279,6 +280,7 @@ func (portal *Portal) isDuplicate(id groupme.ID) bool {
if msg != nil { if msg != nil {
return true return true
} }
return false return false
} }
@ -287,7 +289,6 @@ func init() {
} }
func (portal *Portal) markHandled(source *User, message *groupme.Message, mxid id.EventID) { func (portal *Portal) markHandled(source *User, message *groupme.Message, mxid id.EventID) {
print("handle message")
msg := portal.bridge.DB.Message.New() msg := portal.bridge.DB.Message.New()
msg.Chat = portal.Key msg.Chat = portal.Key
msg.JID = message.ID.String() msg.JID = message.ID.String()
@ -311,7 +312,7 @@ func (portal *Portal) markHandled(source *User, message *groupme.Message, mxid i
index := portal.recentlyHandledIndex index := portal.recentlyHandledIndex
portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength portal.recentlyHandledIndex = (portal.recentlyHandledIndex + 1) % recentlyHandledLength
portal.recentlyHandledLock.Unlock() portal.recentlyHandledLock.Unlock()
portal.recentlyHandled[index] = groupme.ID(msg.JID) portal.recentlyHandled[index] = message.ID.String()
} }
func (portal *Portal) getMessageIntent(user *User, info *groupme.Message) *appservice.IntentAPI { func (portal *Portal) getMessageIntent(user *User, info *groupme.Message) *appservice.IntentAPI {
@ -704,7 +705,6 @@ func (portal *Portal) BackfillHistory(user *User, lastMessageTime uint64) error
endBackfill := portal.beginBackfill() endBackfill := portal.beginBackfill()
defer endBackfill() defer endBackfill()
println("hi")
lastMessage := portal.bridge.DB.Message.GetLastInChat(portal.Key) lastMessage := portal.bridge.DB.Message.GetLastInChat(portal.Key)
fmt.Println(lastMessage) fmt.Println(lastMessage)
if lastMessage == nil { if lastMessage == nil {
@ -1239,7 +1239,7 @@ func (portal *Portal) sendMessageDirect(intent *appservice.IntentAPI, eventType
if timestamp == 0 { if timestamp == 0 {
return intent.SendMessageEvent(portal.MXID, eventType, &wrappedContent) return intent.SendMessageEvent(portal.MXID, eventType, &wrappedContent)
} else { } else {
return intent.SendMassagedMessageEvent(portal.MXID, eventType, &wrappedContent, timestamp) return intent.SendMassagedMessageEvent(portal.MXID, eventType, &wrappedContent, timestamp*1000) //milliseconds
} }
} }
@ -1259,7 +1259,7 @@ func (portal *Portal) HandleTextMessage(source *User, message *groupme.Message)
//TODO: mentions //TODO: mentions
_, _ = intent.UserTyping(portal.MXID, false, 0) _, _ = intent.UserTyping(portal.MXID, false, 0)
resp, err := portal.sendMessage(intent, event.EventMessage, content, message.CreatedAt.ToTime().UnixNano()) resp, err := portal.sendMessage(intent, event.EventMessage, content, message.CreatedAt.ToTime().Unix())
if err != nil { if err != nil {
portal.log.Errorfln("Failed to handle message %s: %v", message.ID, err) portal.log.Errorfln("Failed to handle message %s: %v", message.ID, err)
return return
@ -1835,18 +1835,16 @@ func (portal *Portal) addRelaybotFormat(sender *User, content *event.MessageEven
return true return true
} }
func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*groupme.Message, *User) { func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) ([]*groupme.Message, *User) {
print("convertMatrixMessage") content, ok := evt.Content.Parsed.(*event.MessageEventContent)
return nil, nil if !ok {
// content, ok := evt.Content.Parsed.(*event.MessageEventContent) portal.log.Debugfln("Failed to handle event %s: unexpected parsed content type %T", evt.ID, evt.Content.Parsed)
// if !ok { return nil, sender
// portal.log.Debugfln("Failed to handle event %s: unexpected parsed content type %T", evt.ID, evt.Content.Parsed) }
// return nil, sender
// }
// ts := uint64(evt.Timestamp / 1000) //ts := uint64(evt.Timestamp / 1000)
// status := waProto.WebMessageInfo_ERROR //status := waProto.WebMessageInfo_ERROR
// fromMe := true //fromMe := true
// info := &waProto.WebMessageInfo{ // info := &waProto.WebMessageInfo{
// Key: &waProto.MessageKey{ // Key: &waProto.MessageKey{
// FromMe: &fromMe, // FromMe: &fromMe,
@ -1857,9 +1855,13 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*gro
// Message: &waProto.Message{}, // Message: &waProto.Message{},
// Status: &status, // Status: &status,
// } // }
// ctxInfo := &waProto.ContextInfo{} //
// replyToID := content.GetReplyTo() info := groupme.Message{
// if len(replyToID) > 0 { SourceGUID: evt.ID.String(), //TODO Figure out for multiple messages
GroupID: groupme.ID(portal.Key.JID),
}
replyToID := content.GetReplyTo()
if len(replyToID) > 0 {
// content.RemoveReplyFallback() // content.RemoveReplyFallback()
// msg := portal.bridge.DB.Message.GetByMXID(replyToID) // msg := portal.bridge.DB.Message.GetByMXID(replyToID)
// if msg != nil && msg.Content != nil { // if msg != nil && msg.Content != nil {
@ -1867,42 +1869,46 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*gro
// ctxInfo.Participant = &msg.Sender // ctxInfo.Participant = &msg.Sender
// ctxInfo.QuotedMessage = msg.Content // ctxInfo.QuotedMessage = msg.Content
// } // }
// } }
// relaybotFormatted := false relaybotFormatted := false
// if sender.NeedsRelaybot(portal) { if sender.NeedsRelaybot(portal) {
// if !portal.HasRelaybot() { if !portal.HasRelaybot() {
// if sender.HasSession() { if sender.HasSession() {
// portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway") portal.log.Debugln("Database says", sender.MXID, "not in chat and no relaybot, but trying to send anyway")
// } else { } else {
// portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot") portal.log.Debugln("Ignoring message from", sender.MXID, "in chat with no relaybot")
// return nil, sender return nil, sender
// } }
// } else { } else {
// relaybotFormatted = portal.addRelaybotFormat(sender, content) relaybotFormatted = portal.addRelaybotFormat(sender, content)
// sender = portal.bridge.Relaybot sender = portal.bridge.Relaybot
// } }
// } }
// if evt.Type == event.EventSticker { if evt.Type == event.EventSticker {
// content.MsgType = event.MsgImage content.MsgType = event.MsgImage
// } else if content.MsgType == event.MsgImage && content.GetInfo().MimeType == "image/gif" { } else if content.MsgType == event.MsgImage && content.GetInfo().MimeType == "image/gif" {
// content.MsgType = event.MsgVideo content.MsgType = event.MsgVideo
// } }
switch content.MsgType {
case event.MsgText, event.MsgEmote, event.MsgNotice:
text := content.Body
if content.Format == event.FormatHTML {
text, _ = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
//TODO mentions
}
if content.MsgType == event.MsgEmote && !relaybotFormatted {
text = "/me " + text
}
info.Text = text
// switch content.MsgType {
// case event.MsgText, event.MsgEmote, event.MsgNotice:
// text := content.Body
// if content.Format == event.FormatHTML {
// text, ctxInfo.MentionedJid = portal.bridge.Formatter.ParseMatrix(content.FormattedBody)
// }
// if content.MsgType == event.MsgEmote && !relaybotFormatted {
// text = "/me " + text
// }
// if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil { // if ctxInfo.StanzaId != nil || ctxInfo.MentionedJid != nil {
// info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{ // info.Message.ExtendedTextMessage = &waProto.ExtendedTextMessage{
// Text: &text, // Text: &text,
// ContextInfo: ctxInfo, // ContextInfo: ctxInfo,
// } // }
// } else { // }
//else {
// info.Message.Conversation = &text // info.Message.Conversation = &text
// } // }
// case event.MsgImage: // case event.MsgImage:
@ -1975,11 +1981,11 @@ func (portal *Portal) convertMatrixMessage(sender *User, evt *event.Event) (*gro
// FileSha256: media.FileSHA256, // FileSha256: media.FileSHA256,
// FileLength: &media.FileLength, // FileLength: &media.FileLength,
// } // }
// default: default:
// portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType) portal.log.Debugln("Unhandled Matrix event %s: unknown msgtype %s", evt.ID, content.MsgType)
// return nil, sender return nil, sender
// } }
// return info, sender return []*groupme.Message{&info}, sender
} }
func (portal *Portal) wasMessageSent(sender *User, id string) bool { func (portal *Portal) wasMessageSent(sender *User, id string) bool {
@ -2017,23 +2023,37 @@ func (portal *Portal) sendDeliveryReceipt(eventID id.EventID) {
var timeout = errors.New("message sending timed out") var timeout = errors.New("message sending timed out")
func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) { func (portal *Portal) HandleMatrixMessage(sender *User, evt *event.Event) {
println("handle matrix message") if !portal.HasRelaybot() && ((portal.IsPrivateChat() && sender.JID != portal.Key.Receiver) ||
portal.sendMatrixConnectionError(sender, evt.ID)) {
return return
// if !portal.HasRelaybot() && ((portal.IsPrivateChat() && sender.JID != portal.Key.Receiver) || }
// portal.sendMatrixConnectionError(sender, evt.ID)) { portal.log.Debugfln("Received event %s", evt.ID)
// return info, sender := portal.convertMatrixMessage(sender, evt)
// } if info == nil {
// portal.log.Debugfln("Received event %s", evt.ID) return
// info, sender := portal.convertMatrixMessage(sender, evt) }
// if info == nil { for _, i := range info {
// return portal.log.Debugln("Sending event", evt.ID, "to WhatsApp", info[0].ID)
// } i = portal.sendRaw(sender, evt, info[0], false) //TODO deal with multiple messages for longer messages
// portal.markHandled(sender, info, evt.ID) portal.markHandled(sender, i, evt.ID)
// portal.log.Debugln("Sending event", evt.ID, "to WhatsApp", info.ID) }
// portal.sendRaw(sender, evt, info, false)
} }
func (portal *Portal) sendRaw(sender *User, evt *event.Event, info *waProto.WebMessageInfo, isRetry bool) { func (portal *Portal) sendRaw(sender *User, evt *event.Event, info *groupme.Message, isRetry bool) *groupme.Message {
m, err := sender.Client.CreateMessage(context.TODO(), info.GroupID, info)
id := ""
if m != nil {
id = m.ID.String()
}
if err != nil {
portal.log.Warnln(err, id, info.GroupID.String())
}
if isRetry && err != nil {
m, err = sender.Client.CreateMessage(context.TODO(), info.GroupID, info)
}
return m
// errChan := make(chan error, 1) // errChan := make(chan error, 1)
// go sender.Conn.SendRaw(info, errChan) // go sender.Conn.SendRaw(info, errChan)