From 9d825dc2d26d70da01d6c60baae7bf23225dac51 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Fri, 23 Apr 2021 14:59:08 +1000 Subject: [PATCH] add start of OpenGroup Pollers v2 to start of the app --- app/sql.js | 21 ++++- js/background.js | 2 +- ts/components/session/ActionsPanel.tsx | 11 +-- .../session/LeftPaneMessageSection.tsx | 71 +++++++++++++---- ts/data/data.ts | 6 +- ts/data/opengroups.ts | 11 ++- ts/interactions/conversation.ts | 37 +++++++++ ts/interactions/index.ts | 3 +- ts/models/conversation.ts | 14 +--- ts/opengroup/opengroupV2/ApiUtil.ts | 1 - ts/opengroup/opengroupV2/JoinOpenGroupV2.ts | 7 +- .../opengroupV2/OpenGroupAPIV2CompactPoll.ts | 23 ++---- .../opengroupV2/OpenGroupManagerV2.ts | 78 +++++++++++++++---- .../opengroupV2/OpenGroupServerPoller.ts | 3 + ts/opengroup/utils/OpenGroupUtils.ts | 30 +++++-- .../conversations/ConversationController.ts | 2 + 16 files changed, 237 insertions(+), 83 deletions(-) create mode 100644 ts/interactions/conversation.ts diff --git a/app/sql.js b/app/sql.js index 3864e0b56..1049e43e6 100644 --- a/app/sql.js +++ b/app/sql.js @@ -49,7 +49,8 @@ module.exports = { updateConversation, removeConversation, getAllConversations, - getAllPublicConversations, + getAllOpenGroupV1Conversations, + getAllOpenGroupV2Conversations, getPubkeysInPublicConversation, getAllConversationIds, getAllGroupsInvolvingId, @@ -1591,11 +1592,25 @@ async function getAllConversationIds() { return map(rows, row => row.id); } -async function getAllPublicConversations() { +async function getAllOpenGroupV1Conversations() { const rows = await db.all( `SELECT json FROM ${CONVERSATIONS_TABLE} WHERE type = 'group' AND - id LIKE 'publicChat:%' + id LIKE 'publicChat:1@%' + ORDER BY id ASC;` + ); + + return map(rows, row => jsonToObject(row.json)); +} + +async function getAllOpenGroupV2Conversations() { + // first _ matches all opengroupv1, + // second _ force a second char to be there, so it can only be opengroupv2 convos + + const rows = await db.all( + `SELECT json FROM ${CONVERSATIONS_TABLE} WHERE + type = 'group' AND + id LIKE 'publicChat:__%@%' ORDER BY id ASC;` ); diff --git a/js/background.js b/js/background.js index fee9f40f7..d74d9a588 100644 --- a/js/background.js +++ b/js/background.js @@ -106,7 +106,7 @@ if (specialConvInited) { return; } - const publicConversations = await window.Signal.Data.getAllPublicConversations(); + const publicConversations = await window.Signal.Data.getAllOpenGroupV1Conversations(); publicConversations.forEach(conversation => { // weird but create the object and does everything we need conversation.getPublicSendData(); diff --git a/ts/components/session/ActionsPanel.tsx b/ts/components/session/ActionsPanel.tsx index 4970f5855..103386100 100644 --- a/ts/components/session/ActionsPanel.tsx +++ b/ts/components/session/ActionsPanel.tsx @@ -30,6 +30,7 @@ import { clearSearch } from '../../state/ducks/search'; import { showLeftPaneSection } from '../../state/ducks/section'; import { cleanUpOldDecryptedMedias } from '../../session/crypto/DecryptedAttachmentsManager'; +import { OpenGroupManagerV2 } from '../../opengroup/opengroupV2/OpenGroupManagerV2'; // tslint:disable-next-line: no-import-side-effect no-submodule-imports export enum SectionType { @@ -178,16 +179,8 @@ export const ActionsPanel = () => { // 'http://sessionopengroup.com/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231b' // 'https://sog.ibolpap.finance/main?public_key=b464aa186530c97d6bcf663a3a3b7465a5f782beaa67c83bee99468824b4aa10' // 'https://opengroup.bilb.us/main?public_key=1352534ba73d4265973280431dbc72e097a3e43275d1ada984f9805b4943047d' - + void OpenGroupManagerV2.getInstance().startPolling(); void syncConfiguration(); - // const parsedRoom = parseOpenGroupV2( - // 'https://opengroup.bilb.us/main?public_key=1352534ba73d4265973280431dbc72e097a3e43275d1ada984f9805b4943047d' - // ); - // if (parsedRoom) { - // setTimeout(async () => { - - // }, 6000); - // } }, []); // wait for cleanUpMediasInterval and then start cleaning up medias diff --git a/ts/components/session/LeftPaneMessageSection.tsx b/ts/components/session/LeftPaneMessageSection.tsx index 0ce4fb4b5..b7426526d 100644 --- a/ts/components/session/LeftPaneMessageSection.tsx +++ b/ts/components/session/LeftPaneMessageSection.tsx @@ -25,6 +25,11 @@ import { LeftPaneSectionHeader } from './LeftPaneSectionHeader'; import { ConversationController } from '../../session/conversations'; import { OpenGroup } from '../../opengroup/opengroupV1/OpenGroup'; import { ConversationType } from '../../models/conversation'; +import { + getOpenGroupV2ConversationId, + openGroupV2CompleteURLRegex, +} from '../../opengroup/utils/OpenGroupUtils'; +import { joinOpenGroupV2, parseOpenGroupV2 } from '../../opengroup/opengroupV2/JoinOpenGroupV2'; export interface Props { searchTerm: string; @@ -377,34 +382,25 @@ export class LeftPaneMessageSection extends React.Component { } } - private async handleJoinChannelButtonClick(serverUrl: string) { - const { loading } = this.state; - - if (loading) { - return; - } - - // guess if this is an open - + private async handleOpenGroupJoinV1(serverUrlV1: string) { // Server URL valid? - if (serverUrl.length === 0 || !OpenGroup.validate(serverUrl)) { + if (serverUrlV1.length === 0 || !OpenGroup.validate(serverUrlV1)) { ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl')); return; } // Already connected? - if (OpenGroup.getConversation(serverUrl)) { + if (OpenGroup.getConversation(serverUrlV1)) { ToastUtils.pushToastError('publicChatExists', window.i18n('publicChatExists')); return; } - // Connect to server try { ToastUtils.pushToastInfo('connectingToServer', window.i18n('connectingToServer')); this.setState({ loading: true }); - await OpenGroup.join(serverUrl); - if (await OpenGroup.serverExists(serverUrl)) { + await OpenGroup.join(serverUrlV1); + if (await OpenGroup.serverExists(serverUrlV1)) { ToastUtils.pushToastSuccess( 'connectToServerSuccess', window.i18n('connectToServerSuccess') @@ -413,7 +409,7 @@ export class LeftPaneMessageSection extends React.Component { throw new Error('Open group joined but the corresponding server does not exist'); } this.setState({ loading: false }); - const openGroupConversation = OpenGroup.getConversation(serverUrl); + const openGroupConversation = OpenGroup.getConversation(serverUrlV1); if (!openGroupConversation) { window.log.error('Joined an opengroup but did not find ther corresponding conversation'); @@ -426,6 +422,51 @@ export class LeftPaneMessageSection extends React.Component { } } + private async handleOpenGroupJoinV2(serverUrlV2: string) { + const parsedRoom = parseOpenGroupV2(serverUrlV2); + if (!parsedRoom) { + ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl')); + return; + } + try { + const conversationID = getOpenGroupV2ConversationId(parsedRoom.serverUrl, parsedRoom.roomId); + ToastUtils.pushToastInfo('connectingToServer', window.i18n('connectingToServer')); + this.setState({ loading: true }); + await joinOpenGroupV2(parsedRoom, false); + + const isConvoCreated = ConversationController.getInstance().get(conversationID); + if (isConvoCreated) { + ToastUtils.pushToastSuccess( + 'connectToServerSuccess', + window.i18n('connectToServerSuccess') + ); + } else { + ToastUtils.pushToastError('connectToServerFail', window.i18n('connectToServerFail')); + } + } catch (error) { + window.log.warn('got error while joining open group:', error); + ToastUtils.pushToastError('connectToServerFail', window.i18n('connectToServerFail')); + } finally { + this.setState({ loading: false }); + } + } + + private async handleJoinChannelButtonClick(serverUrl: string) { + const { loading } = this.state; + + if (loading) { + return; + } + + // guess if this is an open + if (serverUrl.match(openGroupV2CompleteURLRegex)) { + await this.handleOpenGroupJoinV2(serverUrl); + } else { + // this is an open group v1 + await this.handleOpenGroupJoinV1(serverUrl); + } + } + private async onCreateClosedGroup(groupName: string, groupMembers: Array) { if (this.state.loading) { window.log.warn('Closed group creation already in progress'); diff --git a/ts/data/data.ts b/ts/data/data.ts index ec624b997..0563dfbd9 100644 --- a/ts/data/data.ts +++ b/ts/data/data.ts @@ -93,7 +93,7 @@ const channelsToMake = { getAllConversations, getAllConversationIds, - getAllPublicConversations, + getAllOpenGroupV1Conversations, getPubkeysInPublicConversation, savePublicServerToken, getPublicServerTokenByServerUrl, @@ -584,8 +584,8 @@ export async function getAllConversationIds(): Promise> { return ids; } -export async function getAllPublicConversations(): Promise { - const conversations = await channels.getAllPublicConversations(); +export async function getAllOpenGroupV1Conversations(): Promise { + const conversations = await channels.getAllOpenGroupV1Conversations(); const collection = new ConversationCollection(); collection.add(conversations); diff --git a/ts/data/opengroups.ts b/ts/data/opengroups.ts index 7ba0670ac..567770ef0 100644 --- a/ts/data/opengroups.ts +++ b/ts/data/opengroups.ts @@ -1,3 +1,4 @@ +import { ConversationCollection } from '../models/conversation'; import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil'; import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils'; import { channels } from './channels'; @@ -15,7 +16,6 @@ export type OpenGroupV2Room = { }; export async function getAllV2OpenGroupRooms(): Promise | undefined> { - // TODO sql const opengroupsv2Rooms = (await channels.getAllV2OpenGroupRooms()) as Array; if (!opengroupsv2Rooms) { @@ -86,4 +86,13 @@ export const channelsToMake = { getV2OpenGroupRoomByRoomId, saveV2OpenGroupRoom, removeV2OpenGroupRoom, + getAllOpenGroupV2Conversations, }; + +export async function getAllOpenGroupV2Conversations(): Promise { + const conversations = await channels.getAllOpenGroupV2Conversations(); + + const collection = new ConversationCollection(); + collection.add(conversations); + return collection; +} diff --git a/ts/interactions/conversation.ts b/ts/interactions/conversation.ts new file mode 100644 index 000000000..f2ec6d676 --- /dev/null +++ b/ts/interactions/conversation.ts @@ -0,0 +1,37 @@ +import { + getCompleteUrlFromRoom, + openGroupPrefixRegex, + openGroupV2ConversationIdRegex, +} from '../opengroup/utils/OpenGroupUtils'; +import { getV2OpenGroupRoom } from '../data/opengroups'; +import { ToastUtils } from '../session/utils'; + +export async function copyPublicKey(convoId: string) { + if (convoId.match(openGroupPrefixRegex)) { + // open group v1 or v2 + if (convoId.match(openGroupV2ConversationIdRegex)) { + // this is a v2 group, just build the url + const roomInfos = await getV2OpenGroupRoom(convoId); + if (roomInfos) { + const fullUrl = getCompleteUrlFromRoom(roomInfos); + window.clipboard.writeText(fullUrl); + + ToastUtils.pushCopiedToClipBoard(); + return; + } + window.log.warn('coy to pubkey no roomInfo'); + return; + } + + // this is a v1 + const atIndex = convoId.indexOf('@'); + const openGroupUrl = convoId.substr(atIndex + 1); + window.clipboard.writeText(openGroupUrl); + + ToastUtils.pushCopiedToClipBoard(); + return; + } + window.clipboard.writeText(convoId); + + ToastUtils.pushCopiedToClipBoard(); +} diff --git a/ts/interactions/index.ts b/ts/interactions/index.ts index fe6cff982..6d4e80553 100644 --- a/ts/interactions/index.ts +++ b/ts/interactions/index.ts @@ -1,3 +1,4 @@ import * as MessageInteraction from './message'; +import * as ConversationInteraction from './conversation'; -export { MessageInteraction }; +export { MessageInteraction, ConversationInteraction }; diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index a74b7ab57..a69e65254 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -42,6 +42,8 @@ import { openGroupV1ConversationIdRegex, openGroupV2ConversationIdRegex, } from '../opengroup/utils/OpenGroupUtils'; +import { getV2OpenGroupRoom } from '../data/opengroups'; +import { ConversationInteraction } from '../interactions'; export enum ConversationType { GROUP = 'group', @@ -1275,17 +1277,7 @@ export class ConversationModel extends Backbone.Model { } public copyPublicKey() { - if (this.isPublic()) { - const atIndex = this.id.indexOf('@') as number; - const openGroupUrl = this.id.substr(atIndex + 1); - window.clipboard.writeText(openGroupUrl); - - ToastUtils.pushCopiedToClipBoard(); - return; - } - window.clipboard.writeText(this.id); - - ToastUtils.pushCopiedToClipBoard(); + void ConversationInteraction.copyPublicKey(this.id); } public changeNickname() { diff --git a/ts/opengroup/opengroupV2/ApiUtil.ts b/ts/opengroup/opengroupV2/ApiUtil.ts index 773378cb9..9119ac139 100644 --- a/ts/opengroup/opengroupV2/ApiUtil.ts +++ b/ts/opengroup/opengroupV2/ApiUtil.ts @@ -99,7 +99,6 @@ export const parseMessages = async ( rawMessages.map(async r => { try { const opengroupMessage = OpenGroupMessageV2.fromJson(r); - console.warn('opengroupMessage', opengroupMessage); if ( !opengroupMessage?.serverId || !opengroupMessage.sentTimestamp || diff --git a/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts b/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts index 6ab9b0480..df57e0684 100644 --- a/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts +++ b/ts/opengroup/opengroupV2/JoinOpenGroupV2.ts @@ -60,7 +60,7 @@ export function parseOpenGroupV2(urlWithPubkey: string): OpenGroupV2Room | undef */ export async function joinOpenGroupV2( room: OpenGroupV2Room, - fromSyncMessage: boolean = false + fromSyncMessage: boolean ): Promise { if (!room.serverUrl || !room.roomId || room.roomId.length < 2 || !room.serverPublicKey) { return; @@ -79,8 +79,9 @@ export async function joinOpenGroupV2( window.log.warn('Skipping join opengroupv2: already exists'); return; } else if (alreadyExist) { - // we don't have a convo associated with it. Remove the room in db - await removeV2OpenGroupRoom(conversationId); + // we don't have a convo associated with it. Remove everything related to it so we start fresh + window.log.warn('leaving before rejoining open group v2 room', conversationId); + await ConversationController.getInstance().deleteContact(conversationId); } // Try to connect to server diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts index 85dde8563..08826d867 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2CompactPoll.ts @@ -25,11 +25,7 @@ export const compactFetchEverything = async ( } const result = await sendOpenGroupV2RequestCompactPoll(compactPollRequest, abortSignal); - const statusCode = parseStatusCodeFromOnionRequest(result); - if (statusCode !== 200) { - return null; - } - return result; + return result ? result : null; }; /** @@ -119,8 +115,6 @@ async function sendOpenGroupV2RequestCompactPoll( // this will throw if the url is not valid const builtUrl = new URL(`${serverUrl}/${endpoint}`); - console.warn(`sending compactPoll request: ${request.body}`); - const res = await sendViaOnion( serverPubKey, builtUrl, @@ -144,11 +138,14 @@ async function sendOpenGroupV2RequestCompactPoll( return null; } // get all roomIds which needs a refreshed token - const roomTokensToRefresh = results.filter(ret => ret.statusCode === 401).map(r => r.roomId); + const roomWithTokensToRefresh = results.filter(ret => ret.statusCode === 401).map(r => r.roomId); - if (roomTokensToRefresh) { + // this holds only the poll results which are valid + const roomPollValidResults = results.filter(ret => ret.statusCode === 200); + + if (roomWithTokensToRefresh) { await Promise.all( - roomTokensToRefresh.map(async roomId => { + roomWithTokensToRefresh.map(async roomId => { const roomDetails = await getV2OpenGroupRoomByRoomId({ serverUrl, roomId, @@ -165,11 +162,7 @@ async function sendOpenGroupV2RequestCompactPoll( ); } - throw new Error( - 'See how we handle needs of new tokens, and save stuff to db (last deleted, ... conversation commit, etc' - ); - - return results; + return roomPollValidResults; } type ParsedRoomCompactPollResults = { diff --git a/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts b/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts index 63a8d9dce..7b14ba985 100644 --- a/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts +++ b/ts/opengroup/opengroupV2/OpenGroupManagerV2.ts @@ -1,12 +1,20 @@ -import { OpenGroupV2Room, removeV2OpenGroupRoom, saveV2OpenGroupRoom } from '../../data/opengroups'; +import { + getAllOpenGroupV2Conversations, + getAllV2OpenGroupRooms, + OpenGroupV2Room, + removeV2OpenGroupRoom, + saveV2OpenGroupRoom, +} from '../../data/opengroups'; import { ConversationModel, ConversationType } from '../../models/conversation'; import { ConversationController } from '../../session/conversations'; import { allowOnlyOneAtATime } from '../../session/utils/Promise'; import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils'; import { OpenGroupRequestCommonType } from './ApiUtil'; -import { openGroupV2GetRoomInfo } from './OpenGroupAPIV2'; +import { deleteAuthToken, openGroupV2GetRoomInfo } from './OpenGroupAPIV2'; import { OpenGroupServerPoller } from './OpenGroupServerPoller'; +import _ from 'lodash'; + /** * When we get our configuration from the network, we might get a few times the same open group on two different messages. * If we don't do anything, we will join them multiple times. @@ -93,9 +101,10 @@ export class OpenGroupManagerV2 { private readonly pollers: Map = new Map(); private isPolling = false; - private wasStopped = false; - private constructor() {} + private constructor() { + this.startPollingBouncy = this.startPollingBouncy.bind(this); + } public static getInstance() { if (!OpenGroupManagerV2.instance) { @@ -104,14 +113,8 @@ export class OpenGroupManagerV2 { return OpenGroupManagerV2.instance; } - public startPolling() { - if (this.isPolling) { - return; - } - if (this.wasStopped) { - throw new Error('OpengroupManager is not supposed to be starting again after being stopped.'); - } - this.isPolling = true; + public async startPolling() { + await allowOnlyOneAtATime('V2ManagerStartPolling', this.startPollingBouncy); } /** @@ -121,7 +124,13 @@ export class OpenGroupManagerV2 { if (!this.isPolling) { return; } - this.wasStopped = true; + // the stop call calls the abortController, which will effectively cancel the request right away, + // or drop the result from it. + this.pollers.forEach(poller => { + poller.stop(); + }); + this.pollers.clear(); + this.isPolling = false; } @@ -149,4 +158,47 @@ export class OpenGroupManagerV2 { poller.stop(); } } + + /** + * This function is private because we want to make sure it only runs once at a time. + */ + private async startPollingBouncy() { + if (this.isPolling) { + return; + } + const allConvos = await getAllOpenGroupV2Conversations(); + let allRoomInfos = await getAllV2OpenGroupRooms(); + + // this is time for some cleanup! + // We consider the conversations are our source-of-truth, + // so if there is a roomInfo without an associated convo, we remove it + if (allRoomInfos) { + await Promise.all( + [...allRoomInfos.values()].map(async infos => { + try { + const roomConvoId = getOpenGroupV2ConversationId(infos.serverUrl, infos.roomId); + if (!allConvos.get(roomConvoId)) { + // leave the group on the remote server + // this request doesn't throw + await deleteAuthToken(_.pick(infos, 'serverUrl', 'roomId')); + // remove the roomInfos locally for this open group room + await removeV2OpenGroupRoom(roomConvoId); + // no need to remove it from the ConversationController, the convo is already not there + } + } catch (e) { + window.log.warn('cleanup roomInfos error', e); + } + }) + ); + } + // refresh our roomInfos list + allRoomInfos = await getAllV2OpenGroupRooms(); + if (allRoomInfos) { + allRoomInfos.forEach(infos => { + this.addRoomToPolledRooms(infos); + }); + } + + this.isPolling = true; + } } diff --git a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts index e16173e0a..db165283e 100644 --- a/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts +++ b/ts/opengroup/opengroupV2/OpenGroupServerPoller.ts @@ -43,6 +43,7 @@ export class OpenGroupServerPoller { }); this.abortController = new AbortController(); + this.compactPoll = this.compactPoll.bind(this); this.pollForEverythingTimer = global.setInterval(this.compactPoll, pollForEverythingInterval); } @@ -143,6 +144,8 @@ export class OpenGroupServerPoller { this.roomIdsToPoll.has(result.roomId) ); window.log.warn(`compactFetchResults for ${this.serverUrl}:`, compactFetchResults); + + // ==> At this point all those results need to trigger conversation updates, so update what we have to update } catch (e) { window.log.warn('Got error while compact fetch:', e); } finally { diff --git a/ts/opengroup/utils/OpenGroupUtils.ts b/ts/opengroup/utils/OpenGroupUtils.ts index 5e7e5a767..54f7730fd 100644 --- a/ts/opengroup/utils/OpenGroupUtils.ts +++ b/ts/opengroup/utils/OpenGroupUtils.ts @@ -1,23 +1,39 @@ import { default as insecureNodeFetch } from 'node-fetch'; +import { OpenGroupV2Room } from '../../data/opengroups'; import { sendViaOnion } from '../../session/onions/onionSend'; -import { OpenGroup } from '../opengroupV1/OpenGroup'; -export const protocolRegex = '(https?://)?'; -export const hostnameRegex = - '(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]).)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])'; -export const portRegex = '(:[0-9]+)?'; +const protocolRegex = new RegExp('(https?://)?'); + +const dot = '\\.'; +const qMark = '\\?'; +const hostnameRegex = new RegExp( + `(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])${dot})*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9-]*[A-Za-z0-9])` +); +const portRegex = '(:[0-9]+)?'; // roomIds allows between 2 and 64 of '0-9' or 'a-z' or '_' chars export const roomIdV2Regex = '[0-9a-z_]{2,64}'; export const publicKeyRegex = '[0-9a-z]{64}'; export const publicKeyParam = 'public_key='; -export const openGroupV2ServerUrlRegex = new RegExp(`${protocolRegex}${hostnameRegex}${portRegex}`); +export const openGroupV2ServerUrlRegex = new RegExp( + `${protocolRegex.source}${hostnameRegex.source}${portRegex}` +); export const openGroupV2CompleteURLRegex = new RegExp( - `^${openGroupV2ServerUrlRegex}/${roomIdV2Regex}\\?${publicKeyParam}${publicKeyRegex}$`, + `^${openGroupV2ServerUrlRegex.source}\/${roomIdV2Regex}${qMark}${publicKeyParam}${publicKeyRegex}$`, 'gm' ); +/** + * This function returns a full url on an open group v2 room used for sync messages for instance. + * This is basically what the QRcode encodes + * + */ +export function getCompleteUrlFromRoom(roomInfos: OpenGroupV2Room) { + // serverUrl has the port and protocol already + return `${roomInfos.serverUrl}/${roomInfos.roomId}?${publicKeyParam}${roomInfos.serverPublicKey}`; +} + /** * Just a constant to have less `publicChat:` everywhere. * This is the prefix used to identify our open groups in the conversation database (v1 or v2) diff --git a/ts/session/conversations/ConversationController.ts b/ts/session/conversations/ConversationController.ts index af27695bf..91c6677df 100644 --- a/ts/session/conversations/ConversationController.ts +++ b/ts/session/conversations/ConversationController.ts @@ -17,6 +17,7 @@ import { actions as conversationActions } from '../../state/ducks/conversations' import { getV2OpenGroupRoom, removeV2OpenGroupRoom } from '../../data/opengroups'; import { deleteAuthToken } from '../../opengroup/opengroupV2/OpenGroupAPIV2'; import _ from 'lodash'; +import { OpenGroupManagerV2 } from '../../opengroup/opengroupV2/OpenGroupManagerV2'; export class ConversationController { private static instance: ConversationController | null; @@ -200,6 +201,7 @@ export class ConversationController { window.log.info('leaving open group v2', conversation.id); const roomInfos = await getV2OpenGroupRoom(conversation.id); if (roomInfos) { + OpenGroupManagerV2.getInstance().removeRoomFromPolledRooms(roomInfos); // leave the group on the remote server await deleteAuthToken(_.pick(roomInfos, 'serverUrl', 'roomId')); // remove the roomInfos locally for this open group room