Skip to content
Draft
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
7 changes: 5 additions & 2 deletions packages/base/matrix-event.gts
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,12 @@ export interface RealmEvent extends BaseMatrixEvent {
content: RealmEventContent;
}

export type RealmEventContent =
export type RealmEventContent = (
| IndexRealmEventContent
| UpdateRealmEventContent;
| UpdateRealmEventContent
) & {
realmURL?: string;
};

export type IndexRealmEventContent =
| IncrementalIndexEventContent
Expand Down
25 changes: 7 additions & 18 deletions packages/host/app/services/matrix-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1846,28 +1846,17 @@ export default class MatrixService extends Service {
return;
}

let realmResourceForEvent = this.realm.realmForSessionRoomId(
event.room_id!,
);
if (!realmResourceForEvent) {
const content = event.content as RealmEventContent;
if (!content.realmURL) {
realmEventsLogger.debug(
'Ignoring realm event because no realm found',
'Ignoring realm event because no realm URL was provided',
event,
);
} else {
if (realmResourceForEvent.info?.realmUserId !== event.sender) {
realmEventsLogger.warn(
`Realm event sender ${event.sender} is not the realm user ${realmResourceForEvent.info?.realmUserId}`,
event,
);
}

(event.content as any).origin_server_ts = event.origin_server_ts;
this.messageService.relayRealmEvent(
realmResourceForEvent.url,
event.content as RealmEventContent,
);
return;
}

(content as any).origin_server_ts = event.origin_server_ts;
this.messageService.relayRealmEvent(content);
}
}

Expand Down
6 changes: 5 additions & 1 deletion packages/host/app/services/message-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ export default class MessageService extends Service {
}
}

