mirror of
https://github.com/oxen-io/session-desktop.git
synced 2023-12-14 02:12:57 +01:00
fix: run tests for libsession-util integration and fix issue
This commit is contained in:
parent
faea0501bb
commit
cbffc29950
24 changed files with 181 additions and 99 deletions
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ const SessionJoinableRoomAvatar = (props: JoinableRoomProps) => {
|
|||
});
|
||||
}
|
||||
} catch (e) {
|
||||
window?.log?.warn(e);
|
||||
window?.log?.warn(e.message);
|
||||
}
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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']>
|
||||
>,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue