@@ -50,7 +54,7 @@ export const SearchResults = (props: SearchResultsProps) => {
) : null}
- {/* {haveMessages ? (
+ {haveMessages ? (
{hideMessagesHeader ? null : (
@@ -61,7 +65,7 @@ export const SearchResults = (props: SearchResultsProps) => {
))}
- ) : null} */}
+ ) : null}
);
};
diff --git a/ts/components/settings/section/CategoryAppearance.tsx b/ts/components/settings/section/CategoryAppearance.tsx
index c21ef9161..81d6e34e0 100644
--- a/ts/components/settings/section/CategoryAppearance.tsx
+++ b/ts/components/settings/section/CategoryAppearance.tsx
@@ -3,7 +3,15 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
// tslint:disable-next-line: no-submodule-imports
import useUpdate from 'react-use/lib/useUpdate';
-import { createOrUpdateItem, hasLinkPreviewPopupBeenDisplayed } from '../../../data/data';
+import {
+ createOrUpdateItem,
+ fillWithTestData,
+ fillWithTestData2,
+ // fillWithTestData2,
+ getMessageCount,
+ hasLinkPreviewPopupBeenDisplayed,
+ trimMessages,
+} from '../../../data/data';
import { ToastUtils } from '../../../session/utils';
import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { toggleAudioAutoplay } from '../../../state/ducks/userConfig';
@@ -131,6 +139,30 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null
buttonColor={SessionButtonColor.Primary}
buttonText={window.i18n('translation')}
/>
+
{
+ console.warn('trim the database to last 10k messages');
+
+ const msgCount = await getMessageCount();
+ const deleteAmount = Math.max(msgCount - 10000, 0);
+
+ dispatch(
+ updateConfirmModal({
+ onClickOk: () => {
+ void trimMessages();
+ },
+ onClickClose: () => {
+ updateConfirmModal(null);
+ },
+ message: `Are you sure you want to delete your ${deleteAmount} oldest received messages?`,
+ })
+ );
+ }}
+ buttonColor={SessionButtonColor.Primary}
+ buttonText={window.i18n('trimDatabase')}
+ />
{
ipcRenderer.send('show-debug-log');
@@ -138,6 +170,20 @@ export const SettingsCategoryAppearance = (props: { hasPassword: boolean | null
buttonColor={SessionButtonColor.Primary}
buttonText={window.i18n('showDebugLog')}
/>
+ {
+ fillWithTestData(100, 2000000);
+ }}
+ buttonColor={SessionButtonColor.Primary}
+ buttonText={'Spam fill DB'}
+ />
+ {
+ fillWithTestData2(100, 1000);
+ }}
+ buttonColor={SessionButtonColor.Primary}
+ buttonText={'Spam fill DB using cached'}
+ />
>
);
}
diff --git a/ts/data/data.ts b/ts/data/data.ts
index e5cc48e59..2e7c76825 100644
--- a/ts/data/data.ts
+++ b/ts/data/data.ts
@@ -3,10 +3,15 @@ import { ipcRenderer } from 'electron';
// tslint:disable: no-require-imports no-var-requires one-variable-per-declaration no-void-expression
import _ from 'lodash';
-import { ConversationCollection, ConversationModel } from '../models/conversation';
+import {
+ ConversationCollection,
+ ConversationModel,
+ ConversationTypeEnum,
+} from '../models/conversation';
import { MessageCollection, MessageModel } from '../models/message';
-import { MessageAttributes } from '../models/messageType';
+import { MessageAttributes, MessageDirection } from '../models/messageType';
import { HexKeyPair } from '../receiver/keypairs';
+import { getConversationController } from '../session/conversations';
import { getSodium } from '../session/crypto';
import { PubKey } from '../session/types';
import { fromArrayBufferToBase64, fromBase64ToArrayBuffer } from '../session/utils/String';
@@ -109,6 +114,7 @@ const channelsToMake = {
removeAllMessagesInConversation,
+ getMessageCount,
getMessageBySender,
getMessageBySenderAndServerTimestamp,
getMessageBySenderAndTimestamp,
@@ -123,6 +129,7 @@ const channelsToMake = {
hasConversationOutgoingMessage,
getSeenMessagesByHashList,
getLastHashBySnode,
+ trimMessages,
getUnprocessedCount,
getAllUnprocessed,
@@ -156,6 +163,9 @@ const channelsToMake = {
removeAllClosedGroupEncryptionKeyPairs,
removeOneOpenGroupV1Message,
+ // dev performance testing
+ fillWithTestData,
+
// open group v2
...channelstoMakeOpenGroupV2,
};
@@ -191,8 +201,12 @@ export function init() {
});
}
-// When IPC arguments are prepared for the cross-process send, they are JSON.stringified.
-// We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates).
+/**
+ * When IPC arguments are prepared for the cross-process send, they are JSON.stringified.
+ * We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates).
+ * @param data
+ * @returns
+ */
function _cleanData(data: any): any {
const keys = Object.keys(data);
@@ -758,6 +772,13 @@ export async function getMessagesByConversation(
return new MessageCollection(messages);
}
+/**
+ * @returns Returns count of all messages in the database
+ */
+export async function getMessageCount() {
+ return await channels.getMessageCount();
+}
+
export async function getFirstUnreadMessageIdInConversation(
conversationId: string
): Promise {
@@ -801,6 +822,12 @@ export async function removeAllMessagesInConversation(conversationId: string): P
} while (messages.length > 0);
}
+export async function trimMessages(): Promise {
+ const count = await channels.trimMessages();
+ console.warn({ count });
+ return;
+}
+
export async function getMessagesBySentAt(sentAt: number): Promise {
const messages = await channels.getMessagesBySentAt(sentAt);
return new MessageCollection(messages);
@@ -964,3 +991,49 @@ export async function updateSnodePoolOnDb(snodesAsJsonString: string): Promise {
return channels.removeOneOpenGroupV1Message();
}
+
+/**
+ * Generates fake conversations and distributes messages amongst the conversations randomly
+ * @param numConvosToAdd Amount of fake conversations to generate
+ * @param numMsgsToAdd Number of fake messages to generate
+ */
+export async function fillWithTestData(
+ numConvosToAdd: number,
+ numMsgsToAdd: number
+): Promise {
+ if (!channels.fillWithTestData) {
+ return;
+ }
+ const ids = await channels.fillWithTestData(numConvosToAdd, numMsgsToAdd);
+ ids.map(async (id: string) => {
+ const convo = getConversationController().get(id);
+ const convoMsg = 'x';
+ convo.set('lastMessage', convoMsg);
+ });
+}
+
+export const fillWithTestData2 = async (convs: number, msgs: number) => {
+ const newConvos = [];
+ for (let convsAddedCount = 0; convsAddedCount < convs; convsAddedCount++) {
+ const convoId = Date.now() + convsAddedCount + '';
+ const newConvo = await getConversationController().getOrCreateAndWait(
+ convoId,
+ ConversationTypeEnum.PRIVATE
+ );
+ newConvos.push(newConvo);
+ }
+
+ for (let msgsAddedCount = 0; msgsAddedCount < msgs; msgsAddedCount++) {
+ if (msgsAddedCount % 100 == 0) {
+ console.warn(msgsAddedCount);
+ }
+ const convoToChoose = newConvos[Math.floor(Math.random() * newConvos.length)];
+ convoToChoose.addSingleMessage({
+ source: convoToChoose.id,
+ type: MessageDirection.outgoing,
+ conversationId: convoToChoose.id,
+ body: 'spongebob ' + new Date().toString(),
+ direction: Math.random() > 0.5 ? 'outgoing' : 'incoming',
+ });
+ }
+};
diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts
index b2455de9b..bf79517ec 100644
--- a/ts/models/messageType.ts
+++ b/ts/models/messageType.ts
@@ -118,6 +118,11 @@ export interface DataExtractionNotificationMsg {
referencedAttachmentTimestamp: number; // the attachment timestamp he screenshot
}
+export enum MessageDirection {
+ outgoing = 'outgoing',
+ incoming = 'incoming',
+}
+
export type PropsForDataExtractionNotification = DataExtractionNotificationMsg & {
name: string;
messageId: string;
diff --git a/ts/state/ducks/search.ts b/ts/state/ducks/search.ts
index 38ab06d4d..7a48f859b 100644
--- a/ts/state/ducks/search.ts
+++ b/ts/state/ducks/search.ts
@@ -16,6 +16,10 @@ export type SearchStateType = {
// For conversations we store just the id, and pull conversation props in the selector
conversations: Array;
contacts: Array;
+
+ // TODO: ww typing
+ messages?: Array;
+ messagesLookup?: any;
};
// Actions
@@ -24,6 +28,9 @@ type SearchResultsPayloadType = {
normalizedPhoneNumber?: string;
conversations: Array;
contacts: Array;
+
+ // TODO: ww typing
+ messages?: Array;
};
type SearchResultsKickoffActionType = {
@@ -94,6 +101,7 @@ async function doSearch(query: string, options: SearchOptions): Promise
});
export const getSearchResults = createSelector(
- [getSearch, getConversationLookup, getSelectedConversationKey],
- (state: SearchStateType, lookup: ConversationLookupType, selectedConversation?: string) => {
+ [getSearch, getConversationLookup, getSelectedConversationKey, getSelectedMessage],
+ (
+ searchState: SearchStateType,
+ lookup: ConversationLookupType,
+ selectedConversation?: string,
+ selectedMessage?: string
+ ) => {
+ console.warn({ state: searchState });
return {
contacts: compact(
- state.contacts.map(id => {
+ searchState.contacts.map(id => {
const value = lookup[id];
if (value && id === selectedConversation) {
@@ -41,7 +47,7 @@ export const getSearchResults = createSelector(
})
),
conversations: compact(
- state.conversations.map(id => {
+ searchState.conversations.map(id => {
const value = lookup[id];
// Don't return anything when activeAt is unset (i.e. no current conversations with this user)
@@ -60,9 +66,21 @@ export const getSearchResults = createSelector(
return value;
})
),
+ messages: compact(
+ searchState.messages?.map(message => {
+ if (message.id === selectedMessage) {
+ return {
+ ...message,
+ isSelected: true,
+ };
+ }
+
+ return message;
+ })
+ ),
hideMessagesHeader: false,
- searchTerm: state.query,
+ searchTerm: searchState.query,
};
}
);
diff --git a/ts/types/LocalizerKeys.ts b/ts/types/LocalizerKeys.ts
index 18945b0c3..218956f2a 100644
--- a/ts/types/LocalizerKeys.ts
+++ b/ts/types/LocalizerKeys.ts
@@ -460,4 +460,6 @@ export type LocalizerKeys =
| 'searchFor...'
| 'joinedTheGroup'
| 'editGroupName'
+ | 'trimDatabase'
+ | 'trimDatabaseDescription'
| 'reportIssue';