You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/ts/session/utils/libsession/libsession_utils_user_group...

181 lines
5.9 KiB
TypeScript

import { isEmpty, uniq } from 'lodash';
import { CommunityInfo } from 'session_util_wrapper';
import { OpenGroupData } from '../../../data/opengroups';
import { ConversationModel } from '../../../models/conversation';
import { getCommunityInfoFromDBValues } from '../../../types/sqlSharedTypes';
import { UserGroupsWrapperActions } from '../../../webworker/workers/browser/libsession_worker_interface';
import { OpenGroupUtils } from '../../apis/open_group_api/utils';
import { getConversationController } from '../../conversations';
/**
* The key of this map is the convoId as stored in the database.
* Note: the wrapper clean
*/
const mappedCommunityWrapperValues = new Map<string, CommunityInfo>();
/**
* Update the UserGroupsWrapper with all the data is cares about from the database.
*/
async function insertAllUserGroupsIntoWrapper() {
const convoIdsToInsert = uniq(
getConversationController()
.getConversations()
.filter(filterUserGroupsToStoreInWrapper)
.map(m => m.id)
);
const communitiesIdsToInsert = uniq(
getConversationController()
.getConversations()
.filter(filterUserCommunitiesToStoreInWrapper)
.map(m => m.id)
);
window.log.debug(
`UserGroupsWrapper keep tracks of ${convoIdsToInsert.length} usergroups of which ${communitiesIdsToInsert.length} are communities`
);
for (let index = 0; index < convoIdsToInsert.length; index++) {
const id = convoIdsToInsert[index];
await insertGroupsFromDBIntoWrapperAndRefresh(id);
}
}
/**
* Returns true if that conversation is an active group
*/
function filterUserGroupsToStoreInWrapper(convo: ConversationModel): boolean {
return convo.isGroup() && convo.isActive();
}
function filterUserCommunitiesToStoreInWrapper(convo: ConversationModel): boolean {
return convo.isPublic() && convo.isActive();
}
/**
* 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.
*/
async function insertGroupsFromDBIntoWrapperAndRefresh(convoId: string): Promise<void> {
const foundConvo = getConversationController().get(convoId);
if (!foundConvo) {
return;
}
if (!filterUserGroupsToStoreInWrapper(foundConvo)) {
return;
}
if (foundConvo.isOpenGroupV2()) {
const asOpengroup = foundConvo.toOpenGroupV2();
const isPinned = !!foundConvo.get('isPinned');
const roomDetails = OpenGroupData.getV2OpenGroupRoomByRoomId(asOpengroup);
if (!roomDetails) {
return;
}
// we need to build the full URL with the pubkey so we can add it to the wrapper. Let's reuse the exposed method from the wrapper for that
const fullUrl = await UserGroupsWrapperActions.buildFullUrlFromDetails(
roomDetails.serverUrl,
roomDetails.roomId,
roomDetails.serverPublicKey
);
const wrapperComm = getCommunityInfoFromDBValues({
isPinned,
fullUrl,
});
try {
console.info(`inserting into usergroup wrapper ${convoId}...`);
// this does the create or the update of the matching existing community
await UserGroupsWrapperActions.setCommunityByFullUrl(
wrapperComm.fullUrl,
wrapperComm.priority
);
} catch (e) {
window.log.warn(`UserGroupsWrapperActions.set of ${convoId} failed with ${e.message}`);
// we still let this go through
}
await refreshCommunityMappedValue(convoId);
} else {
// TODO
// throw new Error('insertGroupsFromDBIntoWrapperAndRefresh group and legacy todo');
}
}
/**
* refreshMappedValue is used to query the UserGroups Wrapper for the details of that group and update the cached in-memory entry representing its content.
* @param id the pubkey to re fresh the cached value from
* @param duringAppStart set this to true if we should just fetch the cached value but not trigger a UI refresh of the corresponding conversation
*/
async function refreshCommunityMappedValue(convoId: string, duringAppStart = false) {
try {
if (!OpenGroupUtils.isOpenGroupV2(convoId)) {
throw new Error(`Not an opengroupv2: "${convoId}"`);
}
const fromWrapper = await UserGroupsWrapperActions.getCommunityByFullUrl(convoId);
if (fromWrapper) {
SessionUtilUserGroups.setCommunityMappedValue(convoId, fromWrapper);
if (!duringAppStart) {
getConversationController()
.get(convoId)
?.triggerUIRefresh();
}
}
return;
} catch (e) {
window.log.info(`refreshCommunityMappedValue: not an opengroup convoID: ${convoId}`, e);
}
// TODO
// throw new Error('refreshMappedValue group and legacy todo');
}
function setCommunityMappedValue(convoId: string, info: CommunityInfo) {
if (isEmpty(info.fullUrl)) {
throw new Error(`setCommunityMappedValue needs a valid info.fullUrl ${info.fullUrl}`);
}
// this has the pubkey associated with it
mappedCommunityWrapperValues.set(convoId, info);
}
function getCommunityMappedValueByConvoId(convoId: string) {
return mappedCommunityWrapperValues.get(convoId);
}
function getAllCommunities(): Array<CommunityInfo> {
return [...mappedCommunityWrapperValues.values()];
}
/**
* Remove the matching community from the wrapper and from the cached list of communities
*/
async function removeCommunityFromWrapper(convoId: string, fullUrlWithOrWithoutPubkey: string) {
const fromWrapper = await UserGroupsWrapperActions.getCommunityByFullUrl(
fullUrlWithOrWithoutPubkey
);
if (fromWrapper) {
await UserGroupsWrapperActions.eraseCommunityByFullUrl(fromWrapper.fullUrl);
}
// might not be there but better make sure
mappedCommunityWrapperValues.delete(convoId);
}
export const SessionUtilUserGroups = {
filterUserGroupsToStoreInWrapper,
filterUserCommunitiesToStoreInWrapper,
getAllCommunities,
insertAllUserGroupsIntoWrapper,
insertGroupsFromDBIntoWrapperAndRefresh,
setCommunityMappedValue,
getCommunityMappedValueByConvoId,
refreshCommunityMappedValue,
removeCommunityFromWrapper,
};