add start of OpenGroup Pollers v2 to start of the app

pull/1576/head
Audric Ackermann 4 years ago
parent 193fb2a101
commit 9d825dc2d2
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -49,7 +49,8 @@ module.exports = {
updateConversation, updateConversation,
removeConversation, removeConversation,
getAllConversations, getAllConversations,
getAllPublicConversations, getAllOpenGroupV1Conversations,
getAllOpenGroupV2Conversations,
getPubkeysInPublicConversation, getPubkeysInPublicConversation,
getAllConversationIds, getAllConversationIds,
getAllGroupsInvolvingId, getAllGroupsInvolvingId,
@ -1591,11 +1592,25 @@ async function getAllConversationIds() {
return map(rows, row => row.id); return map(rows, row => row.id);
} }
async function getAllPublicConversations() { async function getAllOpenGroupV1Conversations() {
const rows = await db.all( const rows = await db.all(
`SELECT json FROM ${CONVERSATIONS_TABLE} WHERE `SELECT json FROM ${CONVERSATIONS_TABLE} WHERE
type = 'group' AND 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;` ORDER BY id ASC;`
); );

@ -106,7 +106,7 @@
if (specialConvInited) { if (specialConvInited) {
return; return;
} }
const publicConversations = await window.Signal.Data.getAllPublicConversations(); const publicConversations = await window.Signal.Data.getAllOpenGroupV1Conversations();
publicConversations.forEach(conversation => { publicConversations.forEach(conversation => {
// weird but create the object and does everything we need // weird but create the object and does everything we need
conversation.getPublicSendData(); conversation.getPublicSendData();

@ -30,6 +30,7 @@ import { clearSearch } from '../../state/ducks/search';
import { showLeftPaneSection } from '../../state/ducks/section'; import { showLeftPaneSection } from '../../state/ducks/section';
import { cleanUpOldDecryptedMedias } from '../../session/crypto/DecryptedAttachmentsManager'; import { cleanUpOldDecryptedMedias } from '../../session/crypto/DecryptedAttachmentsManager';
import { OpenGroupManagerV2 } from '../../opengroup/opengroupV2/OpenGroupManagerV2';
// tslint:disable-next-line: no-import-side-effect no-submodule-imports // tslint:disable-next-line: no-import-side-effect no-submodule-imports
export enum SectionType { export enum SectionType {
@ -178,16 +179,8 @@ export const ActionsPanel = () => {
// 'http://sessionopengroup.com/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231b' // 'http://sessionopengroup.com/main?public_key=658d29b91892a2389505596b135e76a53db6e11d613a51dbd3d0816adffb231b'
// 'https://sog.ibolpap.finance/main?public_key=b464aa186530c97d6bcf663a3a3b7465a5f782beaa67c83bee99468824b4aa10' // 'https://sog.ibolpap.finance/main?public_key=b464aa186530c97d6bcf663a3a3b7465a5f782beaa67c83bee99468824b4aa10'
// 'https://opengroup.bilb.us/main?public_key=1352534ba73d4265973280431dbc72e097a3e43275d1ada984f9805b4943047d' // 'https://opengroup.bilb.us/main?public_key=1352534ba73d4265973280431dbc72e097a3e43275d1ada984f9805b4943047d'
void OpenGroupManagerV2.getInstance().startPolling();
void syncConfiguration(); 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 // wait for cleanUpMediasInterval and then start cleaning up medias

@ -25,6 +25,11 @@ import { LeftPaneSectionHeader } from './LeftPaneSectionHeader';
import { ConversationController } from '../../session/conversations'; import { ConversationController } from '../../session/conversations';
import { OpenGroup } from '../../opengroup/opengroupV1/OpenGroup'; import { OpenGroup } from '../../opengroup/opengroupV1/OpenGroup';
import { ConversationType } from '../../models/conversation'; import { ConversationType } from '../../models/conversation';
import {
getOpenGroupV2ConversationId,
openGroupV2CompleteURLRegex,
} from '../../opengroup/utils/OpenGroupUtils';
import { joinOpenGroupV2, parseOpenGroupV2 } from '../../opengroup/opengroupV2/JoinOpenGroupV2';
export interface Props { export interface Props {
searchTerm: string; searchTerm: string;
@ -377,34 +382,25 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
} }
} }
private async handleJoinChannelButtonClick(serverUrl: string) { private async handleOpenGroupJoinV1(serverUrlV1: string) {
const { loading } = this.state;
if (loading) {
return;
}
// guess if this is an open
// Server URL valid? // Server URL valid?
if (serverUrl.length === 0 || !OpenGroup.validate(serverUrl)) { if (serverUrlV1.length === 0 || !OpenGroup.validate(serverUrlV1)) {
ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl')); ToastUtils.pushToastError('connectToServer', window.i18n('invalidOpenGroupUrl'));
return; return;
} }
// Already connected? // Already connected?
if (OpenGroup.getConversation(serverUrl)) { if (OpenGroup.getConversation(serverUrlV1)) {
ToastUtils.pushToastError('publicChatExists', window.i18n('publicChatExists')); ToastUtils.pushToastError('publicChatExists', window.i18n('publicChatExists'));
return; return;
} }
// Connect to server // Connect to server
try { try {
ToastUtils.pushToastInfo('connectingToServer', window.i18n('connectingToServer')); ToastUtils.pushToastInfo('connectingToServer', window.i18n('connectingToServer'));
this.setState({ loading: true }); this.setState({ loading: true });
await OpenGroup.join(serverUrl); await OpenGroup.join(serverUrlV1);
if (await OpenGroup.serverExists(serverUrl)) { if (await OpenGroup.serverExists(serverUrlV1)) {
ToastUtils.pushToastSuccess( ToastUtils.pushToastSuccess(
'connectToServerSuccess', 'connectToServerSuccess',
window.i18n('connectToServerSuccess') window.i18n('connectToServerSuccess')
@ -413,7 +409,7 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
throw new Error('Open group joined but the corresponding server does not exist'); throw new Error('Open group joined but the corresponding server does not exist');
} }
this.setState({ loading: false }); this.setState({ loading: false });
const openGroupConversation = OpenGroup.getConversation(serverUrl); const openGroupConversation = OpenGroup.getConversation(serverUrlV1);
if (!openGroupConversation) { if (!openGroupConversation) {
window.log.error('Joined an opengroup but did not find ther corresponding conversation'); window.log.error('Joined an opengroup but did not find ther corresponding conversation');
@ -426,6 +422,51 @@ export class LeftPaneMessageSection extends React.Component<Props, State> {
} }
} }
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<ContactType>) { private async onCreateClosedGroup(groupName: string, groupMembers: Array<ContactType>) {
if (this.state.loading) { if (this.state.loading) {
window.log.warn('Closed group creation already in progress'); window.log.warn('Closed group creation already in progress');

@ -93,7 +93,7 @@ const channelsToMake = {
getAllConversations, getAllConversations,
getAllConversationIds, getAllConversationIds,
getAllPublicConversations, getAllOpenGroupV1Conversations,
getPubkeysInPublicConversation, getPubkeysInPublicConversation,
savePublicServerToken, savePublicServerToken,
getPublicServerTokenByServerUrl, getPublicServerTokenByServerUrl,
@ -584,8 +584,8 @@ export async function getAllConversationIds(): Promise<Array<string>> {
return ids; return ids;
} }
export async function getAllPublicConversations(): Promise<ConversationCollection> { export async function getAllOpenGroupV1Conversations(): Promise<ConversationCollection> {
const conversations = await channels.getAllPublicConversations(); const conversations = await channels.getAllOpenGroupV1Conversations();
const collection = new ConversationCollection(); const collection = new ConversationCollection();
collection.add(conversations); collection.add(conversations);

@ -1,3 +1,4 @@
import { ConversationCollection } from '../models/conversation';
import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil'; import { OpenGroupRequestCommonType } from '../opengroup/opengroupV2/ApiUtil';
import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils'; import { isOpenGroupV2 } from '../opengroup/utils/OpenGroupUtils';
import { channels } from './channels'; import { channels } from './channels';
@ -15,7 +16,6 @@ export type OpenGroupV2Room = {
}; };
export async function getAllV2OpenGroupRooms(): Promise<Map<string, OpenGroupV2Room> | undefined> { export async function getAllV2OpenGroupRooms(): Promise<Map<string, OpenGroupV2Room> | undefined> {
// TODO sql
const opengroupsv2Rooms = (await channels.getAllV2OpenGroupRooms()) as Array<OpenGroupV2Room>; const opengroupsv2Rooms = (await channels.getAllV2OpenGroupRooms()) as Array<OpenGroupV2Room>;
if (!opengroupsv2Rooms) { if (!opengroupsv2Rooms) {
@ -86,4 +86,13 @@ export const channelsToMake = {
getV2OpenGroupRoomByRoomId, getV2OpenGroupRoomByRoomId,
saveV2OpenGroupRoom, saveV2OpenGroupRoom,
removeV2OpenGroupRoom, removeV2OpenGroupRoom,
getAllOpenGroupV2Conversations,
}; };
export async function getAllOpenGroupV2Conversations(): Promise<ConversationCollection> {
const conversations = await channels.getAllOpenGroupV2Conversations();
const collection = new ConversationCollection();
collection.add(conversations);
return collection;
}

@ -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();
}

@ -1,3 +1,4 @@
import * as MessageInteraction from './message'; import * as MessageInteraction from './message';
import * as ConversationInteraction from './conversation';
export { MessageInteraction }; export { MessageInteraction, ConversationInteraction };

@ -42,6 +42,8 @@ import {
openGroupV1ConversationIdRegex, openGroupV1ConversationIdRegex,
openGroupV2ConversationIdRegex, openGroupV2ConversationIdRegex,
} from '../opengroup/utils/OpenGroupUtils'; } from '../opengroup/utils/OpenGroupUtils';
import { getV2OpenGroupRoom } from '../data/opengroups';
import { ConversationInteraction } from '../interactions';
export enum ConversationType { export enum ConversationType {
GROUP = 'group', GROUP = 'group',
@ -1275,17 +1277,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
} }
public copyPublicKey() { public copyPublicKey() {
if (this.isPublic()) { void ConversationInteraction.copyPublicKey(this.id);
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();
} }
public changeNickname() { public changeNickname() {

@ -99,7 +99,6 @@ export const parseMessages = async (
rawMessages.map(async r => { rawMessages.map(async r => {
try { try {
const opengroupMessage = OpenGroupMessageV2.fromJson(r); const opengroupMessage = OpenGroupMessageV2.fromJson(r);
console.warn('opengroupMessage', opengroupMessage);
if ( if (
!opengroupMessage?.serverId || !opengroupMessage?.serverId ||
!opengroupMessage.sentTimestamp || !opengroupMessage.sentTimestamp ||

@ -60,7 +60,7 @@ export function parseOpenGroupV2(urlWithPubkey: string): OpenGroupV2Room | undef
*/ */
export async function joinOpenGroupV2( export async function joinOpenGroupV2(
room: OpenGroupV2Room, room: OpenGroupV2Room,
fromSyncMessage: boolean = false fromSyncMessage: boolean
): Promise<void> { ): Promise<void> {
if (!room.serverUrl || !room.roomId || room.roomId.length < 2 || !room.serverPublicKey) { if (!room.serverUrl || !room.roomId || room.roomId.length < 2 || !room.serverPublicKey) {
return; return;
@ -79,8 +79,9 @@ export async function joinOpenGroupV2(
window.log.warn('Skipping join opengroupv2: already exists'); window.log.warn('Skipping join opengroupv2: already exists');
return; return;
} else if (alreadyExist) { } else if (alreadyExist) {
// we don't have a convo associated with it. Remove the room in db // we don't have a convo associated with it. Remove everything related to it so we start fresh
await removeV2OpenGroupRoom(conversationId); window.log.warn('leaving before rejoining open group v2 room', conversationId);
await ConversationController.getInstance().deleteContact(conversationId);
} }
// Try to connect to server // Try to connect to server

@ -25,11 +25,7 @@ export const compactFetchEverything = async (
} }
const result = await sendOpenGroupV2RequestCompactPoll(compactPollRequest, abortSignal); const result = await sendOpenGroupV2RequestCompactPoll(compactPollRequest, abortSignal);
const statusCode = parseStatusCodeFromOnionRequest(result); return result ? result : null;
if (statusCode !== 200) {
return null;
}
return result;
}; };
/** /**
@ -119,8 +115,6 @@ async function sendOpenGroupV2RequestCompactPoll(
// this will throw if the url is not valid // this will throw if the url is not valid
const builtUrl = new URL(`${serverUrl}/${endpoint}`); const builtUrl = new URL(`${serverUrl}/${endpoint}`);
console.warn(`sending compactPoll request: ${request.body}`);
const res = await sendViaOnion( const res = await sendViaOnion(
serverPubKey, serverPubKey,
builtUrl, builtUrl,
@ -144,11 +138,14 @@ async function sendOpenGroupV2RequestCompactPoll(
return null; return null;
} }
// get all roomIds which needs a refreshed token // 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( await Promise.all(
roomTokensToRefresh.map(async roomId => { roomWithTokensToRefresh.map(async roomId => {
const roomDetails = await getV2OpenGroupRoomByRoomId({ const roomDetails = await getV2OpenGroupRoomByRoomId({
serverUrl, serverUrl,
roomId, roomId,
@ -165,11 +162,7 @@ async function sendOpenGroupV2RequestCompactPoll(
); );
} }
throw new Error( return roomPollValidResults;
'See how we handle needs of new tokens, and save stuff to db (last deleted, ... conversation commit, etc'
);
return results;
} }
type ParsedRoomCompactPollResults = { type ParsedRoomCompactPollResults = {

@ -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 { ConversationModel, ConversationType } from '../../models/conversation';
import { ConversationController } from '../../session/conversations'; import { ConversationController } from '../../session/conversations';
import { allowOnlyOneAtATime } from '../../session/utils/Promise'; import { allowOnlyOneAtATime } from '../../session/utils/Promise';
import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils'; import { getOpenGroupV2ConversationId } from '../utils/OpenGroupUtils';
import { OpenGroupRequestCommonType } from './ApiUtil'; import { OpenGroupRequestCommonType } from './ApiUtil';
import { openGroupV2GetRoomInfo } from './OpenGroupAPIV2'; import { deleteAuthToken, openGroupV2GetRoomInfo } from './OpenGroupAPIV2';
import { OpenGroupServerPoller } from './OpenGroupServerPoller'; 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. * 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. * If we don't do anything, we will join them multiple times.
@ -93,9 +101,10 @@ export class OpenGroupManagerV2 {
private readonly pollers: Map<string, OpenGroupServerPoller> = new Map(); private readonly pollers: Map<string, OpenGroupServerPoller> = new Map();
private isPolling = false; private isPolling = false;
private wasStopped = false;
private constructor() {} private constructor() {
this.startPollingBouncy = this.startPollingBouncy.bind(this);
}
public static getInstance() { public static getInstance() {
if (!OpenGroupManagerV2.instance) { if (!OpenGroupManagerV2.instance) {
@ -104,14 +113,8 @@ export class OpenGroupManagerV2 {
return OpenGroupManagerV2.instance; return OpenGroupManagerV2.instance;
} }
public startPolling() { public async startPolling() {
if (this.isPolling) { await allowOnlyOneAtATime('V2ManagerStartPolling', this.startPollingBouncy);
return;
}
if (this.wasStopped) {
throw new Error('OpengroupManager is not supposed to be starting again after being stopped.');
}
this.isPolling = true;
} }
/** /**
@ -121,7 +124,13 @@ export class OpenGroupManagerV2 {
if (!this.isPolling) { if (!this.isPolling) {
return; 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; this.isPolling = false;
} }
@ -149,4 +158,47 @@ export class OpenGroupManagerV2 {
poller.stop(); 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;
}
} }

@ -43,6 +43,7 @@ export class OpenGroupServerPoller {
}); });
this.abortController = new AbortController(); this.abortController = new AbortController();
this.compactPoll = this.compactPoll.bind(this);
this.pollForEverythingTimer = global.setInterval(this.compactPoll, pollForEverythingInterval); this.pollForEverythingTimer = global.setInterval(this.compactPoll, pollForEverythingInterval);
} }
@ -143,6 +144,8 @@ export class OpenGroupServerPoller {
this.roomIdsToPoll.has(result.roomId) this.roomIdsToPoll.has(result.roomId)
); );
window.log.warn(`compactFetchResults for ${this.serverUrl}:`, compactFetchResults); 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) { } catch (e) {
window.log.warn('Got error while compact fetch:', e); window.log.warn('Got error while compact fetch:', e);
} finally { } finally {

@ -1,23 +1,39 @@
import { default as insecureNodeFetch } from 'node-fetch'; import { default as insecureNodeFetch } from 'node-fetch';
import { OpenGroupV2Room } from '../../data/opengroups';
import { sendViaOnion } from '../../session/onions/onionSend'; import { sendViaOnion } from '../../session/onions/onionSend';
import { OpenGroup } from '../opengroupV1/OpenGroup';
export const protocolRegex = '(https?://)?'; const protocolRegex = new RegExp('(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])'; const dot = '\\.';
export const portRegex = '(:[0-9]+)?'; 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 // roomIds allows between 2 and 64 of '0-9' or 'a-z' or '_' chars
export const roomIdV2Regex = '[0-9a-z_]{2,64}'; export const roomIdV2Regex = '[0-9a-z_]{2,64}';
export const publicKeyRegex = '[0-9a-z]{64}'; export const publicKeyRegex = '[0-9a-z]{64}';
export const publicKeyParam = 'public_key='; 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( export const openGroupV2CompleteURLRegex = new RegExp(
`^${openGroupV2ServerUrlRegex}/${roomIdV2Regex}\\?${publicKeyParam}${publicKeyRegex}$`, `^${openGroupV2ServerUrlRegex.source}\/${roomIdV2Regex}${qMark}${publicKeyParam}${publicKeyRegex}$`,
'gm' '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. * 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) * This is the prefix used to identify our open groups in the conversation database (v1 or v2)

@ -17,6 +17,7 @@ import { actions as conversationActions } from '../../state/ducks/conversations'
import { getV2OpenGroupRoom, removeV2OpenGroupRoom } from '../../data/opengroups'; import { getV2OpenGroupRoom, removeV2OpenGroupRoom } from '../../data/opengroups';
import { deleteAuthToken } from '../../opengroup/opengroupV2/OpenGroupAPIV2'; import { deleteAuthToken } from '../../opengroup/opengroupV2/OpenGroupAPIV2';
import _ from 'lodash'; import _ from 'lodash';
import { OpenGroupManagerV2 } from '../../opengroup/opengroupV2/OpenGroupManagerV2';
export class ConversationController { export class ConversationController {
private static instance: ConversationController | null; private static instance: ConversationController | null;
@ -200,6 +201,7 @@ export class ConversationController {
window.log.info('leaving open group v2', conversation.id); window.log.info('leaving open group v2', conversation.id);
const roomInfos = await getV2OpenGroupRoom(conversation.id); const roomInfos = await getV2OpenGroupRoom(conversation.id);
if (roomInfos) { if (roomInfos) {
OpenGroupManagerV2.getInstance().removeRoomFromPolledRooms(roomInfos);
// leave the group on the remote server // leave the group on the remote server
await deleteAuthToken(_.pick(roomInfos, 'serverUrl', 'roomId')); await deleteAuthToken(_.pick(roomInfos, 'serverUrl', 'roomId'));
// remove the roomInfos locally for this open group room // remove the roomInfos locally for this open group room

Loading…
Cancel
Save