diff --git a/preload.js b/preload.js
index f43747571..9ede62bd2 100644
--- a/preload.js
+++ b/preload.js
@@ -3,6 +3,8 @@ const { Storage } = require('./ts/util/storage');
const url = require('url');
+const _ = require('lodash');
+
const config = url.parse(window.location.toString(), true).query;
const configAny = config;
@@ -29,6 +31,7 @@ window.sessionFeatureFlags = {
useTestNet: Boolean(
process.env.NODE_APP_INSTANCE && process.env.NODE_APP_INSTANCE.includes('testnet')
),
+ useDebugLogging: !_.isEmpty(process.env.SESSION_DEBUG),
useClosedGroupV3: false || process.env.USE_CLOSED_GROUP_V3,
useSharedUtilForUserConfig: true,
debug: {
@@ -234,6 +237,7 @@ const { setupi18n } = require('./ts/util/i18n');
window.Signal = data.initData();
const { getConversationController } = require('./ts/session/conversations/ConversationController');
+const { isEmpty } = require('lodash');
window.getConversationController = getConversationController;
// Linux seems to periodically let the event loop stop, so this is a global workaround
setInterval(() => {
diff --git a/ts/components/conversation/message/message-content/OutgoingMessageStatus.tsx b/ts/components/conversation/message/message-content/OutgoingMessageStatus.tsx
index f0d0c847d..c71d4097e 100644
--- a/ts/components/conversation/message/message-content/OutgoingMessageStatus.tsx
+++ b/ts/components/conversation/message/message-content/OutgoingMessageStatus.tsx
@@ -1,7 +1,7 @@
import { ipcRenderer } from 'electron';
import React from 'react';
import styled from 'styled-components';
-import { MessageDeliveryStatus } from '../../../../models/messageType';
+import { LastMessageStatusType } from '../../../../state/ducks/conversations';
import { SessionIcon } from '../../../icon';
const MessageStatusSendingContainer = styled.div`
@@ -56,7 +56,7 @@ const MessageStatusError = ({ dataTestId }: { dataTestId?: string }) => {
};
export const OutgoingMessageStatus = (props: {
- status?: MessageDeliveryStatus | null;
+ status: LastMessageStatusType | null;
dataTestId?: string;
}) => {
const { status, dataTestId } = props;
diff --git a/ts/components/conversation/message/message-item/MessageDetail.tsx b/ts/components/conversation/message/message-item/MessageDetail.tsx
index e88190cee..eb1f9b33c 100644
--- a/ts/components/conversation/message/message-item/MessageDetail.tsx
+++ b/ts/components/conversation/message/message-item/MessageDetail.tsx
@@ -62,14 +62,14 @@ const ContactItem = (props: { contact: ContactPropsMessageDetail }) => {
const { contact } = props;
const errors = contact.errors || [];
- const statusComponent = !contact.isOutgoingKeyError ? (
+ const statusComponent = (
- ) : null;
+ );
return (
diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts
index 6a8aa4c99..615b0c7d9 100644
--- a/ts/models/conversation.ts
+++ b/ts/models/conversation.ts
@@ -117,7 +117,6 @@ import {
type InMemoryConvoInfos = {
mentionedUs: boolean;
unreadCount: number;
- lastReadTimestampMessage: number | null;
};
// TODO decide it it makes sense to move this to a redux slice?
@@ -275,7 +274,7 @@ export class ConversationModel extends Backbone.Model
{
public getGroupAdmins(): Array {
const groupAdmins = this.get('groupAdmins');
- return groupAdmins && groupAdmins?.length > 0 ? groupAdmins : [];
+ return groupAdmins && groupAdmins.length > 0 ? groupAdmins : [];
}
// tslint:disable-next-line: cyclomatic-complexity max-func-body-length
@@ -291,8 +290,6 @@ export class ConversationModel extends Backbone.Model {
const weAreModerator = this.isModerator(ourNumber); // only used for sogs
const isMe = this.isMe();
const isTyping = !!this.typingTimer;
- // const unreadCount = this.get('unreadCount') || undefined;
- // const mentionedUs = this.get('mentionedUs') || undefined;
const isKickedFromGroup = !!this.get('isKickedFromGroup');
const left = !!this.get('left');
const currentNotificationSetting = this.get('triggerNotificationsFor');
@@ -337,7 +334,7 @@ export class ConversationModel extends Backbone.Model {
toRet.avatarPath = avatarPath;
}
- const foundContact = SessionUtilContact.getMappedValue(this.id);
+ const foundContact = SessionUtilContact.getContactCached(this.id);
const foundCommunity = SessionUtilUserGroups.getCommunityByConvoIdCached(this.id);
const foundLegacyGroup = SessionUtilUserGroups.getLegacyGroupCached(this.id);
const foundVolatileInfo = SessionUtilConvoInfoVolatile.getVolatileInfoCached(this.id);
@@ -498,13 +495,10 @@ export class ConversationModel extends Backbone.Model {
inMemoryConvoInfos.delete(this.id);
return;
}
- console.warn('memoryDetails', memoryDetails);
-
if (!inMemoryConvoInfos.get(this.id)) {
inMemoryConvoInfos.set(this.id, {
mentionedUs: false,
unreadCount: 0,
- lastReadTimestampMessage: null,
});
}
@@ -517,10 +511,7 @@ export class ConversationModel extends Backbone.Model {
existing.unreadCount = memoryDetails.unreadCount;
changes = true;
}
- if (existing.lastReadTimestampMessage !== memoryDetails.lastReadTimestampMessage) {
- existing.lastReadTimestampMessage = memoryDetails.lastReadTimestampMessage;
- changes = true;
- }
+
if (existing.mentionedUs !== memoryDetails.mentionedUs) {
existing.mentionedUs = memoryDetails.mentionedUs;
changes = true;
@@ -531,10 +522,6 @@ export class ConversationModel extends Backbone.Model {
}
}
- public getCachedLastReadTimestampMessage() {
- return inMemoryConvoInfos.get(this.id)?.lastReadTimestampMessage || null;
- }
-
public async queueJob(callback: () => Promise) {
// tslint:disable-next-line: no-promise-as-boolean
const previous = this.pending || Promise.resolve();
@@ -1855,8 +1842,8 @@ export class ConversationModel extends Backbone.Model {
return;
}
const lastMessageModel = messages.at(0);
- const lastMessageStatus = lastMessageModel?.getMessagePropStatus() || undefined;
- const lastMessageNotificationText = lastMessageModel?.getNotificationText() || undefined;
+ const lastMessageStatus = lastMessageModel.getMessagePropStatus() || undefined;
+ const lastMessageNotificationText = lastMessageModel.getNotificationText() || undefined;
// we just want to set the `status` to `undefined` if there are no `lastMessageNotificationText`
const lastMessageUpdate =
!!lastMessageNotificationText && !isEmpty(lastMessageNotificationText)
diff --git a/ts/models/message.ts b/ts/models/message.ts
index 995773848..a98522403 100644
--- a/ts/models/message.ts
+++ b/ts/models/message.ts
@@ -713,7 +713,7 @@ export class MessageModel extends Backbone.Model {
// We include numbers we didn't successfully send to so we can display errors.
// Older messages don't have the recipients included on the message, so we fall
// back to the conversation's current recipients
- const phoneNumbers: Array = this.isIncoming()
+ const contacts: Array = this.isIncoming()
? [this.get('source')]
: this.get('sent_to') || [];
@@ -727,30 +727,21 @@ export class MessageModel extends Backbone.Model {
const errors = reject(allErrors, error => Boolean(error.number));
const errorsGroupedById = groupBy(allErrors, 'number');
const finalContacts = await Promise.all(
- (phoneNumbers || []).map(async id => {
+ (contacts || []).map(async id => {
const errorsForContact = errorsGroupedById[id];
- const isOutgoingKeyError = false;
const contact = this.findAndFormatContact(id);
return {
...contact,
- // fallback to the message status if we do not have a status with a user
- // this is useful for medium groups.
- status: this.getStatus(id) || this.getMessagePropStatus(),
+ status: this.getMessagePropStatus(),
errors: errorsForContact,
- isOutgoingKeyError,
- isPrimaryDevice: true,
profileName: contact.profileName,
};
})
);
- // The prefix created here ensures that contacts with errors are listed
- // first; otherwise it's alphabetical
- const sortedContacts = sortBy(
- finalContacts,
- contact => `${contact.isPrimaryDevice ? '0' : '1'}${contact.pubkey}`
- );
+ // sort by pubkey
+ const sortedContacts = sortBy(finalContacts, contact => contact.pubkey);
const toRet: MessagePropsDetails = {
sentAt: this.get('sent_at') || 0,
@@ -1013,19 +1004,6 @@ export class MessageModel extends Backbone.Model {
return lodashSize(this.get('errors')) > 0;
}
- public getStatus(pubkey: string) {
- const readBy = this.get('read_by') || [];
- if (readBy.indexOf(pubkey) >= 0) {
- return 'read';
- }
- const sentTo = this.get('sent_to') || [];
- if (sentTo.indexOf(pubkey) >= 0) {
- return 'sent';
- }
-
- return null;
- }
-
public async updateMessageHash(messageHash: string) {
if (!messageHash) {
window?.log?.error('Message hash not provided to update message hash');
diff --git a/ts/models/messageType.ts b/ts/models/messageType.ts
index 3cc6b7d7d..6057ba5ca 100644
--- a/ts/models/messageType.ts
+++ b/ts/models/messageType.ts
@@ -1,11 +1,14 @@
import { defaultsDeep } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
-import { CallNotificationType, PropsForMessageWithConvoProps } from '../state/ducks/conversations';
+import {
+ CallNotificationType,
+ LastMessageStatusType,
+ PropsForMessageWithConvoProps,
+} from '../state/ducks/conversations';
import { AttachmentTypeWithPath } from '../types/Attachment';
import { Reaction, ReactionList, SortedReactionList } from '../types/Reaction';
export type MessageModelType = 'incoming' | 'outgoing';
-export type MessageDeliveryStatus = 'sending' | 'sent' | 'read' | 'error';
export interface MessageAttributes {
// the id of the message
@@ -48,7 +51,7 @@ export interface MessageAttributes {
* timestamp is the sent_at timestamp, which is the envelope.timestamp
*/
timestamp?: number;
- status?: MessageDeliveryStatus;
+ status?: LastMessageStatusType;
sent_to: Array;
sent: boolean;
@@ -196,7 +199,7 @@ export interface MessageAttributesOptionals {
unread?: number;
group?: any;
timestamp?: number;
- status?: MessageDeliveryStatus;
+ status?: LastMessageStatusType;
sent_to?: Array;
sent?: boolean;
serverId?: number;
diff --git a/ts/node/migration/sessionMigrations.ts b/ts/node/migration/sessionMigrations.ts
index cebd37d83..6a9ae8fcb 100644
--- a/ts/node/migration/sessionMigrations.ts
+++ b/ts/node/migration/sessionMigrations.ts
@@ -19,6 +19,7 @@ import {
CONVERSATIONS_TABLE,
dropFtsAndTriggers,
GUARD_NODE_TABLE,
+ jsonToObject,
LAST_HASHES_TABLE,
MESSAGES_TABLE,
NODES_FOR_PUBKEY_TABLE,
@@ -1486,11 +1487,16 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
* Setup up the User profile wrapper with what is stored in our own conversation
*/
- const ourConversation = sqlNode.getConversationById(publicKeyHex, db);
- if (!ourConversation) {
+ const ourConvoRow = db.prepare(`SELECT * FROM ${CONVERSATIONS_TABLE} WHERE id = $id;`).get({
+ id: publicKeyHex,
+ });
+
+ if (!ourConvoRow) {
throw new Error('Failed to find our logged in conversation while migrating');
}
+ const ourConversation = jsonToObject(ourConvoRow);
+
// Insert the user profile into the userWrappoer
const ourDbName = ourConversation.displayNameInProfile || '';
const ourDbProfileUrl = ourConversation.avatarPointer || '';
diff --git a/ts/receiver/configMessage.ts b/ts/receiver/configMessage.ts
index 0520a1a72..09944bd57 100644
--- a/ts/receiver/configMessage.ts
+++ b/ts/receiver/configMessage.ts
@@ -309,7 +309,7 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
const legacyGroupsToLeaveInDB = allLegacyGroupsInDb.filter(m => {
return !allLegacyGroupsIdsInWrapper.includes(m.id);
});
-
+ // TODO we need to store the encryption keypair if needed
window.log.info(
`we have to join ${legacyGroupsToJoinInDB.length} legacy groups in DB compared to what is in the wrapper`
);
@@ -456,6 +456,39 @@ async function handleUserGroupsUpdate(result: IncomingConfResult): Promise {
@@ -463,50 +496,71 @@ async function handleConvoInfoVolatileUpdate(
// if (!result.needsDump) {
// return result;
// }
- console.error('handleConvoInfoVolatileUpdate : TODO ');
const types = SessionUtilConvoInfoVolatile.getConvoInfoVolatileTypes();
for (let typeIndex = 0; typeIndex < types.length; typeIndex++) {
const type = types[typeIndex];
switch (type) {
case '1o1':
- // Note: "Note to Self" comes here too
- const privateChats = await ConvoInfoVolatileWrapperActions.getAll1o1();
- for (let index = 0; index < privateChats.length; index++) {
- const fromWrapper = privateChats[index];
- const foundConvo = getConversationController().get(fromWrapper.pubkeyHex);
- // TODO should we create the conversation if the conversation does not exist locally? Or assume that it should be coming from a contacts update?
- if (foundConvo) {
- console.warn(
- `fromWrapper from getAll1o1: ${fromWrapper.pubkeyHex}: ${fromWrapper.unread}`
+ try {
+ // Note: "Note to Self" comes here too
+ const wrapper1o1s = await ConvoInfoVolatileWrapperActions.getAll1o1();
+ for (let index = 0; index < wrapper1o1s.length; index++) {
+ const fromWrapper = wrapper1o1s[index];
+ await applyConvoVolatileUpdateFromWrapper(
+ fromWrapper.pubkeyHex,
+ fromWrapper.unread,
+ fromWrapper.lastRead
);
- // this should mark all the messages sent before fromWrapper.lastRead as read and update the unreadCount
- await foundConvo.markReadFromConfigMessage(fromWrapper.lastRead);
- // this commits to the DB, if needed
- await foundConvo.markAsUnread(fromWrapper.unread, true);
-
- if (SessionUtilConvoInfoVolatile.isConvoToStoreInWrapper(foundConvo)) {
- await SessionUtilConvoInfoVolatile.refreshConvoVolatileCached(
- foundConvo.id,
- foundConvo.isClosedGroup(),
- false
- );
-
- await foundConvo.refreshInMemoryDetails();
- }
}
+ } catch (e) {
+ window.log.warn('handleConvoInfoVolatileUpdate of "1o1" failed with error: ', e.message);
}
- console.warn('handleConvoInfoVolatileUpdate: privateChats', privateChats);
break;
case 'Community':
- const comms = await ConvoInfoVolatileWrapperActions.getAllCommunities();
- console.warn('handleConvoInfoVolatileUpdate: comms', comms);
+ try {
+ const wrapperComms = await ConvoInfoVolatileWrapperActions.getAllCommunities();
+ for (let index = 0; index < wrapperComms.length; index++) {
+ const fromWrapper = wrapperComms[index];
+
+ const convoId = getOpenGroupV2ConversationId(
+ fromWrapper.baseUrl,
+ fromWrapper.roomCasePreserved
+ );
+
+ await applyConvoVolatileUpdateFromWrapper(
+ convoId,
+ fromWrapper.unread,
+ fromWrapper.lastRead
+ );
+ }
+ } catch (e) {
+ window.log.warn(
+ 'handleConvoInfoVolatileUpdate of "Community" failed with error: ',
+ e.message
+ );
+ }
break;
case 'LegacyGroup':
- const legacyGroup = await ConvoInfoVolatileWrapperActions.getAllLegacyGroups();
- console.warn('handleConvoInfoVolatileUpdate: legacyGroup', legacyGroup);
+ try {
+ const legacyGroups = await ConvoInfoVolatileWrapperActions.getAllLegacyGroups();
+ for (let index = 0; index < legacyGroups.length; index++) {
+ const fromWrapper = legacyGroups[index];
+
+ await applyConvoVolatileUpdateFromWrapper(
+ fromWrapper.pubkeyHex,
+ fromWrapper.unread,
+ fromWrapper.lastRead
+ );
+ }
+ } catch (e) {
+ window.log.warn(
+ 'handleConvoInfoVolatileUpdate of "LegacyGroup" failed with error: ',
+ e.message
+ );
+ }
break;
default:
diff --git a/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts b/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts
index cb45e8788..4a5ad3c4a 100644
--- a/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts
+++ b/ts/session/apis/open_group_api/opengroupV2/OpenGroupServerPoller.ts
@@ -380,7 +380,6 @@ export const getRoomAndUpdateLastFetchTimestamp = async (
if (!newMessages.length) {
// if we got no new messages, just write our last update timestamp to the db
roomInfos.lastFetchTimestamp = Date.now();
- window?.log?.info();
await OpenGroupData.saveV2OpenGroupRoom(roomInfos);
return null;
}
diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts
index 70994c9e3..51cae1494 100644
--- a/ts/session/conversations/ConversationController.ts
+++ b/ts/session/conversations/ConversationController.ts
@@ -221,26 +221,28 @@ export class ConversationController {
// open group v2
} else if (conversation.isPublic()) {
window?.log?.info('leaving open group v2', conversation.id);
+ // remove from the wrapper the entries before we remove the roomInfos, as we won't have the required community pubkey afterwards
+ try {
+ await SessionUtilUserGroups.removeCommunityFromWrapper(conversation.id, conversation.id);
+ await SessionUtilConvoInfoVolatile.removeCommunityFromWrapper(
+ conversation.id,
+ conversation.id
+ );
+ } catch (e) {
+ window?.log?.info('SessionUtilUserGroups.removeCommunityFromWrapper failed:', e);
+ }
+
const roomInfos = OpenGroupData.getV2OpenGroupRoom(conversation.id);
if (roomInfos) {
getOpenGroupManager().removeRoomFromPolledRooms(roomInfos);
}
- // remove the roomInfos locally for this open group room
+ // remove the roomInfos locally for this open group room including the pubkey
try {
await OpenGroupData.removeV2OpenGroupRoom(conversation.id);
} catch (e) {
window?.log?.info('removeV2OpenGroupRoom failed:', e);
}
- try {
- await SessionUtilUserGroups.removeCommunityFromWrapper(conversation.id, conversation.id);
- await SessionUtilConvoInfoVolatile.removeCommunityFromWrapper(
- conversation.id,
- conversation.id
- );
- } catch (e) {
- window?.log?.info('SessionUtilUserGroups.removeCommunityFromWrapper failed:', e);
- }
} else if (conversation.isPrivate()) {
// if this conversation is a private conversation it's in fact a `contact` for desktop.
// we just want to remove everything related to it and set the hidden field to true
diff --git a/ts/session/utils/job_runners/jobs/ConfigurationSyncJob.ts b/ts/session/utils/job_runners/jobs/ConfigurationSyncJob.ts
index c3875c583..48d1f6494 100644
--- a/ts/session/utils/job_runners/jobs/ConfigurationSyncJob.ts
+++ b/ts/session/utils/job_runners/jobs/ConfigurationSyncJob.ts
@@ -130,11 +130,7 @@ async function buildAndSaveDumpsToDB(changes: Array): Promise<
for (let i = 0; i < changes.length; i++) {
const change = changes[i];
const variant = LibSessionUtil.kindToVariant(change.message.kind);
- console.warn(
- `ConfigurationSyncJob.saveDumpToDB: "${variant}" updatedHash: "${
- change.updatedHash
- }:${change.message.seqno.toNumber()}"`
- );
+
const needsDump = await LibSessionUtil.markAsPushed(
variant,
change.publicKey,
@@ -302,11 +298,13 @@ async function queueNewJobIfNeeded() {
await runners.configurationSyncRunner.addJob(
new ConfigurationSyncJob({ nextAttemptTimestamp: Date.now() })
);
+ window.log.debug('Scheduling ConfSyncJob: ASAP');
} else {
// if we did run at t=100, and it is currently t=110, diff is 10
const diff = Math.max(Date.now() - lastRunConfigSyncJobTimestamp, 0);
// but we want to run every 30, so what we need is actually `30-10` from now = 20
const leftBeforeNextTick = Math.max(defaultMsBetweenRetries - diff, 0);
+ window.log.debug('Scheduling ConfSyncJob: LATER');
// TODO we need to make the addJob wait for the previous addJob to be done before it can be called.
await runners.configurationSyncRunner.addJob(
diff --git a/ts/session/utils/libsession/libsession_utils.ts b/ts/session/utils/libsession/libsession_utils.ts
index cab6742bf..3d56f9212 100644
--- a/ts/session/utils/libsession/libsession_utils.ts
+++ b/ts/session/utils/libsession/libsession_utils.ts
@@ -112,6 +112,7 @@ async function pendingChangesForPubkey(pubkey: string): Promise;
};
@@ -60,7 +57,7 @@ export type MessagePropsDetails = {
direction: MessageModelType;
};
-export type LastMessageStatusType = MessageDeliveryStatus | undefined;
+export type LastMessageStatusType = 'sending' | 'sent' | 'read' | 'error' | undefined;
export type FindAndFormatContactType = {
pubkey: string;
diff --git a/ts/util/logging.ts b/ts/util/logging.ts
index 659a8495f..63a3ca016 100644
--- a/ts/util/logging.ts
+++ b/ts/util/logging.ts
@@ -110,6 +110,9 @@ const development = window && window?.getEnvironment && window?.getEnvironment()
// The Bunyan API: https://github.com/trentm/node-bunyan#log-method-api
function logAtLevel(level: string, prefix: string, ...args: any) {
+ if (prefix === 'DEBUG' && window.sessionFeatureFlags.useDebugLogging) {
+ return;
+ }
if (development) {
const fn = `_${level}`;
(console as any)[fn](prefix, now(), ...args);
diff --git a/ts/window.d.ts b/ts/window.d.ts
index 664e85c5f..a0bad52c3 100644
--- a/ts/window.d.ts
+++ b/ts/window.d.ts
@@ -43,6 +43,7 @@ declare global {
debugNonSnodeRequests: boolean;
debugOnionRequests: boolean;
};
+ useDebugLogging: boolean;
};
SessionSnodeAPI: SessionSnodeAPI;
onLogin: (pw: string) => Promise;