-
Notifications
You must be signed in to change notification settings - Fork 2
fix: group invites time mismatch #192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -294,8 +294,14 @@ func (lc *LineClient) Connect(ctx context.Context) { | |
| } | ||
| } | ||
|
|
||
| lc.wg.Add(4) | ||
| go lc.syncChats(ctx) | ||
| // Create/sync group portals before message prefetching or SSE polling can | ||
| // deliver messages. Otherwise an existing LINE group whose Matrix room | ||
| // doesn't exist yet may be created by the first message, which makes the | ||
| // sender's existing membership look like a fresh join. | ||
| lc.wg.Add(1) | ||
| lc.syncChats(ctx) | ||
|
|
||
| lc.wg.Add(3) | ||
|
Comment on lines
+301
to
+304
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🔴 Critical 🧩 Analysis chain🏁 Script executed: #!/bin/bash
rg -n -C3 'wg\.(Add|Done|Wait)\(|func \(lc \*LineClient\) (syncChats|syncDMChats|prefetchMessages|pollLoop|Disconnect)\b' pkg/connectorRepository: beeper/line Length of output: 6067 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the startup / shutdown flow around Connect and Disconnect.
sed -n '250,360p' pkg/connector/client.go
printf '\n---\n'
sed -n '420,450p' pkg/connector/client.go
printf '\n---\n'
sed -n '1080,1145p' pkg/connector/sync.go
printf '\n---\n'
rg -n -C2 'Connect\(context\.Background\(\)\)|Disconnect\(\)|wg\.Wait\(|wg\.Add\(' pkg/connectorRepository: beeper/line Length of output: 9939 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the startup / shutdown flow around Connect and Disconnect.
sed -n '250,360p' pkg/connector/client.go
printf '\n---\n'
sed -n '420,450p' pkg/connector/client.go
printf '\n---\n'
sed -n '1080,1145p' pkg/connector/sync.go
printf '\n---\n'
rg -n -C2 'Connect\(context\.Background\(\)\)|Disconnect\(\)|wg\.Wait\(|wg\.Add\(' pkg/connectorRepository: beeper/line Length of output: 9939 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the startup / shutdown flow around Connect and Disconnect.
sed -n '250,360p' pkg/connector/client.go
printf '\n---\n'
sed -n '420,450p' pkg/connector/client.go
printf '\n---\n'
sed -n '1080,1145p' pkg/connector/sync.go
printf '\n---\n'
rg -n -C2 'Connect\(context\.Background\(\)\)|Disconnect\(\)|wg\.Wait\(|wg\.Add\(' pkg/connectorRepository: beeper/line Length of output: 9939 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the startup / shutdown flow around Connect and Disconnect.
sed -n '250,360p' pkg/connector/client.go
printf '\n---\n'
sed -n '420,450p' pkg/connector/client.go
printf '\n---\n'
sed -n '1080,1145p' pkg/connector/sync.go
printf '\n---\n'
rg -n -C2 'Connect\(context\.Background\(\)\)|Disconnect\(\)|wg\.Wait\(|wg\.Add\(' pkg/connectorRepository: beeper/line Length of output: 9939 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the startup / shutdown flow around Connect and Disconnect.
sed -n '250,360p' pkg/connector/client.go
printf '\n---\n'
sed -n '420,450p' pkg/connector/client.go
printf '\n---\n'
sed -n '1080,1145p' pkg/connector/sync.go
printf '\n---\n'
rg -n -C2 'Connect\(context\.Background\(\)\)|Disconnect\(\)|wg\.Wait\(|wg\.Add\(' pkg/connectorRepository: beeper/line Length of output: 9939 Reserve all four WaitGroup slots before 🤖 Prompt for AI Agents |
||
| go lc.syncDMChats(ctx) | ||
| go lc.prefetchMessages(ctx) | ||
| go lc.pollLoop(ctx) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,6 +74,31 @@ func groupDecryptLogContext(evt *zerolog.Event, msg *line.Message, chatMID strin | |
| return evt | ||
| } | ||
|
|
||
| type messageWithChatInfo struct { | ||
| *simplevent.Message[line.Message] | ||
| GetChatInfoFunc func(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) | ||
| } | ||
|
|
||
| var _ bridgev2.RemoteChatResyncWithInfo = (*messageWithChatInfo)(nil) | ||
|
|
||
| func (evt *messageWithChatInfo) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { | ||
| if evt.GetChatInfoFunc == nil { | ||
| return nil, nil | ||
| } | ||
| return evt.GetChatInfoFunc(ctx, portal) | ||
| } | ||
|
|
||
| func (lc *LineClient) getChatInfoForIncomingMessage(ctx context.Context, portal *bridgev2.Portal, chatMid string) (*bridgev2.ChatInfo, error) { | ||
| info, err := lc.GetChatInfo(ctx, portal) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| if isChatMID(chatMid) { | ||
| lc.stripRemoteMembersFromInitialChatInfo(info) | ||
| } | ||
| return info, nil | ||
| } | ||
|
|
||
| func (lc *LineClient) queueIncomingMessage(msg *line.Message, opType int) { | ||
| // Only process known content types; skip system messages (group created, member invited, etc.) | ||
| if !isBridgeableContentType(msg) { | ||
|
|
@@ -87,29 +112,45 @@ func (lc *LineClient) queueIncomingMessage(msg *line.Message, opType int) { | |
| return | ||
| } | ||
|
|
||
| senderID := makeUserID(msg.From) | ||
|
|
||
| portalIDStr := portalMIDForMessage(msg, opType) | ||
| portalKey := networkid.PortalKey{ID: makePortalID(portalIDStr), Receiver: lc.UserLogin.ID} | ||
| ts := lc.parseMessageTimestamp(msg) | ||
|
|
||
| lc.ensureGroupMessageSenderKnown(portalIDStr, msg.From, ts) | ||
|
|
||
| senderID := makeUserID(msg.From) | ||
| bodyText, unwrappedText := lc.decryptMessageBody(msg, portalIDStr, opType) | ||
| ts := lc.parseMessageTimestamp(msg) | ||
|
|
||
| lc.UserLogin.Bridge.QueueRemoteEvent(lc.UserLogin, &simplevent.Message[line.Message]{ | ||
| messageEvent := &simplevent.Message[line.Message]{ | ||
| EventMeta: simplevent.EventMeta{ | ||
| Type: bridgev2.RemoteEventMessage, | ||
| LogContext: func(c zerolog.Context) zerolog.Context { return c.Str("msg_id", msg.ID) }, | ||
| PortalKey: portalKey, | ||
| CreatePortal: true, | ||
| Sender: bridgev2.EventSender{Sender: senderID, IsFromMe: OperationType(opType) == OpSendMessage}, | ||
| Timestamp: ts, | ||
| PreHandleFunc: func(ctx context.Context, portal *bridgev2.Portal) { | ||
| lc.hiddenJoinGroupMessageSender(ctx, portal, portalIDStr, msg.From, ts) | ||
| }, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate first-message join paths. On line 119 we call
Comment on lines
+132
to
+134
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win Avoid emitting a hidden join for every group message.
🤖 Prompt for AI Agents |
||
| }, | ||
| Data: *msg, | ||
| ID: networkid.MessageID(msg.ID), | ||
| ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data line.Message) (*bridgev2.ConvertedMessage, error) { | ||
| return lc.convertLineMessage(ctx, portal, intent, data, bodyText, unwrappedText) | ||
| }, | ||
| }) | ||
| } | ||
|
|
||
| var remoteEvent bridgev2.RemoteEvent = messageEvent | ||
| if isChatMID(portalIDStr) { | ||
| remoteEvent = &messageWithChatInfo{ | ||
| Message: messageEvent, | ||
| GetChatInfoFunc: func(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { | ||
| return lc.getChatInfoForIncomingMessage(ctx, portal, portalIDStr) | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| lc.UserLogin.Bridge.QueueRemoteEvent(lc.UserLogin, remoteEvent) | ||
| } | ||
|
|
||
| // isBridgeableContentType reports whether an inbound LINE message should be | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synchronous
syncChatsblocks startup of every other login. mautrix'sbridge.StartLogins(bridge.go:373) callslogin.Client.Connect(ctx)for each login in sequence; previously all four sync goroutines were launched non-blocking and Connect returned almost immediately. Now Connect waits forsyncChatsto finish queueing every group plus up to 30s for portal creation (waitForGroupPortalCreates). For a single-login bridge that's fine; on a multi-login install all subsequent logins are delayed by that per-login window. If you want the ordering guarantee without blocking startup, you can keepsyncChatsin a goroutine and haveprefetchMessages+pollLoopwait on a sharedexsync.Eventset whenwaitForGroupPortalCreatesreturns.