relayRealmEvent(realmURL: string, event: RealmEventContent) {
relayRealmEvent(event: RealmEventContent) {
const realmURL = event.realmURL;
if (!realmURL) {
return;
}
this.listenerCallbacks.get(realmURL)?.forEach((cb) => {
cb(event);
});
Expand Down
7 changes: 6 additions & 1 deletion packages/host/tests/helpers/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,13 @@ export class TestRealmAdapter implements RealmAdapter {
rid.replace('test-session-room-realm-', '').startsWith(realmUrl),
);

const eventWithRealmURL: RealmEventContent = {
...event,
realmURL: realmUrl,
};

for (let roomId of targetRoomIds) {
simulateRemoteMessage(roomId, realmMatrixUsername, event, {
simulateRemoteMessage(roomId, realmMatrixUsername, eventWithRealmURL, {
type: APP_BOXEL_REALM_EVENT_TYPE,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ module('Integration | message service subscription', function (hooks) {
eventName: 'index',
indexType: 'incremental-index-initiation',
updatedFile: 'index.json',
realmURL: testRealmURL,
},
});

Expand Down
30 changes: 0 additions & 30 deletions packages/matrix/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,36 +120,6 @@ export async function setRealmRedirects(page: Page) {
}

export async function registerRealmUsers(synapse: SynapseInstance) {
await registerUser(
synapse,
'base_realm',
await realmPassword('base_realm', realmSecretSeed),
);
await registerUser(
synapse,
'experiments_realm',
await realmPassword('experiments_realm', realmSecretSeed),
);
await registerUser(
synapse,
'catalog_realm',
await realmPassword('catalog_realm', realmSecretSeed),
);
await registerUser(
synapse,
'skills_realm',
await realmPassword('skills_realm', realmSecretSeed),
);
await registerUser(
synapse,
'test_realm',
await realmPassword('test_realm', realmSecretSeed),
);
await registerUser(
synapse,
'node-test_realm',
await realmPassword('node-test_realm', realmSecretSeed),
);
await registerUser(
synapse,
'realm_server',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
exports.up = (pgm) => {
pgm.addColumns('session_rooms', {
realm_user_id: { type: 'varchar' },
});
};

exports.down = (pgm) => {
pgm.dropColumns('session_rooms', ['realm_user_id']);
};
11 changes: 8 additions & 3 deletions packages/realm-server/handlers/handle-create-session.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import {
fetchSessionRoom,
logger,
REALM_SERVER_REALM,
SupportedMimeType,
upsertSessionRoom,
} from '@cardstack/runtime-common';
Expand Down Expand Up @@ -42,17 +41,23 @@ export default function handleCreateSessionRequest({
createJWT: async (user: string, sessionRoom: string) =>
createJWT({ user, sessionRoom }, realmSecretSeed),
ensureSessionRoom: async (userId: string) => {
const realmServerUserId = matrixClient.getUserId();
if (!realmServerUserId) {
throw new Error(
'Realm server Matrix user ID is not available, unable to create session room',
);
}
let sessionRoom = await fetchSessionRoom(
dbAdapter,
REALM_SERVER_REALM,
realmServerUserId,
userId,
);

if (!sessionRoom) {
sessionRoom = await matrixClient.createDM(userId);
await upsertSessionRoom(
dbAdapter,
REALM_SERVER_REALM,
realmServerUserId,
userId,
sessionRoom,
);
Expand Down
21 changes: 1 addition & 20 deletions packages/realm-server/handlers/handle-publish-realm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ import {
import { createJWT } from '../jwt';
import type { CreateRoutesArgs } from '../routes';
import type { RealmServerTokenClaim } from '../utils/jwt';
import { registerUser } from '../synapse';
import { passwordFromSeed } from '@cardstack/runtime-common/matrix-client';

const log = logger('handle-publish');

Expand Down Expand Up @@ -99,13 +97,11 @@ function rewriteHostHomeForPublishedRealm(

export default function handlePublishRealm({
dbAdapter,
matrixClient,
realmSecretSeed,
serverURL,
virtualNetwork,
realms,
realmsRootPath,
getMatrixRegistrationSecret,
createAndMountRealm,
domainsForPublishedRealms,
}: CreateRoutesArgs): (ctxt: Koa.Context, next: Koa.Next) => Promise<void> {
Expand Down Expand Up @@ -246,7 +242,6 @@ export default function handlePublishRealm({
);

let userId;
let realmUsername;
let publishedRealmData: PublishedRealmTable | undefined;
if (existingPublishedRealm) {
let results = (await query(dbAdapter, [
Expand All @@ -261,7 +256,6 @@ export default function handlePublishRealm({
| 'last_published_at'
>[];
publishedRealmData = results[0];
realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmData.id}`;

let lastPublishedAt = Date.now().toString();
await query(dbAdapter, [
Expand All @@ -273,10 +267,9 @@ export default function handlePublishRealm({
publishedRealmData.last_published_at = lastPublishedAt;
} else {
let publishedRealmId = uuidv4();
realmUsername = `realm/${PUBLISHED_DIRECTORY_NAME}_${publishedRealmId}`;
let { valueExpressions, nameExpressions } = asExpressions({
id: publishedRealmId,
owner_username: realmUsername,
owner_username: 'NONE',
source_realm_url: sourceRealmURL,
published_realm_url: publishedRealmURL,
last_published_at: Date.now().toString(),
Expand All @@ -294,18 +287,7 @@ export default function handlePublishRealm({
| 'last_published_at'
>[];
publishedRealmData = results[0];

let { userId: newUserId } = await registerUser({
matrixURL: matrixClient.matrixURL,
displayname: realmUsername,
username: realmUsername,
password: await passwordFromSeed(realmUsername, realmSecretSeed),
registrationSecret: await getMatrixRegistrationSecret(),
});
userId = newUserId;

await insertPermissions(dbAdapter, new URL(publishedRealmURL), {
[userId]: ['read', 'realm-owner'],
[ownerUserId]: ['read', 'realm-owner'],
'*': ['read'],
});
Expand Down Expand Up @@ -350,7 +332,6 @@ export default function handlePublishRealm({
let realm = createAndMountRealm(
publishedRealmPath,
publishedRealmURL,
realmUsername,
new URL(sourceRealmURL),
false,
);
Expand Down
8 changes: 4 additions & 4 deletions packages/realm-server/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,12 @@ const getIndexHTML = async () => {
await waitForWorkerManager(workerManagerPort);
}

let realmServerMatrixClient = new MatrixClient({
let matrixClient = new MatrixClient({
matrixURL: new URL(MATRIX_URL),
username: REALM_SERVER_MATRIX_USERNAME,
seed: REALM_SECRET_SEED,
});
await matrixClient.login();
let prerenderer = createRemotePrerenderer(prerendererUrl);
let createPrerenderAuth = buildCreatePrerenderAuth(
REALM_SECRET_SEED,
Expand Down Expand Up @@ -272,12 +273,11 @@ const getIndexHTML = async () => {
{
url,
adapter: realmAdapter,
matrix: { url: new URL(matrixURL), username },
secretSeed: REALM_SECRET_SEED,
virtualNetwork,
dbAdapter,
queue,
realmServerMatrixClient,
matrixClient,
realmServerURL: serverURL,
definitionLookup,
cardSizeLimitBytes: Number(
Expand Down Expand Up @@ -319,7 +319,7 @@ const getIndexHTML = async () => {
let server = new RealmServer({
realms,
virtualNetwork,
matrixClient: realmServerMatrixClient,
matrixClient,
realmsRootPath,
realmServerSecretSeed: REALM_SERVER_SECRET_SEED,
realmSecretSeed: REALM_SECRET_SEED,
Expand Down
30 changes: 26 additions & 4 deletions packages/realm-server/node-realm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@ export class NodeAdapter implements RealmAdapter {
dbAdapter: DBAdapter,
): Promise<void> {
realmEventsLog.debug('Broadcasting realm event', event);

const eventWithRealmURL: RealmEventContent = {
...event,
realmURL: realmUrl,
};
let realmUserId;
if (dbAdapter.isClosed) {
realmEventsLog.warn(
`Database adapter is closed, skipping sending realm event`,
Expand All @@ -247,19 +251,35 @@ export class NodeAdapter implements RealmAdapter {
}
try {
await matrixClient.login();
realmUserId = matrixClient.getUserId();
if (!realmUserId) {
realmEventsLog.error(
'Matrix client has no user ID after login, unable to broadcast realm event',
event,
);
return;
}
} catch (e) {
realmEventsLog.error('Error logging into matrix. Skipping broadcast', e);
return;
}

let dmRooms = await this.waitForSessionRooms(dbAdapter, realmUrl);
let dmRooms = await this.waitForSessionRooms(
dbAdapter,
realmUrl,
realmUserId,
);

realmEventsLog.debug('Sending to dm rooms', Object.values(dmRooms));

for (let userId of Object.keys(dmRooms)) {
let roomId = dmRooms[userId];
try {
await matrixClient.sendEvent(roomId, APP_BOXEL_REALM_EVENT_TYPE, event);
await matrixClient.sendEvent(
roomId,
APP_BOXEL_REALM_EVENT_TYPE,
eventWithRealmURL,
);
} catch (e) {
realmEventsLog.error(
`Unable to send event in room ${roomId} for user ${userId}`,
Expand All @@ -273,6 +293,7 @@ export class NodeAdapter implements RealmAdapter {
private async waitForSessionRooms(
dbAdapter: DBAdapter,
realmUrl: string,
realmUserId: string,
attempts = 3,
delayMs = 50,
): Promise<Record<string, string>> {
Expand All @@ -282,7 +303,7 @@ export class NodeAdapter implements RealmAdapter {

let dmRooms: Record<string, string> = {};
try {
dmRooms = await fetchAllSessionRooms(dbAdapter, realmUrl);
dmRooms = await fetchAllSessionRooms(dbAdapter, realmUrl, realmUserId);
} catch (e) {
realmEventsLog.error('Error getting account data', e);
return {}; // bail immediately on errors instead of retrying
Expand All @@ -300,6 +321,7 @@ export class NodeAdapter implements RealmAdapter {
return await this.waitForSessionRooms(
dbAdapter,
realmUrl,
realmUserId,
attempts - 1,
delayMs,
);
Expand Down
1 change: 0 additions & 1 deletion packages/realm-server/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ export type CreateRoutesArgs = {
createAndMountRealm: (
path: string,
url: string,
username: string,
copiedFromRealm?: URL,
enableFileWatcher?: boolean,
fromScratchIndexPriority?: number,
Expand Down
Loading
Loading