import { Controller } from "@nestjs/common"; import { GrpcMethod } from "@nestjs/microservices"; import { PreferencesService } from "../preferences/preferences.service.js"; import { updatePreferencesSchema } from "../preferences/preferences.dto.js"; import type { NotificationPreference } from "../notifications/notifications.schema.js"; /** * PreferencesGrpcController —— gRPC 入口(NotificationPreferenceService 2 RPC)。 * * 仲裁依据: * - msg.proto §NotificationPreferenceService(GetPreferences / UpdatePreferences) * - proto-loader 默认 keepCase=false,字段名 camelCase */ interface GrpcPreference { id: string; userId: string; type: string; channels: string[]; frequencyLimit: number; quietHoursStart: string; quietHoursEnd: string; quietHoursTimezone: string; enabled: boolean; createdAt: number; updatedAt: number; } function opt(val: unknown): string | undefined { if (typeof val === "string" && val.length > 0) return val; return undefined; } function toGrpcPreference(p: NotificationPreference): GrpcPreference { return { id: p.id, userId: p.userId, type: p.type, channels: p.channels, frequencyLimit: p.frequencyLimit ?? 0, quietHoursStart: p.quietHoursStart ?? "", quietHoursEnd: p.quietHoursEnd ?? "", quietHoursTimezone: p.quietHoursTimezone ?? "", enabled: p.enabled, createdAt: p.createdAt instanceof Date ? p.createdAt.getTime() : 0, updatedAt: p.updatedAt instanceof Date ? p.updatedAt.getTime() : 0, }; } @Controller() export class PreferencesGrpcController { constructor(private readonly service: PreferencesService) {} @GrpcMethod("NotificationPreferenceService", "GetPreferences") async getPreferences( data: Record, ): Promise<{ preferences: GrpcPreference[] }> { const prefs = await this.service.getByUserId(String(data.userId ?? "")); return { preferences: prefs.map(toGrpcPreference) }; } @GrpcMethod("NotificationPreferenceService", "UpdatePreferences") async updatePreferences( data: Record, ): Promise> { const rawPrefs = Array.isArray(data.preferences) ? data.preferences : []; const dto = updatePreferencesSchema.parse({ userId: data.userId, preferences: rawPrefs.map((p: Record) => ({ type: p.type, channels: Array.isArray(p.channels) ? p.channels : [], frequencyLimit: p.frequencyLimit ? Number(p.frequencyLimit) : undefined, quietHoursStart: opt(p.quietHoursStart), quietHoursEnd: opt(p.quietHoursEnd), quietHoursTimezone: opt(p.quietHoursTimezone), enabled: p.enabled ?? true, })), }); await this.service.update(dto); return {}; } }