Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Not initializing on reconnection when general channel was deleted (#2334) #2400

Merged
merged 3 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

* Fixes channel name creation logic
* Allow JPEG and GIF files as profile photos ([#2332](https://github.com/TryQuiet/quiet/issues/2332))
* Fixes issues with recreating general channel when deleted while offline ([#2334](https://github.com/TryQuiet/quiet/issues/2334))

[2.1.2]

Expand Down
14 changes: 7 additions & 7 deletions packages/backend/src/nest/storage/storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -611,15 +611,15 @@ export class StorageService extends EventEmitter {
}
}
await repo.db.load()
const allEntries = this.getAllEventLogRawEntries(repo.db)
// const allEntries = this.getAllEventLogRawEntries(repo.db)
await repo.db.close()
await repo.db.drop()
const hashes = allEntries.map(e => CID.parse(e.hash))
const files = allEntries
.map(e => {
return e.payload.value.media
})
.filter(isDefined)
Comment on lines -614 to -622
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes were just to clean up some seemingly useless stuff. We weren't doing anything with those hashes/files so its just wasted work.

// const hashes = allEntries.map(e => CID.parse(e.hash))
// const files = allEntries
// .map(e => {
// return e.payload.value.media
// })
// .filter(isDefined)
// await this.deleteChannelFiles(files)
// await this.deleteChannelMessages(hashes)
this.publicChannelsRepos.delete(channelId)
Expand Down
84 changes: 77 additions & 7 deletions packages/e2e-tests/src/tests/multipleClients.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ describe('Multiple Clients', () => {

let secondChannelUser1: Channel

let thirdChannelOwner: Channel

let channelContextMenuOwner: ChannelContextMenu

let invitationCode: string
Expand All @@ -37,6 +39,7 @@ describe('Multiple Clients', () => {
const communityName = 'testcommunity'
const displayedCommunityName = 'Testcommunity'
const newChannelName = 'mid-night-club'
const thirdChannelName = 'delete-this'

const sleep = async (time = 1000) => {
await new Promise<void>(resolve =>
Expand Down Expand Up @@ -342,16 +345,42 @@ describe('Multiple Clients', () => {
const channels = await sidebarOwner.getChannelList()
expect(channels.length).toEqual(2)
})

it('Channel deletion - Owner creates third channel', async () => {
await sidebarOwner.addNewChannel(thirdChannelName)
await sidebarOwner.switchChannel(thirdChannelName)
thirdChannelOwner = new Channel(users.owner.app.driver, thirdChannelName)
const messages = await thirdChannelOwner.getUserMessages(users.owner.username)
expect(messages.length).toEqual(1)
await new Promise<void>(resolve =>
setTimeout(() => {
resolve()
}, 2000)
)
const channels = await sidebarUser1.getChannelList()
expect(channels.length).toEqual(3)
})

// End of tests for Windows
if (process.platform !== 'win32') {
it('Leave community', async () => {
console.log('TEST 2')
const settingsModal = await new Sidebar(users.user1.app.driver).openSettings()
const isSettingsModal = await settingsModal.element.isDisplayed()
expect(isSettingsModal).toBeTruthy()
await settingsModal.openLeaveCommunityModal()
await settingsModal.leaveCommunityButton()
it('User 1 closes app', async () => {
console.log('User 1 closes app')
await users.user1.app?.close()
})

// Delete third channel while guest is absent
it('Channel deletion - Owner deletes third channel', async () => {
console.log('TEST 2.5')
await new Promise<void>(resolve => setTimeout(() => resolve(), 10000))
const isThirdChannel = await thirdChannelOwner.messageInput.isDisplayed()
expect(isThirdChannel).toBeTruthy()
await channelContextMenuOwner.openMenu()
await channelContextMenuOwner.openDeletionChannelModal()
await channelContextMenuOwner.deleteChannel()
const channels = await sidebarOwner.getChannelList()
expect(channels.length).toEqual(2)
})

// Delete general channel while guest is absent
it('Channel deletion - Owner recreates general channel', async () => {
console.log('TEST 3')
Expand All @@ -365,6 +394,47 @@ describe('Multiple Clients', () => {
expect(channels.length).toEqual(2)
})

it('User 1 re-opens app', async () => {
console.log('User 1 re-opens app')
await users.user1.app?.open()
await new Promise<void>(resolve => setTimeout(() => resolve(), 30000))
})

// Check correct channels replication
it('Channel deletion - User sees information about recreation general channel and see correct amount of messages (#2334)', async () => {
console.log('TESTING - ISSUE 2334')
generalChannelUser1 = new Channel(users.user1.app.driver, 'general')
await generalChannelUser1.element.isDisplayed()
console.timeEnd(`[${users.user1.app.name}] '${users.user2.username}' joining community time`)
await new Promise<void>(resolve =>
setTimeout(() => {
resolve()
}, 10000)
)

await generalChannelUser1.waitForUserMessage(
users.owner.username,
`@${users.owner.username} deleted all messages in #general`
)
await generalChannelUser1.waitForUserMessage(
users.owner.username,
`@${users.owner.username} deleted #${thirdChannelName}`
)
await generalChannelUser1.waitForUserMessage(
users.owner.username,
`@${users.user2.username} has joined Testcommunity! 🎉`
)
})

it('Leave community', async () => {
console.log('TEST 2')
const settingsModal = await new Sidebar(users.user1.app.driver).openSettings()
const isSettingsModal = await settingsModal.element.isDisplayed()
expect(isSettingsModal).toBeTruthy()
await settingsModal.openLeaveCommunityModal()
await settingsModal.leaveCommunityButton()
})

it('Leave community - Guest re-join to community successfully', async () => {
console.log('TEST 4')
const debugModal = new DebugModeModal(users.user1.app.driver)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export function* channelDeletionResponseSaga(
let newGeneralChannel: PublicChannelStorage | undefined = yield* select(publicChannelsSelectors.generalChannel)
while (!newGeneralChannel) {
log('General channel has not been replicated yet')
yield* delay(500)
yield* delay(1000)
newGeneralChannel = yield* select(publicChannelsSelectors.generalChannel)
}
yield* put(publicChannelsActions.setCurrentChannel({ channelId: newGeneralChannel.id }))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ const log = logger('channels')
export function* channelsReplicatedSaga(
action: PayloadAction<ReturnType<typeof publicChannelsActions.channelsReplicated>['payload']>
): Generator {
log('Syncing channels')
// TODO: Refactor to use QuietLogger
log(`Syncing channels: ${JSON.stringify(action.payload, null, 2)}`)
const { channels } = action.payload
const _locallyStoredChannels = yield* select(publicChannelsSelectors.publicChannels)
const locallyStoredChannels = _locallyStoredChannels.map(channel => channel.id)
Expand All @@ -24,20 +25,10 @@ export function* channelsReplicatedSaga(
const databaseStoredChannelsIds = databaseStoredChannels.map(channel => channel.id)
console.log({ locallyStoredChannels, databaseStoredChannelsIds })

// Removing channels from store
if (databaseStoredChannelsIds.length > 0) {
for (const channelId of locallyStoredChannels) {
if (!databaseStoredChannelsIds.includes(channelId)) {
log(`Removing #${channelId} from store`)
yield* put(publicChannelsActions.deleteChannel({ channelId }))
yield* take(publicChannelsActions.completeChannelDeletion)
}
}
}

Comment on lines -27 to -37
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue ended up being that we were deleting the old general channel before we recreated it with the new ID so the check for the presence of the new channel was happening too early. Swapping the order of operations fixes it.

// Upserting channels to local storage
for (const channel of databaseStoredChannels) {
if (!locallyStoredChannels.includes(channel.id)) {
// TODO: Refactor to use QuietLogger
log(`Adding #${channel.name} to store`)
yield* put(
publicChannelsActions.addChannel({
Expand All @@ -52,6 +43,18 @@ export function* channelsReplicatedSaga(
}
}

// Removing channels from store
if (databaseStoredChannelsIds.length > 0) {
for (const channelId of locallyStoredChannels) {
if (!databaseStoredChannelsIds.includes(channelId)) {
// TODO: Refactor to use QuietLogger
log(`Removing #${channelId} from store`)
yield* put(publicChannelsActions.deleteChannel({ channelId }))
yield* take(publicChannelsActions.completeChannelDeletion)
}
}
}

const currentChannelCache = yield* select(publicChannelsSelectors.currentChannelMessages)
const currentChannelRepository = yield* select(messagesSelectors.currentPublicChannelMessagesEntries)

Expand Down
Loading