Apply reactions optimistically
This commit is contained in:
		
					parent
					
						
							
								18abe93022
							
						
					
				
			
			
				commit
				
					
						03eaa9eb3e
					
				
			
		
					 6 changed files with 54 additions and 33 deletions
				
			
		| 
						 | 
				
			
			@ -61,11 +61,11 @@
 | 
			
		|||
            reaction.get('targetAuthorUuid'),
 | 
			
		||||
            reaction.get('targetTimestamp')
 | 
			
		||||
          );
 | 
			
		||||
          return;
 | 
			
		||||
          return undefined;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // awaiting is safe since `onReaction` is never called from inside the queue
 | 
			
		||||
        await targetConversation.queueJob(async () => {
 | 
			
		||||
        return await targetConversation.queueJob(async () => {
 | 
			
		||||
          window.log.info(
 | 
			
		||||
            'Handling reaction for',
 | 
			
		||||
            reaction.get('targetTimestamp')
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@
 | 
			
		|||
              oldReaction.forEach(r => this.remove(r));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
            return undefined;
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          const message = MessageController.register(
 | 
			
		||||
| 
						 | 
				
			
			@ -120,15 +120,18 @@
 | 
			
		|||
            targetMessage
 | 
			
		||||
          );
 | 
			
		||||
 | 
			
		||||
          await message.handleReaction(reaction);
 | 
			
		||||
          const oldReaction = await message.handleReaction(reaction);
 | 
			
		||||
 | 
			
		||||
          this.remove(reaction);
 | 
			
		||||
 | 
			
		||||
          return oldReaction;
 | 
			
		||||
        });
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        window.log.error(
 | 
			
		||||
          'Reactions.onReaction error:',
 | 
			
		||||
          error && error.stack ? error.stack : error
 | 
			
		||||
        );
 | 
			
		||||
        return undefined;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  }))();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								ts/model-types.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								ts/model-types.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -109,15 +109,6 @@ export type MessageAttributesType = {
 | 
			
		|||
  quote?: QuotedMessageType;
 | 
			
		||||
  reactions?: Array<{
 | 
			
		||||
    emoji: string;
 | 
			
		||||
    from: {
 | 
			
		||||
      id: string;
 | 
			
		||||
      color?: string;
 | 
			
		||||
      avatarPath?: string;
 | 
			
		||||
      name?: string;
 | 
			
		||||
      profileName?: string;
 | 
			
		||||
      isMe?: boolean;
 | 
			
		||||
      phoneNumber?: string;
 | 
			
		||||
    };
 | 
			
		||||
    fromId: string;
 | 
			
		||||
    targetAuthorUuid: string;
 | 
			
		||||
    targetTimestamp: number;
 | 
			
		||||
| 
						 | 
				
			
			@ -348,3 +339,15 @@ export declare class ConversationModelCollectionType extends Backbone.Collection
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
export declare class MessageModelCollectionType extends Backbone.Collection<MessageModel> {}
 | 
			
		||||
 | 
			
		||||
export type ReactionAttributesType = {
 | 
			
		||||
  emoji: string;
 | 
			
		||||
  remove?: boolean;
 | 
			
		||||
  targetAuthorUuid: string;
 | 
			
		||||
  targetTimestamp: number;
 | 
			
		||||
  fromId?: string;
 | 
			
		||||
  timestamp: number;
 | 
			
		||||
  fromSync?: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export declare class ReactionModelType extends Backbone.Model<ReactionAttributesType> {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,7 @@ import {
 | 
			
		|||
  MessageModelCollectionType,
 | 
			
		||||
  WhatIsThis,
 | 
			
		||||
  MessageAttributesType,
 | 
			
		||||
  ReactionModelType,
 | 
			
		||||
  ConversationAttributesType,
 | 
			
		||||
  VerificationOptions,
 | 
			
		||||
} from '../model-types.d';
 | 
			
		||||
| 
						 | 
				
			
			@ -3067,6 +3068,11 @@ export class ConversationModel extends window.Backbone
 | 
			
		|||
      fromSync: true,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // Apply reaction optimistically
 | 
			
		||||
    const oldReaction = await window.Whisper.Reactions.onReaction(
 | 
			
		||||
      reactionModel
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
 | 
			
		||||
    const destination = this.getSendTarget()!;
 | 
			
		||||
    const recipients = this.getRecipients();
 | 
			
		||||
| 
						 | 
				
			
			@ -3176,9 +3182,23 @@ export class ConversationModel extends window.Backbone
 | 
			
		|||
        throw new Error('No successful delivery for reaction');
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      window.Whisper.Reactions.onReaction(reactionModel);
 | 
			
		||||
 | 
			
		||||
      return result;
 | 
			
		||||
    }).catch(() => {
 | 
			
		||||
      let reverseReaction: ReactionModelType;
 | 
			
		||||
      if (oldReaction) {
 | 
			
		||||
        // Either restore old reaction
 | 
			
		||||
        reverseReaction = window.Whisper.Reactions.add({
 | 
			
		||||
          ...oldReaction,
 | 
			
		||||
          fromId: window.ConversationController.getOurConversationId(),
 | 
			
		||||
          timestamp,
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        // Or remove a new one on failure
 | 
			
		||||
        reverseReaction = reactionModel.clone();
 | 
			
		||||
        reverseReaction.set('remove', !reverseReaction.get('remove'));
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      window.Whisper.Reactions.onReaction(reverseReaction);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ import {
 | 
			
		|||
  CustomError,
 | 
			
		||||
  MessageAttributesType,
 | 
			
		||||
  RetryOptions,
 | 
			
		||||
  ReactionAttributesType,
 | 
			
		||||
  ShallowChallengeError,
 | 
			
		||||
  QuotedMessageType,
 | 
			
		||||
  WhatIsThis,
 | 
			
		||||
| 
						 | 
				
			
			@ -4084,9 +4085,9 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
 | 
			
		|||
  async handleReaction(
 | 
			
		||||
    reaction: typeof window.WhatIsThis,
 | 
			
		||||
    shouldPersist = true
 | 
			
		||||
  ): Promise<void> {
 | 
			
		||||
  ): Promise<ReactionAttributesType | undefined> {
 | 
			
		||||
    if (this.get('deletedForEveryone')) {
 | 
			
		||||
      return;
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We allow you to react to messages with outgoing errors only if it has sent
 | 
			
		||||
| 
						 | 
				
			
			@ -4095,7 +4096,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
 | 
			
		|||
      this.hasErrors() &&
 | 
			
		||||
      (this.isIncoming() || this.getMessagePropStatus() !== 'partial-sent')
 | 
			
		||||
    ) {
 | 
			
		||||
      return;
 | 
			
		||||
      return undefined;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const reactions = this.get('reactions') || [];
 | 
			
		||||
| 
						 | 
				
			
			@ -4108,6 +4109,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
 | 
			
		|||
 | 
			
		||||
    let reactionToRemove: Partial<ReactionType> | undefined;
 | 
			
		||||
 | 
			
		||||
    let oldReaction: ReactionAttributesType | undefined;
 | 
			
		||||
    if (reaction.get('remove')) {
 | 
			
		||||
      window.log.info('Removing reaction for message', messageId);
 | 
			
		||||
      const newReactions = reactions.filter(
 | 
			
		||||
| 
						 | 
				
			
			@ -4137,9 +4139,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
 | 
			
		|||
      newReactions.push(reaction.toJSON());
 | 
			
		||||
      this.set({ reactions: newReactions });
 | 
			
		||||
 | 
			
		||||
      const oldReaction = reactions.find(
 | 
			
		||||
        re => re.fromId === reaction.get('fromId')
 | 
			
		||||
      );
 | 
			
		||||
      oldReaction = reactions.find(re => re.fromId === reaction.get('fromId'));
 | 
			
		||||
      if (oldReaction) {
 | 
			
		||||
        reactionToRemove = {
 | 
			
		||||
          emoji: oldReaction.emoji,
 | 
			
		||||
| 
						 | 
				
			
			@ -4177,6 +4177,8 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
 | 
			
		|||
        Message: window.Whisper.Message,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return oldReaction;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async handleDeleteForEveryone(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -179,15 +179,6 @@ export type MessageType = {
 | 
			
		|||
  reactions?: Array<{
 | 
			
		||||
    emoji: string;
 | 
			
		||||
    timestamp: number;
 | 
			
		||||
    from: {
 | 
			
		||||
      id: string;
 | 
			
		||||
      color?: string;
 | 
			
		||||
      avatarPath?: string;
 | 
			
		||||
      name?: string;
 | 
			
		||||
      profileName?: string;
 | 
			
		||||
      isMe?: boolean;
 | 
			
		||||
      phoneNumber?: string;
 | 
			
		||||
    };
 | 
			
		||||
  }>;
 | 
			
		||||
  deletedForEveryone?: boolean;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								ts/window.d.ts
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								ts/window.d.ts
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -16,6 +16,8 @@ import {
 | 
			
		|||
  ConversationModelCollectionType,
 | 
			
		||||
  MessageModelCollectionType,
 | 
			
		||||
  MessageAttributesType,
 | 
			
		||||
  ReactionAttributesType,
 | 
			
		||||
  ReactionModelType,
 | 
			
		||||
} from './model-types.d';
 | 
			
		||||
import { ContactRecordIdentityState, TextSecureType } from './textsecure.d';
 | 
			
		||||
import {
 | 
			
		||||
| 
						 | 
				
			
			@ -724,9 +726,9 @@ export type WhisperType = {
 | 
			
		|||
  };
 | 
			
		||||
 | 
			
		||||
  Reactions: {
 | 
			
		||||
    forMessage: (message: unknown) => Array<WhatIsThis>;
 | 
			
		||||
    add: (reaction: unknown) => WhatIsThis;
 | 
			
		||||
    onReaction: (reactionModel: unknown) => unknown;
 | 
			
		||||
    forMessage: (message: unknown) => Array<ReactionModelType>;
 | 
			
		||||
    add: (reaction: ReactionAttributesType) => ReactionModelType;
 | 
			
		||||
    onReaction: (reactionModel: ReactionModelType) => ReactionAttributesType;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  Deletes: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue