Keys auf SSE umgestellt
This commit is contained in:
21
api/src/modules/realtime/sse/sse-ticket.service.ts
Normal file
21
api/src/modules/realtime/sse/sse-ticket.service.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class SseTicketService {
|
||||
private userTickets: Map<string, {userId: string, used: boolean}> = new Map();
|
||||
|
||||
generateTicket(userId: string): {ticket: string } {
|
||||
const ticket = crypto.randomUUID();
|
||||
|
||||
this.userTickets.set(ticket, { userId, used: false });
|
||||
|
||||
return {ticket};
|
||||
}
|
||||
|
||||
getUserIdToTicket(ticketId: string): string {
|
||||
if (!this.userTickets.has(ticketId)) { return null; }
|
||||
const ticket = this.userTickets.get(ticketId);
|
||||
if (!ticket || ticket.used) { return null; }
|
||||
return ticket.userId;
|
||||
}
|
||||
}
|
||||
18
api/src/modules/realtime/sse/sse.controller.spec.ts
Normal file
18
api/src/modules/realtime/sse/sse.controller.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { SseController } from './sse.controller';
|
||||
|
||||
describe('SseController', () => {
|
||||
let controller: SseController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [SseController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<SseController>(SseController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
38
api/src/modules/realtime/sse/sse.controller.ts
Normal file
38
api/src/modules/realtime/sse/sse.controller.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Controller, Get, Param, Query, Req, Sse, UnauthorizedException, UseGuards } from '@nestjs/common';
|
||||
import { AuthenticatedRequest } from 'src/model/interface/authenticated-request.interface';
|
||||
import { SseTicketService } from './sse-ticket.service';
|
||||
import { AuthGuard } from 'src/core/guards/auth.guard';
|
||||
import { Observable, interval, map } from 'rxjs';
|
||||
import { KeyService } from 'src/modules/key/key.service';
|
||||
import { AuthService } from 'src/modules/auth/auth.service';
|
||||
import { User } from 'src/model/entitites';
|
||||
import { UserService } from 'src/modules/user/user.service';
|
||||
import { SseService } from './sse.service';
|
||||
|
||||
@Controller('sse')
|
||||
export class SseController {
|
||||
|
||||
constructor(private ticketService: SseTicketService, private sseService: SseService, private userService: UserService) {}
|
||||
|
||||
@UseGuards(AuthGuard)
|
||||
@Get('ticket')
|
||||
getTicket(@Req() req: AuthenticatedRequest) {
|
||||
return this.ticketService.generateTicket(req.user.id)
|
||||
}
|
||||
|
||||
@Sse('key')
|
||||
async sse(@Query('ticket') ticket: string): Promise<Observable<any>> {
|
||||
const userId = this.ticketService.getUserIdToTicket(ticket);
|
||||
if (!userId) throw new UnauthorizedException('Invalid/expired ticket');
|
||||
const user = await this.getUserToId(userId);
|
||||
if (!userId) throw new UnauthorizedException('Invalid/expired ticket');
|
||||
|
||||
|
||||
return this.sseService.register(userId);
|
||||
}
|
||||
|
||||
private async getUserToId(userId: string): Promise<User> {
|
||||
const user = await this.userService.getUserById(userId);
|
||||
return Promise.resolve(user);
|
||||
}
|
||||
}
|
||||
17
api/src/modules/realtime/sse/sse.module.ts
Normal file
17
api/src/modules/realtime/sse/sse.module.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { SseController } from './sse.controller';
|
||||
import { DatabaseModule } from 'src/shared/database/database.module';
|
||||
import { SseTicketService } from './sse-ticket.service';
|
||||
import { AuthModule } from 'src/modules/auth/auth.module';
|
||||
import { SharedServiceModule } from 'src/shared/service/shared.service.module';
|
||||
import { MailModule } from 'src/modules/mail/mail.module';
|
||||
import { UserService } from 'src/modules/user/user.service';
|
||||
import { SseService } from './sse.service';
|
||||
|
||||
@Module({
|
||||
controllers: [SseController],
|
||||
imports: [DatabaseModule, AuthModule, SharedServiceModule, MailModule],
|
||||
providers: [SseTicketService, UserService, SseService],
|
||||
exports: [SseService]
|
||||
})
|
||||
export class SseModule {}
|
||||
18
api/src/modules/realtime/sse/sse.service.spec.ts
Normal file
18
api/src/modules/realtime/sse/sse.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { SseService } from './sse.service';
|
||||
|
||||
describe('SseService', () => {
|
||||
let service: SseService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [SseService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<SseService>(SseService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
22
api/src/modules/realtime/sse/sse.service.ts
Normal file
22
api/src/modules/realtime/sse/sse.service.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Injectable,MessageEvent } from '@nestjs/common';
|
||||
import { Subject } from 'rxjs';
|
||||
import { Key } from 'src/model/entitites';
|
||||
|
||||
@Injectable()
|
||||
export class SseService {
|
||||
private clients = new Map<string, Subject<MessageEvent>>();
|
||||
|
||||
sendKeysToUsers(userId: string, keys: Key[]) {
|
||||
try {
|
||||
const sub = this.clients.get(userId);
|
||||
if (!sub) { return; }
|
||||
sub.next({ data: keys })
|
||||
} catch {}
|
||||
}
|
||||
|
||||
register(userId: string) {
|
||||
const subj = new Subject<MessageEvent>();
|
||||
this.clients.set(userId, subj);
|
||||
return subj;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user