@@ -123,17 +123,52 @@ func (s *MessageService) FetchMessages(ctx context.Context, req *models.FetchMes
123123 return nil , ErrAuthentication
124124 }
125125
126- logger .Debug ().Str ("user_id" , string (userID )).Str ("since" , req .LastID ).Msg ("syncing messages from matrix" )
126+ since := req .LastID
127+ var filterAfterEventID string
127128
128- resp , err := s .matrixClient .Sync (ctx , userID , req .LastID )
129+ // Acrobits might send a Matrix Event ID (starts with $) as last_id.
130+ // Matrix Sync requires a stream token (usually starts with s).
131+ // If we get an Event ID, we must perform an initial sync (empty since)
132+ // and manually filter the results to return only messages after that event.
133+ if strings .HasPrefix (since , "$" ) {
134+ logger .Debug ().Str ("last_id" , since ).Msg ("received event ID as last_id, performing initial sync and filtering" )
135+ filterAfterEventID = since
136+ since = ""
137+ }
138+
139+ logger .Debug ().Str ("user_id" , string (userID )).Str ("since" , since ).Msg ("syncing messages from matrix" )
140+
141+ resp , err := s .matrixClient .Sync (ctx , userID , since )
142+ if err != nil {
143+ // If the token is invalid (e.g. expired or from a different session), retry with a full sync.
144+ if strings .Contains (err .Error (), "Invalid stream token" ) || strings .Contains (err .Error (), "M_UNKNOWN" ) {
145+ logger .Warn ().Err (err ).Msg ("invalid stream token, retrying with full sync" )
146+ since = ""
147+ resp , err = s .matrixClient .Sync (ctx , userID , since )
148+ }
149+ }
129150 if err != nil {
130151 logger .Error ().Str ("user_id" , string (userID )).Err (err ).Msg ("matrix sync failed" )
131152 return nil , fmt .Errorf ("sync messages: %w" , mapAuthErr (err ))
132153 }
133154
134155 received , sent := make ([]models.Message , 0 , 8 ), make ([]models.Message , 0 , 8 )
135156 for _ , room := range resp .Rooms .Join {
136- for _ , evt := range room .Timeline .Events {
157+ // If we are filtering by event ID, check if the event is in this room's timeline.
158+ // If it is, we only want events AFTER it.
159+ // If it's not, we assume the event is older than the timeline window, so we take all events.
160+ startIndex := 0
161+ if filterAfterEventID != "" {
162+ for i , evt := range room .Timeline .Events {
163+ if string (evt .ID ) == filterAfterEventID {
164+ startIndex = i + 1
165+ break
166+ }
167+ }
168+ }
169+
170+ for i := startIndex ; i < len (room .Timeline .Events ); i ++ {
171+ evt := room .Timeline .Events [i ]
137172 if evt .Type != event .EventMessage {
138173 continue
139174 }
0 commit comments