mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-12 06:40:58 +04:30
Sync domain SSL status on a 2-hour cron and capture owner FA/EN names.
List pages stay cheap by reading ssl_enabled while Nest probes apex hosts in the background; create-business now stores first/last name in both locales. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
f233665d13
commit
267a218c26
@@ -1,4 +1,4 @@
|
||||
import { Controller, Get, UseGuards } from '@nestjs/common';
|
||||
import { Controller, Get, Post, UseGuards } from '@nestjs/common';
|
||||
import { InternalSslService } from './internal-ssl.service';
|
||||
import { SslSyncTokenGuard } from './ssl-sync-token.guard';
|
||||
|
||||
@@ -18,4 +18,10 @@ export class InternalSslController {
|
||||
listApiHosts() {
|
||||
return this.service.listApiHosts();
|
||||
}
|
||||
|
||||
/** Manually probe apex hosts and sync domains.ssl_enabled. */
|
||||
@Post('refresh-status')
|
||||
refreshStatus() {
|
||||
return this.service.refreshSslStatuses('manual');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Cron, CronExpression } from '@nestjs/schedule';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { probeTlsHosts } from '../common/tls-probe';
|
||||
|
||||
@Injectable()
|
||||
export class InternalSslService {
|
||||
export class InternalSslService implements OnModuleInit {
|
||||
private readonly logger = new Logger(InternalSslService.name);
|
||||
private refreshRunning = false;
|
||||
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly config: ConfigService,
|
||||
) {}
|
||||
|
||||
private async listActiveApexHosts(): Promise<string[]> {
|
||||
const domains = await this.prisma.domain.findMany({
|
||||
onModuleInit() {
|
||||
// Warm ssl_enabled shortly after boot so lists are accurate without waiting for cron.
|
||||
setTimeout(() => {
|
||||
void this.refreshSslStatuses('startup');
|
||||
}, 5_000);
|
||||
}
|
||||
|
||||
private async listActiveDomains(): Promise<Array<{ id: bigint; host: string; sslEnabled: boolean }>> {
|
||||
return this.prisma.domain.findMany({
|
||||
where: { isActive: true },
|
||||
select: { host: true },
|
||||
select: { id: true, host: true, sslEnabled: true },
|
||||
orderBy: { host: 'asc' },
|
||||
});
|
||||
}
|
||||
|
||||
private async listActiveApexHosts(): Promise<string[]> {
|
||||
const domains = await this.listActiveDomains();
|
||||
const hosts: string[] = [];
|
||||
for (const { host } of domains) {
|
||||
const apex = host.trim().toLowerCase();
|
||||
@@ -53,4 +68,51 @@ export class InternalSslService {
|
||||
|
||||
return { hosts: [...hosts].sort() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe each active apex host and sync domains.ssl_enabled to the live result.
|
||||
* Runs every 2 hours (and once shortly after API boot).
|
||||
*/
|
||||
@Cron(CronExpression.EVERY_2_HOURS)
|
||||
async refreshSslStatusesCron() {
|
||||
await this.refreshSslStatuses('cron');
|
||||
}
|
||||
|
||||
async refreshSslStatuses(reason: 'cron' | 'startup' | 'manual' = 'manual') {
|
||||
if (this.refreshRunning) {
|
||||
this.logger.warn(`SSL status refresh skipped (${reason}): already running`);
|
||||
return { updated: 0, checked: 0, skipped: true as const };
|
||||
}
|
||||
|
||||
this.refreshRunning = true;
|
||||
const started = Date.now();
|
||||
try {
|
||||
const domains = await this.listActiveDomains();
|
||||
const sslByHost = await probeTlsHosts(domains.map((d) => d.host));
|
||||
|
||||
let updated = 0;
|
||||
for (const domain of domains) {
|
||||
const hostKey = domain.host.trim().toLowerCase();
|
||||
const sslEnabled = sslByHost.get(hostKey) ?? false;
|
||||
if (sslEnabled === domain.sslEnabled) continue;
|
||||
|
||||
await this.prisma.domain.update({
|
||||
where: { id: domain.id },
|
||||
data: { sslEnabled },
|
||||
});
|
||||
updated += 1;
|
||||
this.logger.log(
|
||||
`SSL status ${domain.host}: ${domain.sslEnabled} → ${sslEnabled}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`SSL status refresh (${reason}): checked=${domains.length} updated=${updated} in ${Date.now() - started}ms`,
|
||||
);
|
||||
|
||||
return { updated, checked: domains.length, skipped: false as const };
|
||||
} finally {
|
||||
this.refreshRunning = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user