Bladeren bron

Messages container: Use BaseReceiver type

Previously the methods defined on the Messages container would require a
`Receiver` even though only a `BaseReceiver` was required.

Changing the signature to require only a `BaseReceiver` and adding a
type guard function could get rid of some unchecked casts.
Danilo Bargen 7 jaren geleden
bovenliggende
commit
90843d09b9
4 gewijzigde bestanden met toevoegingen van 74 en 48 verwijderingen
  1. 14 8
      src/services/webclient.ts
  2. 19 19
      src/threema.d.ts
  3. 25 21
      src/threema/container.ts
  4. 16 0
      src/typeguards.ts

+ 14 - 8
src/services/webclient.ts

@@ -21,7 +21,7 @@
 
 import * as msgpack from 'msgpack-lite';
 import {hasFeature, hexToU8a, msgpackVisualizer} from '../helpers';
-import {isContactReceiver, isDistributionListReceiver, isGroupReceiver} from '../typeguards';
+import {isContactReceiver, isDistributionListReceiver, isGroupReceiver, isValidReceiverType} from '../typeguards';
 import {BatteryStatusService} from './battery';
 import {BrowserService} from './browser';
 import {TrustedKeyStoreService} from './keystore';
@@ -1889,13 +1889,13 @@ export class WebClientService {
     }
 
     private _receiveResponseMessages(message: threema.WireMessage): void {
-        this.$log.debug('Received message response');
+        this.$log.debug('Received messages response');
 
         // Unpack data and arguments
         const args = message.args;
         const data = message.data as threema.Message[];
         if (args === undefined || data === undefined) {
-            this.$log.warn('Invalid message response, data or arguments missing');
+            this.$log.warn('Invalid messages response, data or arguments missing');
             return;
         }
 
@@ -1904,18 +1904,20 @@ export class WebClientService {
         const id: string = args[WebClientService.ARGUMENT_RECEIVER_ID];
         let more: boolean = args[WebClientService.ARGUMENT_HAS_MORE];
         if (type === undefined || id === undefined || more === undefined) {
-            this.$log.warn('Invalid message response, argument field missing');
+            this.$log.warn('Invalid messages response, argument field missing');
             return;
         }
+        if (!isValidReceiverType(type)) {
+            this.$log.warn('Invalid messages response, unknown receiver type (' + type + ')');
+            return;
+        }
+        const receiver: threema.BaseReceiver = {type: type, id: id};
 
         // If there's no data returned, override `more` field.
         if (data.length === 0) {
             more = false;
         }
 
-        // Check if the page was requested
-        const receiver = {type: type, id: id} as threema.Receiver;
-
         // Set as loaded
         this.loadingMessages.delete(receiver.type + receiver.id);
 
@@ -2083,7 +2085,11 @@ export class WebClientService {
             this.$log.warn('Invalid message update, argument field missing');
             return;
         }
-        const receiver = {type: type, id: id} as threema.Receiver;
+        if (!isValidReceiverType(type)) {
+            this.$log.warn('Invalid messages update, unknown receiver type (' + type + ')');
+            return;
+        }
+        const receiver: threema.BaseReceiver = {type: type, id: id};
 
         // React depending on mode
         for (const msg of data) {

+ 19 - 19
src/threema.d.ts

@@ -797,26 +797,26 @@ declare namespace threema {
 
         interface Messages {
             converter: (data: Message) => Message;
-            getList(receiver: Receiver): Message[];
+            getList(receiver: BaseReceiver): Message[];
             clear($scope: ng.IScope): void;
-            clearReceiverMessages(receiver: Receiver): number;
-            contains(receiver: Receiver): boolean;
-            hasMore(receiver: Receiver): boolean;
-            setMore(receiver: Receiver, more: boolean): void;
-            getReferenceMsgId(receiver: Receiver): string;
-            isRequested(receiver: Receiver): boolean;
-            setRequested(receiver: Receiver): void;
-            clearRequested(receiver): void;
-            addNewer(receiver: Receiver, messages: Message[]): void;
-            addOlder(receiver: Receiver, messages: Message[]): void;
-            update(receiver: Receiver, message: Message): boolean;
-            setThumbnail(receiver: Receiver, messageId: string, thumbnailImage: string): boolean;
-            remove(receiver: Receiver, messageId: string): boolean;
-            removeTemporary(receiver: Receiver, temporaryMessageId: string): boolean;
-            bindTemporaryToMessageId(receiver: Receiver, temporaryId: string, messageId: string): boolean;
-            notify(receiver: Receiver, $scope: ng.IScope): void;
-            register(receiver: Receiver, $scope: ng.IScope, callback: any): Message[];
-            updateFirstUnreadMessage(receiver: Receiver);
+            clearReceiverMessages(receiver: BaseReceiver): number;
+            contains(receiver: BaseReceiver): boolean;
+            hasMore(receiver: BaseReceiver): boolean;
+            setMore(receiver: BaseReceiver, more: boolean): void;
+            getReferenceMsgId(receiver: BaseReceiver): string;
+            isRequested(receiver: BaseReceiver): boolean;
+            setRequested(receiver: BaseReceiver): void;
+            clearRequested(receiver: BaseReceiver): void;
+            addNewer(receiver: BaseReceiver, messages: Message[]): void;
+            addOlder(receiver: BaseReceiver, messages: Message[]): void;
+            update(receiver: BaseReceiver, message: Message): boolean;
+            setThumbnail(receiver: BaseReceiver, messageId: string, thumbnailImage: string): boolean;
+            remove(receiver: BaseReceiver, messageId: string): boolean;
+            removeTemporary(receiver: BaseReceiver, temporaryMessageId: string): boolean;
+            bindTemporaryToMessageId(receiver: BaseReceiver, temporaryId: string, messageId: string): boolean;
+            notify(receiver: BaseReceiver, $scope: ng.IScope): void;
+            register(receiver: BaseReceiver, $scope: ng.IScope, callback: any): Message[];
+            updateFirstUnreadMessage(receiver: BaseReceiver);
         }
 
         interface Typing {

+ 25 - 21
src/threema/container.ts

@@ -371,7 +371,7 @@ class Messages implements threema.Container.Messages {
     /**
      * Ensure that the receiver exists in the receiver map.
      */
-    private lazyCreate(receiver: threema.Receiver): void {
+    private lazyCreate(receiver: threema.BaseReceiver): void {
         // If the type is not yet known, create a new type map.
         if (!this.messages.has(receiver.type)) {
             this.messages.set(receiver.type, new Map());
@@ -389,7 +389,7 @@ class Messages implements threema.Container.Messages {
      *
      * If the receiver is not known yet, it is initialized.
      */
-    private getReceiverMessages(receiver: threema.Receiver): ReceiverMessages {
+    private getReceiverMessages(receiver: threema.BaseReceiver): ReceiverMessages {
         this.lazyCreate(receiver);
         return this.messages.get(receiver.type).get(receiver.id);
     }
@@ -400,7 +400,7 @@ class Messages implements threema.Container.Messages {
      * If the receiver is not known yet, it is initialized with an empty
      * message list.
      */
-    public getList(receiver: threema.Receiver): threema.Message[] {
+    public getList(receiver: threema.BaseReceiver): threema.Message[] {
         return this.getReceiverMessages(receiver).list;
     }
 
@@ -427,7 +427,7 @@ class Messages implements threema.Container.Messages {
     /**
      * Reset the cached messages of a receiver (e.g. the receiver was locked by the mobile)
      */
-    public clearReceiverMessages(receiver: threema.Receiver): number {
+    public clearReceiverMessages(receiver: threema.BaseReceiver): number {
         let cachedMessageCount = 0;
         if (this.messages.has(receiver.type)) {
             const typeMessages = this.messages.get(receiver.type);
@@ -443,7 +443,7 @@ class Messages implements threema.Container.Messages {
     /**
      * Return whether messages from/for the specified receiver are available.
      */
-    public contains(receiver: threema.Receiver): boolean {
+    public contains(receiver: threema.BaseReceiver): boolean {
         return this.messages.has(receiver.type) &&
                this.messages.get(receiver.type).has(receiver.id);
     }
@@ -452,7 +452,7 @@ class Messages implements threema.Container.Messages {
      * Return whether there are more (older) messages available to fetch
      * for the specified receiver.
      */
-    public hasMore(receiver: threema.Receiver): boolean {
+    public hasMore(receiver: threema.BaseReceiver): boolean {
         return this.getReceiverMessages(receiver).more;
     }
 
@@ -461,14 +461,14 @@ class Messages implements threema.Container.Messages {
      *
      * The flag indicates that more (older) messages are available.
      */
-    public setMore(receiver: threema.Receiver, more: boolean): void {
+    public setMore(receiver: threema.BaseReceiver, more: boolean): void {
         this.getReceiverMessages(receiver).more = more;
     }
 
     /**
      * Return the reference msg id for the specified receiver.
      */
-    public getReferenceMsgId(receiver: threema.Receiver): string {
+    public getReferenceMsgId(receiver: threema.BaseReceiver): string {
         return this.getReceiverMessages(receiver).referenceMsgId;
     }
 
@@ -476,14 +476,14 @@ class Messages implements threema.Container.Messages {
      * Return whether the messages for the specified receiver are already
      * requested.
      */
-    public isRequested(receiver: threema.Receiver): boolean {
+    public isRequested(receiver: threema.BaseReceiver): boolean {
         return this.getReceiverMessages(receiver).requested;
     }
 
     /**
      * Set the requested flag for the specified receiver.
      */
-    public setRequested(receiver: threema.Receiver): void {
+    public setRequested(receiver: threema.BaseReceiver): void {
         const messages = this.getReceiverMessages(receiver);
 
         // If a request was already pending, this must be a bug.
@@ -498,7 +498,7 @@ class Messages implements threema.Container.Messages {
     /**
      * Clear the "requested" flag for the specified receiver messages.
      */
-    public clearRequested(receiver): void {
+    public clearRequested(receiver: threema.BaseReceiver): void {
         const messages = this.getReceiverMessages(receiver);
         messages.requested = false;
     }
@@ -508,7 +508,7 @@ class Messages implements threema.Container.Messages {
      *
      * Messages must be sorted ascending by date.
      */
-    public addNewer(receiver: threema.Receiver, messages: threema.Message[]): void {
+    public addNewer(receiver: threema.BaseReceiver, messages: threema.Message[]): void {
         if (messages.length === 0) {
             // do nothing
             return;
@@ -526,7 +526,7 @@ class Messages implements threema.Container.Messages {
      *
      * Messages must be sorted ascending by date (oldest first).
      */
-    public addOlder(receiver: threema.Receiver, messages: threema.Message[]): void {
+    public addOlder(receiver: threema.BaseReceiver, messages: threema.Message[]): void {
         if (messages.length === 0) {
             // do nothing
             return;
@@ -556,7 +556,7 @@ class Messages implements threema.Container.Messages {
      * Return a boolean indicating whether the message was found and
      * replaced, or not.
      */
-    public update(receiver: threema.Receiver, message: threema.Message): boolean {
+    public update(receiver: threema.BaseReceiver, message: threema.Message): boolean {
         const list = this.getList(receiver);
         for (let i = 0; i < list.length; i++) {
             if (list[i].id === message.id) {
@@ -575,7 +575,7 @@ class Messages implements threema.Container.Messages {
     /**
      * Update a thumbnail of a message, if a message was found the method will return true
      */
-    public setThumbnail(receiver: threema.Receiver, messageId: string, thumbnailImage: string): boolean {
+    public setThumbnail(receiver: threema.BaseReceiver, messageId: string, thumbnailImage: string): boolean {
         const list = this.getList(receiver);
         for (const message of list) {
             if (message.id === messageId) {
@@ -597,7 +597,7 @@ class Messages implements threema.Container.Messages {
      * Return a boolean indicating whether the message was found and
      * removed, or not.
      */
-    public remove(receiver: threema.Receiver, messageId: string): boolean {
+    public remove(receiver: threema.BaseReceiver, messageId: string): boolean {
         const list = this.getList(receiver);
         for (let i = 0; i < list.length; i++) {
             if (list[i].id === messageId) {
@@ -613,7 +613,7 @@ class Messages implements threema.Container.Messages {
      * Return a boolean indicating whether the message was found and
      * removed, or not.
      */
-    public removeTemporary(receiver: threema.Receiver, temporaryMessageId: string): boolean {
+    public removeTemporary(receiver: threema.BaseReceiver, temporaryMessageId: string): boolean {
         const list = this.getList(receiver);
         for (let i = 0; i < list.length; i++) {
             if (list[i].temporaryId === temporaryMessageId) {
@@ -624,7 +624,7 @@ class Messages implements threema.Container.Messages {
         return false;
     }
 
-    public bindTemporaryToMessageId(receiver: threema.Receiver, temporaryId: string, messageId: string): boolean {
+    public bindTemporaryToMessageId(receiver: threema.BaseReceiver, temporaryId: string, messageId: string): boolean {
         const list = this.getList(receiver);
         for (const item of list) {
             if (item.temporaryId === temporaryId) {
@@ -644,7 +644,7 @@ class Messages implements threema.Container.Messages {
         return false;
     }
 
-    public notify(receiver: threema.Receiver, $scope: ng.IScope) {
+    public notify(receiver: threema.BaseReceiver, $scope: ng.IScope) {
         $scope.$broadcast('threema.receiver.' + receiver.type + '.' + receiver.id + '.messages',
             this.getList(receiver), this.hasMore(receiver));
     }
@@ -653,12 +653,16 @@ class Messages implements threema.Container.Messages {
      * register a message change notify on the given scope
      * return the CURRENT list of loaded messages
      */
-    public register(receiver: threema.Receiver, $scope: ng.IScope, callback: any): threema.Message[] {
+    public register(receiver: threema.BaseReceiver, $scope: ng.IScope, callback: any): threema.Message[] {
         $scope.$on('threema.receiver.' + receiver.type + '.' + receiver.id + '.messages', callback);
         return this.getList(receiver);
     }
 
-    public updateFirstUnreadMessage(receiver: threema.Receiver): void {
+    /**
+     * Iterate through the list of messages. Remove all "firstUnreadMessage"
+     * entries and insert a new entry just before the oldest unread message.
+     */
+    public updateFirstUnreadMessage(receiver: threema.BaseReceiver): void {
         const receiverMessages = this.getReceiverMessages(receiver);
         if (receiverMessages !== undefined && receiverMessages.list.length > 0) {
             // remove unread

+ 16 - 0
src/typeguards.ts

@@ -45,3 +45,19 @@ export function isDistributionListReceiver(
 ): receiver is threema.DistributionListReceiver {
     return receiver.type === 'distributionList';
 }
+
+/**
+ * Valid receiver types type guard
+ */
+export function isValidReceiverType(
+    receiverType: string,
+): receiverType is threema.ReceiverType {
+    switch (receiverType) {
+        case 'me':
+        case 'contact':
+        case 'group':
+        case 'distributionList':
+            return true;
+    }
+    return false;
+}