Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Vector 443 #118

Merged
merged 5 commits into from
Aug 12, 2016
Merged
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
154 changes: 144 additions & 10 deletions MatrixSDK/Data/MXEventTimeline.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ @interface MXEventTimeline ()
// past timelines is managed locally.
NSString *forwardsPaginationToken;
BOOL hasReachedHomeServerForwardsPaginationEnd;

/**
The current pending request.
*/
MXHTTPOperation *httpOperation;
}
@end

Expand Down Expand Up @@ -102,6 +107,13 @@ - (void)initialiseState:(NSArray<MXEvent *> *)stateEvents

- (void)destroy
{
if (httpOperation)
{
// Cancel the current server request
[httpOperation cancel];
httpOperation = nil;
}

if (!_isLiveTimeline)
{
// Release past timeline events stored in memory
Expand Down Expand Up @@ -409,7 +421,7 @@ - (void)handleJoinedRoomSync:(MXRoomSync *)roomSync
else if (roomSync.timeline.limited)
{
// The room has been resync with a limited timeline - Post notification
[[NSNotificationCenter defaultCenter] postNotificationName:kMXRoomSyncWithLimitedTimelineNotification
[[NSNotificationCenter defaultCenter] postNotificationName:kMXRoomDidFlushDataNotification
object:room
userInfo:nil];
}
Expand Down Expand Up @@ -537,23 +549,145 @@ - (void)addEvent:(MXEvent*)event direction:(MXTimelineDirection)direction fromSt
#pragma mark - Specific events Handling
- (void)handleRedaction:(MXEvent*)redactionEvent
{
// Check whether the redacted event has been already processed
NSLog(@"[MXEventTimeline] handle an event redaction");

// Check whether the redacted event is stored in room messages
MXEvent *redactedEvent = [store eventWithEventId:redactionEvent.redacts inRoom:_state.roomId];
if (redactedEvent)
{
// Redact the stored event
redactedEvent = [redactedEvent prune];
redactedEvent.redactedBecause = redactionEvent.JSONDictionary;

if (redactedEvent.isState) {
// FIXME: The room state must be refreshed here since this redacted event.
}

// Store the event
// Store the updated event
[store replaceEvent:redactedEvent inRoom:_state.roomId];
}

// Check whether the current room state depends on this redacted event.
if (!redactedEvent || redactedEvent.isState)
{
NSMutableArray *stateEvents = [NSMutableArray arrayWithArray:_state.stateEvents];

for (NSInteger index = 0; index < stateEvents.count; index++)
{
MXEvent *stateEvent = stateEvents[index];

if ([stateEvent.eventId isEqualToString:redactionEvent.redacts])
{
NSLog(@"[MXEventTimeline] the current room state has been modified by the event redaction.");

// Redact the stored event
redactedEvent = [stateEvent prune];
redactedEvent.redactedBecause = redactionEvent.JSONDictionary;

[stateEvents replaceObjectAtIndex:index withObject:redactedEvent];

// Reset the room state.
_state = [[MXRoomState alloc] initWithRoomId:room.roomId andMatrixSession:room.mxSession andDirection:YES];
[self initialiseState:stateEvents];

// Update store with new room state when all state event have been processed
if ([store respondsToSelector:@selector(storeStateForRoom:stateEvents:)])
{
[store storeStateForRoom:_state.roomId stateEvents:_state.stateEvents];
}

// Reset the current pagination
[self resetPagination];

// Notify that room history has been flushed
[[NSNotificationCenter defaultCenter] postNotificationName:kMXRoomDidFlushDataNotification
object:room
userInfo:nil];
return;
}
}
}

// Re-sync the room in case of redacted state event from the past.
// Indeed, redacted information shouldn't spontaneously appear when you backpaginate...
if (!redactedEvent)
{
// Use a /context request to check whether the redacted event is a state event or not.
httpOperation = [room.mxSession.matrixRestClient contextOfEvent:redactionEvent.redacts inRoom:room.roomId limit:1 success:^(MXEventContext *eventContext) {

if (!httpOperation)
{
return;
}
httpOperation = nil;

if (eventContext.event.isState)
{
NSLog(@"[MXEventTimeline] the redacted event is a state event from the past");
[self forceRoomServerSync];
}

} failure:^(NSError *error) {

if (!httpOperation)
{
return;
}
httpOperation = nil;

NSLog(@"[MXEventTimeline] handleRedaction: failed to retrieved the redacted event");
[self forceRoomServerSync];
}];
}
else if (redactedEvent.isState)
{
NSLog(@"[MXEventTimeline] the redacted event is a former state event");
[self forceRoomServerSync];
}
}

- (void)forceRoomServerSync
{
// Reset the storage of this room. Re-sync it from the server
NSLog(@"[MXEventTimeline] re-sync room (%@) from the server.", room.roomId);
[store deleteRoom:room.roomId];

// Make an /initialSync request to get data
// Use a 0 messages limit for now because:
// - /initialSync is marked as obsolete in the spec
// - MXEventTimeline does not have methods to handle /initialSync responses
// So, avoid to write temparary code and let the user uses [MXEventTimeline paginate]
// to get room messages.
httpOperation = [room.mxSession.matrixRestClient initialSyncOfRoom:room.roomId withLimit:0 success:^(MXRoomInitialSync *roomInitialSync) {

if (!httpOperation)
{
return;
}
httpOperation = nil;

_state = [[MXRoomState alloc] initWithRoomId:room.roomId andMatrixSession:room.mxSession andDirection:YES];
[self initialiseState:roomInitialSync.state];

// Update store with new room state when all state event have been processed
if ([store respondsToSelector:@selector(storeStateForRoom:stateEvents:)])
{
[store storeStateForRoom:_state.roomId stateEvents:_state.stateEvents];
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[store commit] should be called to persist the data right now

[self resetPagination];

// Notify that room history has been flushed
[[NSNotificationCenter defaultCenter] postNotificationName:kMXRoomDidFlushDataNotification
object:room
userInfo:nil];

} failure:^(NSError *error) {

NSLog(@"[MXEventTimeline] forceRoomServerSync failed.");

// Reload entirely the app
[[NSNotificationCenter defaultCenter] postNotificationName:kMXSessionDidCorruptDataNotification
object:room.mxSession
userInfo:nil];
}];
}

#pragma mark - State events handling
- (void)cloneState:(MXTimelineDirection)direction
Expand Down Expand Up @@ -584,10 +718,10 @@ - (void)handleStateEvent:(MXEvent*)event direction:(MXTimelineDirection)directio
// Forwards events update the current state of the room
[_state handleStateEvent:event];

// Special handling for presence
if (_isLiveTimeline && MXEventTypeRoomMember == event.eventType)
// Special handling for presence: update MXUser data in case of membership event.
// CAUTION: ignore here redacted state event, the redaction concerns only the context of the event room.
if (_isLiveTimeline && MXEventTypeRoomMember == event.eventType && !event.isRedactedEvent)
{
// Update MXUser data
MXUser *user = [room.mxSession getOrCreateUser:event.sender];

MXRoomMember *roomMember = [_state memberWithUserId:event.sender];
Expand Down
6 changes: 3 additions & 3 deletions MatrixSDK/Data/MXRoom.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@
FOUNDATION_EXPORT NSString *const kMXRoomInitialSyncNotification;

/**
Posted when a limited timeline is observed for an existing room during server sync.
All the existing messages have been removed from the room storage. Only the messages received during this sync are available.
Posted when the messages of an existing room has been flushed during server sync.
This flush may be due to a limited timeline in the room sync, or the redaction of a state event.
The token where to start back pagination has been updated.

The notification object is the concerned room (MXRoom instance).
*/
FOUNDATION_EXPORT NSString *const kMXRoomSyncWithLimitedTimelineNotification;
FOUNDATION_EXPORT NSString *const kMXRoomDidFlushDataNotification;

/**
Posted when the number of unread notifications ('notificationCount' and 'highlightCount' properties) are updated.
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Data/MXRoom.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#import "MXError.h"

NSString *const kMXRoomSyncWithLimitedTimelineNotification = @"kMXRoomSyncWithLimitedTimelineNotification";
NSString *const kMXRoomDidFlushDataNotification = @"kMXRoomDidFlushDataNotification";
NSString *const kMXRoomInitialSyncNotification = @"kMXRoomInitialSyncNotification";
NSString *const kMXRoomDidUpdateUnreadNotification = @"kMXRoomDidUpdateUnreadNotification";

Expand Down
12 changes: 11 additions & 1 deletion MatrixSDK/JSONModels/MXEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,20 @@ FOUNDATION_EXPORT uint64_t const kMXUndefinedTimestamp;
- (MXEventType)eventType;

/**
Indicates if the event hosts state data
Indicates if the event hosts state data.
*/
- (BOOL)isState;

/**
Indicates if the event has been redacted.
*/
- (BOOL)isRedactedEvent;

/**
Return YES if the event is an emote event
*/
- (BOOL)isEmote;

/**
Returns the event IDs for which a read receipt is defined in this event.

Expand Down
19 changes: 19 additions & 0 deletions MatrixSDK/JSONModels/MXEvent.m
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,25 @@ - (BOOL)isState
return (nil != self.stateKey);
}

- (BOOL)isRedactedEvent
{
// The event is redacted if its redactedBecause is filed (with a redaction event id)
return (self.redactedBecause != nil);
}

- (BOOL)isEmote
{
if (self.eventType == MXEventTypeRoomMessage)
{
NSString *msgtype = self.content[@"msgtype"];
if ([msgtype isEqualToString:kMXMessageTypeEmote])
{
return YES;
}
}
return NO;
}

- (NSArray *)readReceiptEventIds
{
NSMutableArray* list = nil;
Expand Down
8 changes: 8 additions & 0 deletions MatrixSDK/MXSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,17 @@ FOUNDATION_EXPORT NSString *const kMXSessionNotificationEventKey;

/**
Posted when MXSession has detected a change in the `ignoredUsers` property.

The notification object is the concerned session (MXSession instance).
*/
FOUNDATION_EXPORT NSString *const kMXSessionIgnoredUsersDidChangeNotification;

/**
Posted when MXSession data have been corrupted. The listener must reload the session data with a full server sync.

The notification object is the concerned session (MXSession instance).
*/
FOUNDATION_EXPORT NSString *const kMXSessionDidCorruptDataNotification;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nobody (MatrixSDK, MatrixKit, Vector, Console) listens to this notification. This is scary.


#pragma mark - Other constants
/**
Expand Down
1 change: 1 addition & 0 deletions MatrixSDK/MXSession.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
NSString *const kMXSessionNotificationRoomIdKey = @"roomId";
NSString *const kMXSessionNotificationEventKey = @"event";
NSString *const kMXSessionIgnoredUsersDidChangeNotification = @"kMXSessionIgnoredUsersDidChangeNotification";
NSString *const kMXSessionDidCorruptDataNotification = @"kMXSessionDidCorruptDataNotification";
NSString *const kMXSessionNoRoomTag = @"m.recent"; // Use the same value as matrix-react-sdk

/**
Expand Down