forked from Yara724/api
133 lines
4.1 KiB
TypeScript
133 lines
4.1 KiB
TypeScript
import { Injectable, Logger, OnModuleInit } from "@nestjs/common";
|
|
import { InjectModel } from "@nestjs/mongoose";
|
|
import { Model } from "mongoose";
|
|
import {
|
|
FANAVARAN_CLIENT_KEYS,
|
|
SEED_FANAVARAN_CLIENT_PROFILES,
|
|
getFanavaranClientProfile,
|
|
setFanavaranClientProfilesCache,
|
|
type FanavaranClientKey,
|
|
type FanavaranClientProfile,
|
|
} from "src/core/config/fanavaran-client.config";
|
|
import { FanavaranAuthService } from "./fanavaran-auth.service";
|
|
import {
|
|
FanavaranClientConfig,
|
|
FanavaranClientConfigDocument,
|
|
} from "./schema/fanavaran-client-config.schema";
|
|
|
|
/**
|
|
* Loads / seeds per-tenant Fanavaran auth+defaults from Mongo and exposes them
|
|
* through the sync helpers in fanavaran-client.config.ts.
|
|
*
|
|
* Boot behaviour: for each known client key, if no document exists, insert the
|
|
* seed profile. Existing documents are never overwritten (ops can edit Mongo).
|
|
*/
|
|
@Injectable()
|
|
export class FanavaranClientConfigService implements OnModuleInit {
|
|
private readonly logger = new Logger(FanavaranClientConfigService.name);
|
|
|
|
constructor(
|
|
@InjectModel(FanavaranClientConfig.name)
|
|
private readonly configModel: Model<FanavaranClientConfigDocument>,
|
|
private readonly fanavaranAuthService: FanavaranAuthService,
|
|
) {}
|
|
|
|
async onModuleInit(): Promise<void> {
|
|
await this.seedMissingProfiles();
|
|
await this.reloadCache();
|
|
}
|
|
|
|
async seedMissingProfiles(): Promise<void> {
|
|
for (const key of FANAVARAN_CLIENT_KEYS) {
|
|
const seed = SEED_FANAVARAN_CLIENT_PROFILES[key];
|
|
const existing = await this.configModel
|
|
.findOne({ key })
|
|
.select({ _id: 1 })
|
|
.lean()
|
|
.exec();
|
|
if (existing) {
|
|
continue;
|
|
}
|
|
await this.configModel.create({
|
|
key: seed.key,
|
|
auth: seed.auth,
|
|
defaults: seed.defaults,
|
|
});
|
|
this.logger.log(
|
|
`Seeded fanavaranClientConfigs for client "${key}" (ClaimExpertId=${seed.defaults.ClaimExpertId}, ExpertiseClaimExpertId=${seed.defaults.ExpertiseClaimExpertId})`,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Re-read Mongo into the runtime profile cache. If any tenant's auth block
|
|
* changed (location, credentials, …), drop cached Fanavaran tokens so the
|
|
* next call re-logins instead of waiting for Tehran midnight.
|
|
*/
|
|
async reloadCache(): Promise<void> {
|
|
const previousFingerprints = new Map<FanavaranClientKey, string>();
|
|
for (const key of FANAVARAN_CLIENT_KEYS) {
|
|
try {
|
|
previousFingerprints.set(
|
|
key,
|
|
FanavaranAuthService.authFingerprint(
|
|
getFanavaranClientProfile(key).auth,
|
|
),
|
|
);
|
|
} catch {
|
|
// First boot / empty cache — nothing to compare.
|
|
}
|
|
}
|
|
|
|
const docs = await this.configModel.find().lean().exec();
|
|
const cache: Partial<Record<FanavaranClientKey, FanavaranClientProfile>> =
|
|
{};
|
|
|
|
for (const key of FANAVARAN_CLIENT_KEYS) {
|
|
const doc = docs.find((row) => row.key === key);
|
|
if (doc?.auth && doc?.defaults) {
|
|
cache[key] = {
|
|
key,
|
|
auth: {
|
|
appName: doc.auth.appName,
|
|
secret: doc.auth.secret,
|
|
username: doc.auth.username,
|
|
password: doc.auth.password,
|
|
corpId: doc.auth.corpId,
|
|
contractId: doc.auth.contractId,
|
|
location: doc.auth.location,
|
|
},
|
|
defaults: { ...doc.defaults },
|
|
};
|
|
} else {
|
|
cache[key] = SEED_FANAVARAN_CLIENT_PROFILES[key];
|
|
}
|
|
}
|
|
|
|
setFanavaranClientProfilesCache(cache);
|
|
|
|
for (const key of FANAVARAN_CLIENT_KEYS) {
|
|
const next = FanavaranAuthService.authFingerprint(cache[key]!.auth);
|
|
const prev = previousFingerprints.get(key);
|
|
if (prev && prev !== next) {
|
|
this.logger.warn(
|
|
`[${key}] Fanavaran auth config changed — invalidating cached authenticationToken`,
|
|
);
|
|
this.fanavaranAuthService.invalidateToken(key);
|
|
}
|
|
}
|
|
|
|
this.logger.log(
|
|
`Loaded ${docs.length} Fanavaran client config(s) from Mongo into runtime cache`,
|
|
);
|
|
}
|
|
|
|
async findByKey(key: FanavaranClientKey) {
|
|
return this.configModel.findOne({ key }).lean().exec();
|
|
}
|
|
|
|
async list() {
|
|
return this.configModel.find().lean().exec();
|
|
}
|
|
}
|