feat: add GET /api/v2/scenes endpoint
- load.controller.ts exposing listScenes() - adjusted AppModule to register LoadController - multi-stage Dockerfile now copies compiled dist/ - synced package-lock.json and installed redis types - fixed iterator usage in storage.service
This commit is contained in:
parent
08caa4cefc
commit
546f321ff0
@ -1,3 +1,18 @@
|
||||
# ignore everything by default
|
||||
*
|
||||
!package*.json
|
||||
!dist
|
||||
|
||||
# keep package manifests so we can install deps
|
||||
!package.json
|
||||
!package-lock.json
|
||||
|
||||
# keep your Nest build config
|
||||
!nest-cli.json
|
||||
!tsconfig.json
|
||||
!tsconfig.build.json
|
||||
|
||||
# keep source code
|
||||
!src/**
|
||||
|
||||
# ignore node_modules and any pre-existing dist output
|
||||
node_modules
|
||||
dist
|
||||
|
27
Dockerfile.override
Normal file
27
Dockerfile.override
Normal file
@ -0,0 +1,27 @@
|
||||
# --- Builder stage ----------------------------------------------------------
|
||||
FROM node:16-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Install dev+prod dependencies and build TS
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# --- Runtime stage ----------------------------------------------------------
|
||||
FROM node:16-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Bring in package manifests so npm can locate the start script
|
||||
COPY --from=builder /app/package*.json ./
|
||||
|
||||
# Bring in only production deps and compiled output
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
# Drop to non-root user
|
||||
USER node
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT ["npm", "run", "start:prod"]
|
@ -34,7 +34,8 @@
|
||||
"nanoid": "^3.1.25",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"rxjs": "^7.2.0"
|
||||
"rxjs": "^7.2.0",
|
||||
"redis": "^4.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^8.0.0",
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { MiddlewareConsumer, Module } from '@nestjs/common';
|
||||
import { RawParserMiddleware } from './raw-parser.middleware';
|
||||
import { ScenesController } from './scenes/scenes.controller';
|
||||
import { LoadController } from './scenes/load.controller';
|
||||
import { StorageService } from './storage/storage.service';
|
||||
import { RoomsController } from './rooms/rooms.controller';
|
||||
import { FilesController } from './files/files.controller';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [ScenesController, RoomsController, FilesController],
|
||||
controllers: [
|
||||
ScenesController,
|
||||
LoadController,
|
||||
RoomsController,
|
||||
FilesController,
|
||||
],
|
||||
providers: [StorageService],
|
||||
})
|
||||
export class AppModule {
|
||||
|
60
src/scenes/load.controller.ts
Normal file
60
src/scenes/load.controller.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import { Controller, Get, Logger, InternalServerErrorException } from '@nestjs/common';
|
||||
import { createClient } from 'redis';
|
||||
import { StorageNamespace } from 'src/storage/storage.service';
|
||||
|
||||
@Controller('scenes')
|
||||
export class LoadController {
|
||||
private readonly logger = new Logger(LoadController.name);
|
||||
|
||||
// Initialize Redis client once
|
||||
private client = createClient({ url: process.env.STORAGE_URI });
|
||||
|
||||
constructor() {
|
||||
this.client.on('error', (err) => {
|
||||
this.logger.error('Redis client error', err);
|
||||
});
|
||||
this.client.connect().catch((err) => {
|
||||
this.logger.error('Failed to connect Redis client', err);
|
||||
});
|
||||
}
|
||||
|
||||
@Get()
|
||||
async listScenes() {
|
||||
try {
|
||||
const prefix = `${StorageNamespace.SCENES}:`;
|
||||
|
||||
// 1) list all keys
|
||||
const keys = await this.client.keys(`${prefix}*`);
|
||||
this.logger.debug(`Found ${keys.length} scene keys`);
|
||||
|
||||
// 2) pipeline a GET for each key
|
||||
const pipeline = this.client.multi();
|
||||
for (const k of keys) {
|
||||
pipeline.get(k);
|
||||
}
|
||||
// pipeline.exec() on redis v4 returns an array of reply values
|
||||
const raws = (await pipeline.exec()) as (string | null)[];
|
||||
|
||||
// 3) build summaries
|
||||
const scenes = keys
|
||||
.map((fullKey, idx) => {
|
||||
const raw = raws[idx];
|
||||
if (!raw) return null;
|
||||
try {
|
||||
const payload = JSON.parse(raw);
|
||||
const id = fullKey.slice(prefix.length);
|
||||
return { id, created: payload.created, updated: payload.updated };
|
||||
} catch {
|
||||
this.logger.warn(`Skipping invalid JSON at ${fullKey}`);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter((s) => s !== null);
|
||||
|
||||
return scenes;
|
||||
} catch (err) {
|
||||
this.logger.error('Error listing scenes', err as any);
|
||||
throw new InternalServerErrorException('Failed to list scenes');
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user