fix: run tests for libsession-util integration and fix issue

This commit is contained in:
Audric Ackermann 2023-04-21 15:17:24 +10:00
parent faea0501bb
commit cbffc29950
24 changed files with 181 additions and 99 deletions

View file

@ -3,16 +3,15 @@ import React from 'react';
import { useSelector } from 'react-redux';
import styled from 'styled-components';
import { SectionType } from '../../state/ducks/section';
import { SessionTheme } from '../../themes/SessionTheme';
import { getLeftPaneLists } from '../../state/selectors/conversations';
import { getSearchResults, isSearching } from '../../state/selectors/search';
import { getFocusedSection, getOverlayMode } from '../../state/selectors/section';
import { getHideMessageRequestBanner } from '../../state/selectors/userConfig';
import { SessionTheme } from '../../themes/SessionTheme';
import { SessionToastContainer } from '../SessionToastContainer';
import { CallInFullScreenContainer } from '../calling/CallInFullScreenContainer';
import { DraggableCallContainer } from '../calling/DraggableCallContainer';
import { IncomingCallDialog } from '../calling/IncomingCallDialog';
import { ModalContainer } from '../dialog/ModalContainer';
import { SessionToastContainer } from '../SessionToastContainer';
import { ActionsPanel } from './ActionsPanel';
import { LeftPaneMessageSection } from './LeftPaneMessageSection';
import { LeftPaneSettingSection } from './LeftPaneSettingSection';
@ -28,7 +27,6 @@ const InnerLeftPaneMessageSection = () => {
const searchResults = showSearch ? useSelector(getSearchResults) : undefined;
const lists = showSearch ? undefined : useSelector(getLeftPaneLists);
const messageRequestsEnabled = useSelector(getHideMessageRequestBanner);
const overlayMode = useSelector(getOverlayMode);
return (
@ -37,7 +35,6 @@ const InnerLeftPaneMessageSection = () => {
conversations={lists?.conversations || []}
contacts={lists?.contacts || []}
searchResults={searchResults}
messageRequestsEnabled={messageRequestsEnabled}
overlayMode={overlayMode}
/>
);

View file

@ -27,8 +27,6 @@ export interface Props {
contacts: Array<ReduxConversationType>;
conversations?: Array<ConversationListItemProps>;
searchResults?: SearchResultsProps;
messageRequestsEnabled?: boolean;
overlayMode: OverlayMode | undefined;
}
@ -70,7 +68,6 @@ const ClosableOverlay = () => {
export class LeftPaneMessageSection extends React.Component<Props> {
public constructor(props: Props) {
super(props);
autoBind(this);
}

View file

@ -7,6 +7,7 @@ import { getUnreadConversationRequests } from '../../state/selectors/conversatio
import { getHideMessageRequestBanner } from '../../state/selectors/userConfig';
import { SessionIcon, SessionIconSize, SessionIconType } from '../icon';
import { MessageRequestBannerContextMenu } from '../menu/MessageRequestBannerContextMenu';
import { isSearching } from '../../state/selectors/search';
const StyledMessageRequestBanner = styled.div`
height: 64px;
@ -87,7 +88,10 @@ export const MessageRequestsBanner = (props: { handleOnClick: () => any }) => {
const conversationRequestsUnread = useSelector(getUnreadConversationRequests).length;
const hideRequestBanner = useSelector(getHideMessageRequestBanner);
if (!conversationRequestsUnread || hideRequestBanner) {
// when searching hide the message request banner
const isCurrentlySearching = useSelector(isSearching);
if (!conversationRequestsUnread || hideRequestBanner || isCurrentlySearching) {
return null;
}

View file

@ -61,7 +61,7 @@ const SessionJoinableRoomAvatar = (props: JoinableRoomProps) => {
});
}
} catch (e) {
window?.log?.warn(e);
window?.log?.warn(e.message);
}
return () => {
isCancelled = true;

View file

@ -41,12 +41,10 @@ import {
updateUserDetailsModal,
} from '../../state/ducks/modalDialog';
import { getIsMessageSection } from '../../state/selectors/section';
import {
useSelectedConversationKey,
useSelectedIsPrivateFriend,
} from '../../state/selectors/selectedConversation';
import { useSelectedConversationKey } from '../../state/selectors/selectedConversation';
import { SessionButtonColor } from '../basic/SessionButton';
import { useConvoIdFromContext } from '../leftpane/conversation-list-item/ConvoIdContext';
import { PubKey } from '../../session/types';
function showDeleteContact(
isGroup: boolean,
@ -339,7 +337,7 @@ export const CopyMenuItem = (): JSX.Element | null => {
export const MarkAllReadMenuItem = (): JSX.Element | null => {
const convoId = useConvoIdFromContext();
const isIncomingRequest = useIsIncomingRequest(convoId);
if (!isIncomingRequest) {
if (!isIncomingRequest && !PubKey.hasBlindedPrefix(convoId)) {
return (
<Item onClick={() => markAllReadByConvoId(convoId)}>{window.i18n('markAllAsRead')}</Item>
);
@ -361,7 +359,7 @@ export const BlockMenuItem = (): JSX.Element | null => {
const isPrivate = useIsPrivate(convoId);
const isIncomingRequest = useIsIncomingRequest(convoId);
if (!isMe && isPrivate && !isIncomingRequest) {
if (!isMe && isPrivate && !isIncomingRequest && !PubKey.hasBlindedPrefix(convoId)) {
const blockTitle = isBlocked ? window.i18n('unblock') : window.i18n('block');
const blockHandler = isBlocked
? () => unblockConvoById(convoId)
@ -391,7 +389,7 @@ export const ChangeNicknameMenuItem = () => {
const convoId = useConvoIdFromContext();
const isMe = useIsMe(convoId);
const isPrivate = useIsPrivate(convoId);
const isPrivateAndFriend = useSelectedIsPrivateFriend();
const isPrivateAndFriend = useIsPrivateAndFriend(convoId);
const dispatch = useDispatch();
if (isMe || !isPrivate || !isPrivateAndFriend) {

View file

@ -105,7 +105,7 @@ export const approveConvoAndSendResponse = async (
) => {
const convoToApprove = getConversationController().get(conversationId);
if (!convoToApprove || convoToApprove.isApproved()) {
if (!convoToApprove) {
window?.log?.info('Conversation is already approved.');
return;
}
@ -134,8 +134,8 @@ export async function declineConversationWithoutConfirm({
}) {
const conversationToDecline = getConversationController().get(conversationId);
if (!conversationToDecline || !conversationToDecline.isApproved()) {
window?.log?.info('Conversation is already declined.');
if (!conversationToDecline || !conversationToDecline.isPrivate()) {
window?.log?.info('No conversation to decline.');
return;
}

View file

@ -19,7 +19,7 @@ export function banUser(userToBan: string, conversationId: string) {
try {
pubKeyToBan = PubKey.cast(userToBan);
} catch (e) {
window?.log?.warn(e);
window?.log?.warn(e.message);
ToastUtils.pushUserBanFailure();
return;
}
@ -44,7 +44,7 @@ export function unbanUser(userToUnBan: string, conversationId: string) {
try {
pubKeyToUnban = PubKey.cast(userToUnBan);
} catch (e) {
window?.log?.warn(e);
window?.log?.warn(e.message);
ToastUtils.pushUserBanFailure();
return;
}

View file

@ -982,11 +982,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
}
}
// TODOLATER we should maybe mark things here as read, but we need a readAt timestamp, and I am not too sure what we should use (considering that disappearing messages needs a real readAt)
// const sentAt = messageAttributes.sent_at || messageAttributes.serverTimestamp;
// if (sentAt) {
// await this.markConversationRead(sentAt);
// }
return this.addSingleMessage({
...messageAttributes,
conversationId: this.id,

View file

@ -1,11 +1,11 @@
import * as BetterSqlite3 from 'better-sqlite3';
import { compact, isArray, isEmpty, isNumber, isString, map, pick } from 'lodash';
import {
ContactsConfigWrapperInsideWorker,
ConvoInfoVolatileWrapperInsideWorker,
UserConfigWrapperInsideWorker,
UserGroupsWrapperInsideWorker,
} from 'libsession_util_nodejs';
import { compact, isArray, isEmpty, isNumber, isString, map, pick } from 'lodash';
import {
CONVERSATION_PRIORITIES,
ConversationAttributes,
@ -21,13 +21,13 @@ import {
import {
CLOSED_GROUP_V2_KEY_PAIRS_TABLE,
CONVERSATIONS_TABLE,
dropFtsAndTriggers,
GUARD_NODE_TABLE,
LAST_HASHES_TABLE,
MESSAGES_TABLE,
NODES_FOR_PUBKEY_TABLE,
objectToJSON,
OPEN_GROUP_ROOMS_V2_TABLE,
dropFtsAndTriggers,
objectToJSON,
rebuildFtsTable,
toSqliteBoolean,
} from '../database_utility';
@ -1572,13 +1572,23 @@ function updateToSessionSchemaVersion30(currentVersion: number, db: BetterSqlite
const ourDbName = ourConversation.displayNameInProfile || '';
const ourDbProfileUrl = ourConversation.avatarPointer || '';
const ourDbProfileKey = fromHexToArray(ourConversation.profileKey || '');
userProfileWrapper.setName(ourDbName);
const ourConvoPriority = ourConversation.priority;
if (ourDbProfileUrl && !isEmpty(ourDbProfileKey)) {
userProfileWrapper.setProfilePicture(ourDbProfileUrl, ourDbProfileKey);
userProfileWrapper.setUserInfo(
ourDbName,
ourConvoPriority,
ourDbProfileUrl || '',
ourDbProfileKey
);
} else {
userProfileWrapper.setProfilePicture('', new Uint8Array());
userProfileWrapper.setUserInfo(
ourDbName,
ourConvoPriority, // consider that the Note to self is hidden on a fresh account (without avatar set)
'',
new Uint8Array()
);
}
insertContactIntoContactWrapper(
ourConversation,
blockedNumbers,

View file

@ -1,4 +1,4 @@
import _, { compact, isEmpty, toNumber } from 'lodash';
import { compact, isEmpty, toNumber } from 'lodash';
import { ConfigDumpData } from '../data/configDump/configDump';
import { Data, hasSyncedInitialConfigurationItem } from '../data/data';
import { ConversationInteraction } from '../interactions';
@ -12,15 +12,17 @@ import {
import { getOpenGroupManager } from '../session/apis/open_group_api/opengroupV2/OpenGroupManagerV2';
import { OpenGroupUtils } from '../session/apis/open_group_api/utils';
import { getOpenGroupV2ConversationId } from '../session/apis/open_group_api/utils/OpenGroupUtils';
import { getSwarmPollingInstance } from '../session/apis/snode_api';
import { getConversationController } from '../session/conversations';
import { IncomingMessage } from '../session/messages/incoming/IncomingMessage';
import { ProfileManager } from '../session/profile_manager/ProfileManager';
import { PubKey } from '../session/types';
import { UserUtils } from '../session/utils';
import { toHex } from '../session/utils/String';
import { ConfigurationSync } from '../session/utils/job_runners/jobs/ConfigurationSyncJob';
import { IncomingConfResult, LibSessionUtil } from '../session/utils/libsession/libsession_utils';
import { SessionUtilConvoInfoVolatile } from '../session/utils/libsession/libsession_utils_convo_info_volatile';
import { SessionUtilUserGroups } from '../session/utils/libsession/libsession_utils_user_groups';
import { toHex } from '../session/utils/String';
import { configurationMessageReceived, trigger } from '../shims/events';
import { assertUnreachable } from '../types/sqlSharedTypes';
import { BlockedNumberController } from '../util';
@ -37,6 +39,7 @@ import {
import { removeFromCache } from './cache';
import { addKeyPairToCacheAndDBIfNeeded, handleNewClosedGroup } from './closedGroups';
import { HexKeyPair } from './keypairs';
import { queueAllCachedFromSource } from './receiver';
import { EnvelopePlus } from './types';
function groupByVariant(
@ -89,7 +92,7 @@ async function mergeConfigsWithIncomingUpdates(
const needsDump = await GenericWrapperActions.needsDump(variant);
const latestEnvelopeTimestamp = Math.max(...sameVariant.map(m => m.envelopeTimestamp));
window.log.info(`${variant}: "${publicKey}" needsPush:${needsPush} needsDump:${needsDump} `);
window.log.debug(`${variant}: "${publicKey}" needsPush:${needsPush} needsDump:${needsDump} `);
const incomingConfResult: IncomingConfResult = {
needsDump,
@ -109,20 +112,23 @@ async function mergeConfigsWithIncomingUpdates(
}
async function handleUserProfileUpdate(result: IncomingConfResult): Promise<IncomingConfResult> {
const updatedUserName = await UserConfigWrapperActions.getName();
if (!result.needsDump) {
return result;
}
const updatedProfilePicture = await UserConfigWrapperActions.getProfilePicture();
const picUpdate = !isEmpty(updatedProfilePicture.key) && !isEmpty(updatedProfilePicture.url);
const updateUserInfo = await UserConfigWrapperActions.getUserInfo();
if (!updateUserInfo) {
return result;
}
const picUpdate = !isEmpty(updateUserInfo.key) && !isEmpty(updateUserInfo.url);
await updateOurProfileLegacyOrViaLibSession(
result.latestEnvelopeTimestamp,
updatedUserName,
picUpdate ? updatedProfilePicture.url : null,
picUpdate ? updatedProfilePicture.key : null
updateUserInfo.name,
picUpdate ? updateUserInfo.url : null,
picUpdate ? updateUserInfo.key : null,
updateUserInfo.priority
);
return result;
}
@ -205,11 +211,16 @@ async function handleCommunitiesUpdate() {
// first let's check which communities needs to be joined or left by doing a diff of what is in the wrapper and what is in the DB
const allCommunitiesInWrapper = await UserGroupsWrapperActions.getAllCommunities();
window.log.debug(
'allCommunitiesInWrapper',
allCommunitiesInWrapper.map(m => m.fullUrl)
);
const allCommunitiesConversation = getConversationController()
.getConversations()
.filter(SessionUtilUserGroups.isCommunityToStoreInWrapper);
const allCommunitiesIdsInDB = allCommunitiesConversation.map(m => m.id as string);
window.log.debug('allCommunitiesIdsInDB', allCommunitiesIdsInDB);
const communitiesIdsInWrapper = compact(
allCommunitiesInWrapper.map(m => {
@ -291,7 +302,7 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
const allLegacyGroupsInWrapper = await UserGroupsWrapperActions.getAllLegacyGroups();
const allLegacyGroupsInDb = getConversationController()
.getConversations()
.filter(SessionUtilUserGroups.isLegacyGroupToStoreInWrapper);
.filter(SessionUtilUserGroups.isLegacyGroupToRemoveFromDBIfNotInWrapper);
const allLegacyGroupsIdsInDB = allLegacyGroupsInDb.map(m => m.id as string);
const allLegacyGroupsIdsInWrapper = allLegacyGroupsInWrapper.map(m => m.pubkeyHex);
@ -300,6 +311,9 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
return !allLegacyGroupsIdsInDB.includes(m.pubkeyHex);
});
window.log.debug(`allLegacyGroupsInWrapper: ${allLegacyGroupsInWrapper.map(m => m.pubkeyHex)} `);
window.log.debug(`allLegacyGroupsIdsInDB: ${allLegacyGroupsIdsInDB} `);
const legacyGroupsToLeaveInDB = allLegacyGroupsInDb.filter(m => {
return !allLegacyGroupsIdsInWrapper.includes(m.id);
});
@ -385,6 +399,11 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
);
changes = true;
}
// start polling for this new group
getSwarmPollingInstance().addGroupId(PubKey.cast(fromWrapper.pubkeyHex));
// trigger decrypting of all this group messages we did not decrypt successfully yet.
await queueAllCachedFromSource(fromWrapper.pubkeyHex);
if (changes) {
await legacyGroupConvo.commit();
@ -578,6 +597,7 @@ async function processMergingResults(results: Map<ConfigWrapperObjectTypes, Inco
break;
default:
try {
// we catch errors here because an old client knowing about a new type of config coming from the network should not just crash
assertUnreachable(kind, `processMergingResults unsupported kind: "${kind}"`);
} catch (e) {
window.log.warn('assertUnreachable failed', e.message);
@ -623,7 +643,7 @@ async function handleConfigMessagesViaLibSession(
}
window?.log?.info(
`Handling our sharedConfig message via libsession_util: ${configMessages.length}`
`Handling our sharedConfig message via libsession_util; count: ${configMessages.length}`
);
const incomingMergeResult = await mergeConfigsWithIncomingUpdates(configMessages);
@ -635,9 +655,10 @@ async function updateOurProfileLegacyOrViaLibSession(
sentAt: number,
displayName: string,
profileUrl: string | null,
profileKey: Uint8Array | null
profileKey: Uint8Array | null,
priority: number | null // passing null means to not update the priority at all (used for legacy config message for now)
) {
await ProfileManager.updateOurProfileSync(displayName, profileUrl, profileKey);
await ProfileManager.updateOurProfileSync(displayName, profileUrl, profileKey, priority);
await setLastProfileUpdateTimestamp(toNumber(sentAt));
// do not trigger a signin by linking if the display name is empty
@ -667,7 +688,8 @@ async function handleOurProfileUpdateLegacy(
toNumber(sentAt),
displayName,
profilePicture,
profileKey
profileKey,
null // passing null to say do not the prioroti, as we do not get one from the legacy config message
);
}
}

View file

@ -44,7 +44,7 @@ export async function handleSwarmContentMessage(envelope: EnvelopePlus, messageH
// the sogs messages do not come as milliseconds but just seconds, so we override it
await innerHandleSwarmContentMessage(envelope, sentAtTimestamp, plaintext, messageHash);
} catch (e) {
window?.log?.warn(e);
window?.log?.warn(e.message);
}
}
@ -466,7 +466,7 @@ export async function innerHandleSwarmContentMessage(
);
}
} catch (e) {
window?.log?.warn(e);
window?.log?.warn(e.message);
}
}

View file

@ -6,10 +6,10 @@ import {
import { SignalService } from '../protobuf';
import { OpenGroupRequestCommonType } from '../session/apis/open_group_api/opengroupV2/ApiUtil';
import { OpenGroupMessageV4 } from '../session/apis/open_group_api/opengroupV2/OpenGroupServerPoller';
import { isUsAnySogsFromCache } from '../session/apis/open_group_api/sogsv3/knownBlindedkeys';
import { getOpenGroupV2ConversationId } from '../session/apis/open_group_api/utils/OpenGroupUtils';
import { getConversationController } from '../session/conversations';
import { removeMessagePadding } from '../session/crypto/BufferPadding';
import { UserUtils } from '../session/utils';
import { perfEnd, perfStart } from '../session/utils/Performance';
import { fromBase64ToArray } from '../session/utils/String';
import { cleanIncomingDataMessage, messageHasVisibleContent } from './dataMessage';
@ -85,7 +85,7 @@ const handleOpenGroupMessage = async (
}
void groupConvo.queueJob(async () => {
const isMe = UserUtils.isUsFromCache(sender);
const isMe = isUsAnySogsFromCache(sender);
// this timestamp has already been forced to ms by the handleMessagesResponseV4() function
const commonAttributes = { serverTimestamp: sentTimestamp, serverId, conversationId };

View file

@ -311,6 +311,20 @@ async function handleExpirationTimerUpdateNoCommit(
await conversation.updateExpireTimer(expireTimer, source, message.get('received_at'), {}, false);
}
async function markConvoAsReadIfOutgoingMessage(
conversation: ConversationModel,
message: MessageModel
) {
const isOutgoingMessage =
message.get('type') === 'outgoing' || message.get('direction') === 'outgoing';
if (isOutgoingMessage) {
const sentAt = message.get('sent_at') || message.get('serverTimestamp');
if (sentAt) {
conversation.markConversationRead(sentAt);
}
}
}
export async function handleMessageJob(
messageModel: MessageModel,
conversation: ConversationModel,
@ -386,6 +400,7 @@ export async function handleMessageJob(
);
}
await markConvoAsReadIfOutgoingMessage(conversation, messageModel);
if (messageModel.get('unread')) {
conversation.throttledNotify(messageModel);
}

View file

@ -7,17 +7,18 @@ import { getOpenGroupManager } from '../apis/open_group_api/opengroupV2/OpenGrou
import { getSwarmFor } from '../apis/snode_api/snodePool';
import { PubKey } from '../types';
import { ConvoVolatileType } from 'libsession_util_nodejs';
import { deleteAllMessagesByConvoIdNoConfirmation } from '../../interactions/conversationInteractions';
import { CONVERSATION_PRIORITIES, ConversationTypeEnum } from '../../models/conversationAttributes';
import { assertUnreachable } from '../../types/sqlSharedTypes';
import { UserGroupsWrapperActions } from '../../webworker/workers/browser/libsession_worker_interface';
import { leaveClosedGroup } from '../group/closed-group';
import { ConfigurationDumpSync } from '../utils/job_runners/jobs/ConfigurationSyncDumpJob';
import { ConfigurationSync } from '../utils/job_runners/jobs/ConfigurationSyncJob';
import { LibSessionUtil } from '../utils/libsession/libsession_utils';
import { SessionUtilContact } from '../utils/libsession/libsession_utils_contacts';
import { SessionUtilConvoInfoVolatile } from '../utils/libsession/libsession_utils_convo_info_volatile';
import { SessionUtilUserGroups } from '../utils/libsession/libsession_utils_user_groups';
import { ConfigurationDumpSync } from '../utils/job_runners/jobs/ConfigurationSyncDumpJob';
import { LibSessionUtil } from '../utils/libsession/libsession_utils';
import { assertUnreachable } from '../../types/sqlSharedTypes';
import { ConvoVolatileType } from 'libsession_util_nodejs';
let instance: ConversationController | null;
@ -235,6 +236,18 @@ export class ConversationController {
break;
case 'Community':
window?.log?.info('leaving open group v2', conversation.id);
try {
const fromWrapper = await UserGroupsWrapperActions.getCommunityByFullUrl(conversation.id);
await SessionUtilConvoInfoVolatile.removeCommunityFromWrapper(
conversation.id,
fromWrapper?.fullUrl || ''
);
} catch (e) {
window?.log?.info('SessionUtilConvoInfoVolatile.removeCommunityFromWrapper failed:', e);
}
// 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);
@ -242,15 +255,6 @@ export class ConversationController {
window?.log?.info('SessionUtilUserGroups.removeCommunityFromWrapper failed:', e);
}
try {
await SessionUtilConvoInfoVolatile.removeCommunityFromWrapper(
conversation.id,
conversation.id
);
} catch (e) {
window?.log?.info('SessionUtilConvoInfoVolatile.removeCommunityFromWrapper failed:', e);
}
const roomInfos = OpenGroupData.getV2OpenGroupRoom(conversation.id);
if (roomInfos) {
getOpenGroupManager().removeRoomFromPolledRooms(roomInfos);
@ -264,7 +268,7 @@ export class ConversationController {
}
break;
case 'LegacyGroup':
window.log.info(`deleteContact ClosedGroup case: ${id}`);
window.log.info(`deleteContact ClosedGroup case: ${conversation.id}`);
await leaveClosedGroup(conversation.id);
await SessionUtilUserGroups.removeLegacyGroupFromWrapper(conversation.id);
await SessionUtilConvoInfoVolatile.removeLegacyGroupFromWrapper(conversation.id);

View file

@ -10,7 +10,8 @@ import { toHex } from '../utils/String';
async function updateOurProfileSync(
displayName: string | undefined,
profileUrl: string | null,
profileKey: Uint8Array | null
profileKey: Uint8Array | null,
priority: number | null
) {
const us = UserUtils.getOurPubKeyStrFromCache();
const ourConvo = getConversationController().get(us);
@ -19,7 +20,11 @@ async function updateOurProfileSync(
return;
}
return updateProfileOfContact(us, displayName, profileUrl, profileKey);
await updateProfileOfContact(us, displayName, profileUrl, profileKey);
if (priority !== null && ourConvo.get('priority') !== priority) {
ourConvo.set('priority', priority);
await ourConvo.commit();
}
}
/**

View file

@ -99,7 +99,7 @@ class ConfigurationSyncDumpJob extends PersistedJob<ConfigurationSyncDumpPersist
// so when we call needsDump(), we know for sure that we are up to date
// TODOLATER we need to add the dump of the wrappers of other destination than ourself once we had the closed group handling of config sync job
// I think dumping should not fetch data from the DB again, but instead just use the data already in the wrapper.
for (let index = 0; index < LibSessionUtil.requiredUserVariants.length; index++) {
const variant = LibSessionUtil.requiredUserVariants[index];
switch (variant) {
@ -174,7 +174,7 @@ async function queueNewJobIfNeeded() {
// this call will make sure that there is only one configuration sync job at all times
await runners.configurationSyncDumpRunner.addJob(
new ConfigurationSyncDumpJob({ nextAttemptTimestamp: Date.now() })
new ConfigurationSyncDumpJob({ nextAttemptTimestamp: Date.now() + 1000 }) // we postpone by 1000ms to make sure whoever is adding this job is done with what is needs to do first
);
} else {
// if we did run at 100, and it is currently 110, diff is 10

View file

@ -168,6 +168,7 @@ class ConfigurationSyncJob extends PersistedJob<ConfigurationSyncPersistedData>
window.log.warn('did not find our own conversation');
return RunJobResult.PermanentFailure;
}
for (let index = 0; index < LibSessionUtil.requiredUserVariants.length; index++) {
const variant = LibSessionUtil.requiredUserVariants[index];
switch (variant) {
@ -292,9 +293,9 @@ async function queueNewJobIfNeeded() {
) {
// this call will make sure that there is only one configuration sync job at all times
await runners.configurationSyncRunner.addJob(
new ConfigurationSyncJob({ nextAttemptTimestamp: Date.now() })
new ConfigurationSyncJob({ nextAttemptTimestamp: Date.now() + 1000 })
);
window.log.debug('Scheduling ConfSyncJob: ASAP');
window.log.debug('Scheduling ConfSyncJob: ASAP'); // we postpone by 1000ms to make sure whoever is adding this job is done with what is needs to do first
} else {
// if we did run at t=100, and it is currently t=110, the difference is 10
const diff = Math.max(Date.now() - lastRunConfigSyncJobTimestamp, 0);

View file

@ -98,17 +98,18 @@ async function pendingChangesForPubkey(pubkey: string): Promise<Array<OutgoingCo
}
const results: Array<OutgoingConfResult> = [];
const variantsNeedingPush = new Set<ConfigWrapperObjectTypes>();
for (let index = 0; index < dumps.length; index++) {
const dump = dumps[index];
const variant = dump.variant;
const needsPush = await GenericWrapperActions.needsPush(variant);
window.log.debug(`needsPush ${needsPush} for variant: ${variant}`);
if (!needsPush) {
continue;
}
variantsNeedingPush.add(variant);
const { data, seqno, hashes } = await GenericWrapperActions.push(variant);
const kind = variantToKind(variant);
@ -124,6 +125,7 @@ async function pendingChangesForPubkey(pubkey: string): Promise<Array<OutgoingCo
namespace,
});
}
window.log.debug(`those variants needs push: "${[...variantsNeedingPush]}"`);
return results;
}

View file

@ -242,9 +242,9 @@ function getVolatileInfoCached(convoId: string): BaseConvoInfoVolatile | undefin
/**
* Removes the matching community from the wrapper and from the cached list of communities
*/
async function removeCommunityFromWrapper(convoId: string, fullUrlWithOrWithoutPubkey: string) {
async function removeCommunityFromWrapper(convoId: string, fullUrlWithPubkey: string) {
try {
await ConvoInfoVolatileWrapperActions.eraseCommunityByFullUrl(fullUrlWithOrWithoutPubkey);
await ConvoInfoVolatileWrapperActions.eraseCommunityByFullUrl(fullUrlWithPubkey);
} catch (e) {
window.log.warn('removeCommunityFromWrapper failed with ', e.message);
}

View file

@ -66,6 +66,27 @@ function isLegacyGroupToStoreInWrapper(convo: ConversationModel): boolean {
);
}
/**
* We do not want to include groups left in the wrapper, but when receiving a list of wrappers from the network we need to check against the one present locally but already left, to know we need to remove them.
*
* This is to take care of this case:
* - deviceA creates group
* - deviceB joins group
* - deviceA leaves the group
* - deviceB leaves the group
* - deviceA removes the group entirely from the wrapper
* - deviceB receives the wrapper update and needs to remove the group from the DB
*
* But, as the group was already left, it would not be accounted for by `isLegacyGroupToStoreInWrapper`
*
*/
function isLegacyGroupToRemoveFromDBIfNotInWrapper(convo: ConversationModel): boolean {
// this filter is based on `isLegacyGroupToStoreInWrapper`
return (
convo.isGroup() && !convo.isPublic() && convo.id.startsWith('05') // new closed groups won't start with 05
);
}
/**
* Fetches the specified convo and updates the required field in the wrapper.
* If that community does not exist in the wrapper, it is created before being updated.
@ -221,10 +242,13 @@ function getAllLegacyGroups(): Array<LegacyGroupInfo> {
* Remove the matching legacy group from the wrapper and from the cached list of legacy groups
*/
async function removeLegacyGroupFromWrapper(groupPk: string) {
const fromWrapper = await UserGroupsWrapperActions.getLegacyGroup(groupPk);
if (fromWrapper) {
try {
await UserGroupsWrapperActions.eraseLegacyGroup(groupPk);
} catch (e) {
window.log.warn(
`UserGroupsWrapperActions.eraseLegacyGroup with = ${groupPk} failed with`,
e.message
);
}
mappedLegacyGroupWrapperValues.delete(groupPk);
@ -257,6 +281,7 @@ export const SessionUtilUserGroups = {
// legacy group
isLegacyGroupToStoreInWrapper,
isLegacyGroupToRemoveFromDBIfNotInWrapper,
getLegacyGroupCached,
getAllLegacyGroups,
removeLegacyGroupFromWrapper, // a group can be removed but also just marked hidden, so only call this function when the group is completely removed // TODOLATER

View file

@ -3,6 +3,7 @@ import { UserUtils } from '..';
import { UserConfigWrapperActions } from '../../../webworker/workers/browser/libsession_worker_interface';
import { getConversationController } from '../../conversations';
import { fromHexToArray } from '../String';
import { CONVERSATION_PRIORITIES } from '../../../models/conversationAttributes';
async function insertUserProfileIntoWrapper(convoId: string) {
if (!isUserProfileToStoreInWrapper(convoId)) {
@ -18,12 +19,21 @@ async function insertUserProfileIntoWrapper(convoId: string) {
const dbName = ourConvo.get('displayNameInProfile') || '';
const dbProfileUrl = ourConvo.get('avatarPointer') || '';
const dbProfileKey = fromHexToArray(ourConvo.get('profileKey') || '');
await UserConfigWrapperActions.setName(dbName);
if (dbProfileUrl && !isEmpty(dbProfileKey)) {
await UserConfigWrapperActions.setProfilePicture(dbProfileUrl, dbProfileKey);
await UserConfigWrapperActions.setUserInfo(
dbName,
ourConvo.get('priority') || CONVERSATION_PRIORITIES.default,
dbProfileUrl,
dbProfileKey
);
} else {
await UserConfigWrapperActions.setProfilePicture('', new Uint8Array());
await UserConfigWrapperActions.setUserInfo(
dbName,
ourConvo.get('priority') || CONVERSATION_PRIORITIES.default,
'',
new Uint8Array()
);
}
}

View file

@ -288,6 +288,11 @@ const _getLeftPaneLists = (
directConversations.push(conversation);
}
// a private conversation not approved is a message request. Exclude them from the left pane lists
if (conversation.isPrivate && !conversation.isApproved) {
continue;
}
const isPrivateButHidden =
conversation.isPrivate &&
conversation.priority &&

View file

@ -58,7 +58,7 @@ const getMessageByReaction = async (
}
if (!originalMessage) {
window?.log?.warn(`Cannot find the original reacted message ${originalMessageId}.`);
window?.log?.debug(`Cannot find the original reacted message ${originalMessageId}.`);
return null;
}
@ -236,7 +236,7 @@ const handleMessageReaction = async ({
const handleClearReaction = async (conversationId: string, serverId: number, emoji: string) => {
const originalMessage = await Data.getMessageByServerId(conversationId, serverId);
if (!originalMessage) {
window?.log?.warn(
window?.log?.debug(
`Cannot find the original reacted message ${serverId} in conversation ${conversationId}.`
);
return;
@ -269,7 +269,7 @@ const handleOpenGroupMessageReactions = async (
) => {
const originalMessage = await Data.getMessageByServerId(conversationId, serverId);
if (!originalMessage) {
window?.log?.warn(
window?.log?.debug(
`Cannot find the original reacted message ${serverId} in conversation ${conversationId}.`
);
return;

View file

@ -92,21 +92,13 @@ export const UserConfigWrapperActions: UserConfigWrapperActionsCalls = {
storageNamespace: async () => GenericWrapperActions.storageNamespace('UserConfig'),
/** UserConfig wrapper specific actions */
getName: async () =>
callLibSessionWorker(['UserConfig', 'getName']) as Promise<
ReturnType<UserConfigWrapperActionsCalls['getName']>
getUserInfo: async () =>
callLibSessionWorker(['UserConfig', 'getUserInfo']) as Promise<
ReturnType<UserConfigWrapperActionsCalls['getUserInfo']>
>,
getProfilePicture: async () =>
callLibSessionWorker(['UserConfig', 'getProfilePicture']) as Promise<
ReturnType<UserConfigWrapperActionsCalls['getProfilePicture']>
>,
setName: async (name: string) =>
callLibSessionWorker(['UserConfig', 'setName', name]) as Promise<
ReturnType<UserConfigWrapperActionsCalls['setName']>
>,
setProfilePicture: async (url: string, key: Uint8Array) =>
callLibSessionWorker(['UserConfig', 'setProfilePicture', url, key]) as Promise<
ReturnType<UserConfigWrapperActionsCalls['setProfilePicture']>
setUserInfo: async (name: string, priority: number, url: string, key: Uint8Array) =>
callLibSessionWorker(['UserConfig', 'setUserInfo', name, priority, url, key]) as Promise<
ReturnType<UserConfigWrapperActionsCalls['setUserInfo']>
>,
};