Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions pkg/connector/chatsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

"github.com/rs/zerolog"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/bridgev2/simplevent"

"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
Expand Down Expand Up @@ -74,6 +75,15 @@ func (l *LinkedInClient) handleConversations(ctx context.Context, convs []linked
Logger()

l.conversationLastRead[conv.EntityURN] = conv.LastReadAt
readStatusChanged := false
lastReadState, ok := l.conversationReadState[conv.EntityURN]
if (ok && lastReadState.Read != conv.Read) || !ok {
readStatusChanged = true
}
l.conversationReadState[conv.EntityURN] = ConversationReadState{
LastReadAt: conv.LastReadAt,
Read: conv.Read,
}

if conv.LastActivityAt.Before(updatedBefore) {
updatedBefore = conv.LastActivityAt.Time
Expand Down Expand Up @@ -115,6 +125,21 @@ func (l *LinkedInClient) handleConversations(ctx context.Context, convs []linked
EventMeta: meta.WithType(bridgev2.RemoteEventChatResync),
LatestMessageTS: latestMessageTS,
})
if readStatusChanged {
sender := bridgev2.EventSender{
IsFromMe: true,
Sender: networkid.UserID(l.userLogin.ID),
SenderLogin: l.userLogin.ID,
}
l.main.Bridge.QueueRemoteEvent(l.userLogin, &simplevent.MarkUnread{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventMarkUnread,
PortalKey: portalKey,
Sender: sender,
},
Unread: !conv.Read,
})
}

if l.main.Config.Sync.UpdateLimit > 0 && updated >= l.main.Config.Sync.UpdateLimit {
log.Info().Msg("Update limit reached")
Expand Down
19 changes: 13 additions & 6 deletions pkg/connector/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,20 @@ import (
"go.mau.fi/mautrix-linkedin/pkg/linkedingo"
)

type ConversationReadState struct {
LastReadAt jsontime.UnixMilli
Read bool
}

type LinkedInClient struct {
main *LinkedInConnector
userID networkid.UserID
userLogin *bridgev2.UserLogin
client *linkedingo.Client

sessID uuid.UUID
conversationLastRead map[linkedingo.URN]jsontime.UnixMilli
sessID uuid.UUID
conversationLastRead map[linkedingo.URN]jsontime.UnixMilli
conversationReadState map[linkedingo.URN]ConversationReadState

linkedinFmtParams linkedinfmt.FormatParams
matrixParser *matrixfmt.HTMLParser
Expand All @@ -59,10 +65,11 @@ var (
func NewLinkedInClient(ctx context.Context, lc *LinkedInConnector, login *bridgev2.UserLogin) *LinkedInClient {
userID := networkid.UserID(login.ID)
client := &LinkedInClient{
main: lc,
userID: userID,
userLogin: login,
conversationLastRead: map[linkedingo.URN]jsontime.UnixMilli{},
main: lc,
userID: userID,
userLogin: login,
conversationLastRead: map[linkedingo.URN]jsontime.UnixMilli{},
conversationReadState: map[linkedingo.URN]ConversationReadState{},
}
client.client = linkedingo.NewClient(
ctx,
Expand Down
25 changes: 19 additions & 6 deletions pkg/connector/handlelinkedin.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,16 @@ func (l *LinkedInClient) onDecoratedEvent(ctx context.Context, decoratedEvent *l
Logger()
log.Debug().Msg("Received decorated event")

data := decoratedEvent.Payload.Data

// The topics are always of the form "urn:li-realtime:TOPIC_NAME:<topic_dependent>"
switch decoratedEvent.Topic.NthPrefixPart(2) {
case linkedingo.RealtimeEventTopicConversations:
l.onRealtimeConversations(ctx)
var conv *linkedingo.Conversation
if data.DecoratedConversation != nil {
conv = &data.DecoratedConversation.Result
}
l.onRealtimeConversations(ctx, conv)
case linkedingo.RealtimeEventTopicConversationDelete:
l.onRealtimeConversationDelete(ctx, decoratedEvent.Payload.Data.DecoratedConversationDelete.Result)
case linkedingo.RealtimeEventTopicMessages:
Expand All @@ -78,13 +84,20 @@ func (l *LinkedInClient) onDecoratedEvent(ctx context.Context, decoratedEvent *l
}
}

func (l *LinkedInClient) onRealtimeConversations(ctx context.Context) {
convs, err := l.client.GetConversations(ctx)
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("failed to get conversations")
func (l *LinkedInClient) onRealtimeConversations(ctx context.Context, conv *linkedingo.Conversation) {
var convs []linkedingo.Conversation
if conv != nil {
convs = []linkedingo.Conversation{*conv}
} else {
convsRes, err := l.client.GetConversations(ctx)
if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("failed to get conversations")
return
}
convs = convsRes.Elements
}

l.handleConversations(ctx, convs.Elements)
l.handleConversations(ctx, convs)
}

func (l *LinkedInClient) onRealtimeConversationDelete(ctx context.Context, conv linkedingo.Conversation) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/linkedingo/conversations.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,6 @@ func (c *Client) DeleteConversation(ctx context.Context, conversationURN URN) er
return err
}

type DecoratedConversationDelete struct {
type DecoratedConversation struct {
Result Conversation `json:"result,omitempty"`
}
13 changes: 7 additions & 6 deletions pkg/linkedingo/realtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ type DecoratedEventPayload struct {
}

type DecoratedEventData struct {
Type string `json:"_type,omitempty"`
DecoratedConversationDelete *DecoratedConversationDelete `json:"doDecorateConversationDeleteMessengerRealtimeDecoration,omitempty"`
DecoratedMessage *DecoratedMessage `json:"doDecorateMessageMessengerRealtimeDecoration,omitempty"`
DecoratedTypingIndicator *DecoratedTypingIndicator `json:"doDecorateTypingIndicatorMessengerRealtimeDecoration,omitempty"`
DecoratedSeenReceipt *DecoratedSeenReceipt `json:"doDecorateSeenReceiptMessengerRealtimeDecoration,omitempty"`
DecoratedReactionSummary *DecoratedReactionSummary `json:"doDecorateRealtimeReactionSummaryMessengerRealtimeDecoration,omitempty"`
Type string `json:"_type,omitempty"`
DecoratedConversation *DecoratedConversation `json:"doDecorateConversationMessengerRealtimeDecoration,omitempty"`
DecoratedConversationDelete *DecoratedConversation `json:"doDecorateConversationDeleteMessengerRealtimeDecoration,omitempty"`
DecoratedMessage *DecoratedMessage `json:"doDecorateMessageMessengerRealtimeDecoration,omitempty"`
DecoratedTypingIndicator *DecoratedTypingIndicator `json:"doDecorateTypingIndicatorMessengerRealtimeDecoration,omitempty"`
DecoratedSeenReceipt *DecoratedSeenReceipt `json:"doDecorateSeenReceiptMessengerRealtimeDecoration,omitempty"`
DecoratedReactionSummary *DecoratedReactionSummary `json:"doDecorateRealtimeReactionSummaryMessengerRealtimeDecoration,omitempty"`
}

func (c *Client) RealtimeConnect(ctx context.Context) error {
Expand Down