Skip to content

Commit

Permalink
fix: prevent loading page on reconnect (#33770)
Browse files Browse the repository at this point in the history
Co-authored-by: Diego Sampaio <[email protected]>
  • Loading branch information
ggazzo and sampaiodiego committed Oct 25, 2024
1 parent b0cc33a commit 5d236fa
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
6 changes: 6 additions & 0 deletions .changeset/pretty-ladybugs-sneeze.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": patch
"@rocket.chat/ddp-streamer": patch
---

Fixes page loading during reconnections
12 changes: 12 additions & 0 deletions apps/meteor/app/authentication/server/startup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,24 @@ import { setAvatarFromServiceWithValidation } from '../../../lib/server/function
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
import * as Mailer from '../../../mailer/server/api';
import { settings } from '../../../settings/server';
import { getBaseUserFields } from '../../../utils/server/functions/getBaseUserFields';
import { safeGetMeteorUser } from '../../../utils/server/functions/safeGetMeteorUser';
import { isValidAttemptByUser, isValidLoginAttemptByIp } from '../lib/restrictLoginAttempts';

Accounts.config({
forbidClientAccountCreation: true,
});
/**
* Accounts calls `_initServerPublications` and holds the `_defaultPublishFields`, without Object.assign its not possible
* to extend the projection
*
* the idea is to send all required fields to the client during login
* we tried `defaultFieldsSelector` , but it changes all Meteor.userAsync projections which is undesirable
*
*
* we are removing the status here because meteor send 'offline'
*/
Object.assign(Accounts._defaultPublishFields.projection, (({ status, ...rest }) => rest)(getBaseUserFields()));

Meteor.startup(() => {
settings.watchMultiple(['Accounts_LoginExpiration', 'Site_Name', 'From_Email'], () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ export class CachedCollection<T extends { _id: string }, U = T> extends Emitter<
CachedCollectionManager.onLogin(() => {
void this.init();
});
Accounts.onLogout(() => {
this.ready.set(false);
});
}

protected get eventName(): `${Name}-changed` | `${string}/${Name}-changed` {
Expand Down Expand Up @@ -342,8 +345,6 @@ export class CachedCollection<T extends { _id: string }, U = T> extends Emitter<
}

async init() {
this.ready.set(false);

if (await this.loadFromCache()) {
this.trySync();
} else {
Expand Down
27 changes: 25 additions & 2 deletions ee/apps/ddp-streamer/src/DDPStreamer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import crypto from 'crypto';

import { MeteorService, Presence, ServiceClass } from '@rocket.chat/core-services';
import { InstanceStatus } from '@rocket.chat/instance-status';
import { Users } from '@rocket.chat/models';
import polka from 'polka';
import { throttle } from 'underscore';
import WebSocket from 'ws';
Expand Down Expand Up @@ -123,12 +124,34 @@ export class DDPStreamer extends ServiceClass {
}
});

server.on(DDP_EVENTS.LOGGED, (info) => {
async function sendUserData(client: Client, userId: string) {
// TODO figure out what fields to send. maybe to to export function getBaseUserFields to a package
const loggedUser = await Users.findOneById(userId, {
projection: { name: 1, username: 1, settings: 1, roles: 1, active: 1, statusLivechat: 1, statusDefault: 1, status: 1 },
});
if (!loggedUser) {
return;
}

// using setImmediate here so login's method result is sent before we send the user data
setImmediate(async () => server.added(client, 'users', userId, loggedUser));
}
server.on(DDP_EVENTS.LOGGED, async (info: Client) => {
const { userId, connection } = info;

Presence.newConnection(userId, connection.id, nodeID);
if (!userId) {
throw new Error('User not logged in');
}

await Presence.newConnection(userId, connection.id, nodeID);

this.updateConnections();

// mimic Meteor's default publication that sends user data after login
await sendUserData(info, userId);

server.emit('presence', { userId, connection });

this.api?.broadcast('accounts.login', { userId, connection });
});

Expand Down

0 comments on commit 5d236fa

Please sign in to comment.