mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
refactor(realtime): the gateway asks a journey-access port instead of importing the journey domain
The websocket gateway injected JourneyDomainService to decide who may join a journey's book room, so the realtime domain, which nearly every domain imports for its broadcasts, depended on journey and closed a cycle through all of them. It now injects a JOURNEY_ACCESS port declared in realtime; JourneyAccessModule (global, imported by AppModule beside the gateway module) binds it to the same JourneyDomainService method.
This commit is contained in:
@@ -2,69 +2,44 @@
|
||||
"fileCycles": [],
|
||||
"domainCycles": [
|
||||
"accommodations -> assignments",
|
||||
"accommodations -> mcp-shared",
|
||||
"accommodations -> places",
|
||||
"accommodations -> realtime",
|
||||
"addons -> memories",
|
||||
"addons -> transit",
|
||||
"assignments -> days",
|
||||
"assignments -> journey",
|
||||
"assignments -> mcp-shared",
|
||||
"assignments -> realtime",
|
||||
"atlas -> addons",
|
||||
"auth -> plugins",
|
||||
"budget -> addons",
|
||||
"budget -> mcp-shared",
|
||||
"budget -> realtime",
|
||||
"days -> accommodations",
|
||||
"days -> assignments",
|
||||
"days -> mcp-shared",
|
||||
"days -> places",
|
||||
"days -> realtime",
|
||||
"files -> mcp-shared",
|
||||
"files -> realtime",
|
||||
"geo -> maps",
|
||||
"integrations -> addons",
|
||||
"integrations -> assignments",
|
||||
"integrations -> atlas",
|
||||
"integrations -> journey",
|
||||
"integrations -> mcp-shared",
|
||||
"integrations -> places",
|
||||
"integrations -> realtime",
|
||||
"integrations -> reservations",
|
||||
"journey -> addons",
|
||||
"journey -> atlas",
|
||||
"journey -> files",
|
||||
"journey -> memories",
|
||||
"journey -> photos",
|
||||
"journey -> realtime",
|
||||
"maps -> geo",
|
||||
"mcp-shared -> realtime",
|
||||
"memories -> addons",
|
||||
"memories -> notifications",
|
||||
"memories -> photos",
|
||||
"memories -> realtime",
|
||||
"notifications -> realtime",
|
||||
"photos -> memories",
|
||||
"places -> accommodations",
|
||||
"places -> assignments",
|
||||
"places -> atlas",
|
||||
"places -> journey",
|
||||
"places -> mcp-shared",
|
||||
"places -> realtime",
|
||||
"plugins -> trips",
|
||||
"plugins -> vacay",
|
||||
"realtime -> journey",
|
||||
"reservations -> accommodations",
|
||||
"reservations -> assignments",
|
||||
"reservations -> budget",
|
||||
"reservations -> days",
|
||||
"reservations -> integrations",
|
||||
"reservations -> mcp-shared",
|
||||
"reservations -> notifications",
|
||||
"reservations -> realtime",
|
||||
"transit -> days",
|
||||
"transit -> mcp-shared",
|
||||
"transit -> reservations",
|
||||
"trip-members -> auth",
|
||||
"trip-members -> trips",
|
||||
|
||||
@@ -64,6 +64,7 @@ import { SpaFallbackFilter } from './platform/spa-fallback.filter';
|
||||
import { PluginsModule } from './plugins/plugins.module';
|
||||
import { PublicApiModule } from './public-api/public-api.module';
|
||||
import { RealtimeGatewayModule } from './realtime/realtime-gateway.module';
|
||||
import { JourneyAccessModule } from './journey/journey-access.module';
|
||||
import { RealtimeModule } from './realtime/realtime.module';
|
||||
import { ReceiptScanModule } from './receipt-scan/receipt-scan.module';
|
||||
import { ReservationImportModule } from './reservation-import/reservation-import.module';
|
||||
@@ -100,6 +101,7 @@ import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
||||
DemoModule,
|
||||
RealtimeModule,
|
||||
RealtimeGatewayModule,
|
||||
JourneyAccessModule,
|
||||
SchedulingModule,
|
||||
McpModule.forRoot({
|
||||
accessPolicy: trekMcpAccessPolicy,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { JOURNEY_ACCESS } from '../realtime/journey-access.types';
|
||||
import { JourneyDomainModule } from './journey-domain.module';
|
||||
import { JourneyDomainService } from './journey-domain.service';
|
||||
|
||||
/**
|
||||
* Binds the realtime gateway's JOURNEY_ACCESS port to JourneyDomainService.
|
||||
* Global so RealtimeGatewayModule resolves it without importing the journey
|
||||
* domain; AppModule imports it next to the gateway module.
|
||||
*/
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [JourneyDomainModule],
|
||||
providers: [{ provide: JOURNEY_ACCESS, useExisting: JourneyDomainService }],
|
||||
exports: [JOURNEY_ACCESS],
|
||||
})
|
||||
export class JourneyAccessModule {}
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* What the gateway asks before it lets a socket into a journey's book room.
|
||||
*
|
||||
* A port rather than JourneyDomainService itself: realtime is imported by
|
||||
* nearly every domain for the broadcast facade, so depending on journey from
|
||||
* here put realtime, journey and everything between them on one import cycle.
|
||||
* The journey domain binds the token (JourneyAccessModule), and the answer is
|
||||
* still the one the REST routes get.
|
||||
*/
|
||||
export const JOURNEY_ACCESS = Symbol('JOURNEY_ACCESS');
|
||||
|
||||
export interface JourneyAccess {
|
||||
/** Truthy when the user may open the journey. */
|
||||
canAccessJourney(journeyId: number, userId: number): Promise<unknown>;
|
||||
}
|
||||
@@ -2,7 +2,6 @@ import { Module, type OnModuleDestroy } from '@nestjs/common';
|
||||
import { MikroOrmModule } from '@mikro-orm/nestjs';
|
||||
import { RealtimeGateway } from './realtime.gateway';
|
||||
import { EphemeralTokenModule } from '../auth-core/ephemeral-token.module';
|
||||
import { JourneyDomainModule } from '../journey/journey-domain.module';
|
||||
import { AppSettings } from '../../db/entities/AppSettings.entity';
|
||||
import { Users } from '../../db/entities/Users.entity';
|
||||
import { Trips } from '../../db/entities/Trips.entity';
|
||||
@@ -23,13 +22,13 @@ import { processRooms, RoomRegistry, roomsSlot } from './ws-state';
|
||||
* TrekWsAdapter already registered.
|
||||
*/
|
||||
@Module({
|
||||
// JourneyDomainModule for the book rooms: who may open a journey is asked
|
||||
// of the same service the REST routes ask. Users/AppSettings: Plan 4 Task
|
||||
// The book rooms ask JOURNEY_ACCESS, bound globally by JourneyAccessModule
|
||||
// to the same service the REST routes ask. Users/AppSettings: Plan 4 Task
|
||||
// 1 — the handshake's password-version and require_mfa reads, moved off
|
||||
// DatabaseService onto UsersRepository/AppSettingsRepository. Trips: Plan 4
|
||||
// Task 2 — handleJoin's own canAccessTrip delegate, now TripsRepository
|
||||
// directly.
|
||||
imports: [EphemeralTokenModule, JourneyDomainModule, MikroOrmModule.forFeature([Users, AppSettings, Trips])],
|
||||
imports: [EphemeralTokenModule, MikroOrmModule.forFeature([Users, AppSettings, Trips])],
|
||||
// The room registry is the process-wide in-memory one; the constructor
|
||||
// below hands whichever one the container resolved to the broadcast
|
||||
// functions, so the gateway and the broadcasts never use two registries.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Injectable, OnModuleDestroy } from '@nestjs/common';
|
||||
import { Inject, Injectable, OnModuleDestroy } from '@nestjs/common';
|
||||
import {
|
||||
ConnectedSocket,
|
||||
MessageBody,
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
userOf,
|
||||
type TrekWebSocket,
|
||||
} from './ws-state';
|
||||
import { JourneyDomainService } from '../journey/journey-domain.service';
|
||||
import { JOURNEY_ACCESS, type JourneyAccess } from './journey-access.types';
|
||||
import { readAppSetting } from '../common/app-settings.registry';
|
||||
import { runningVersion } from '../../app-config';
|
||||
|
||||
@@ -71,9 +71,10 @@ export class RealtimeGateway
|
||||
/*
|
||||
* For the book rooms, and injected rather than reimplemented: who may open
|
||||
* a journey is one question with one answer, and a second copy of it here
|
||||
* is a second thing to keep in step with the REST routes.
|
||||
* is a second thing to keep in step with the REST routes. Behind a port
|
||||
* (journey-access.types.ts) so realtime does not import the journey domain.
|
||||
*/
|
||||
private readonly journeys: JourneyDomainService,
|
||||
@Inject(JOURNEY_ACCESS) private readonly journeys: JourneyAccess,
|
||||
@InjectRepository(Users) private readonly users: UsersRepository,
|
||||
@InjectRepository(AppSettings) private readonly appSettings: AppSettingsRepository,
|
||||
// Room membership, behind its port. The container's provider, which
|
||||
|
||||
Reference in New Issue
Block a user