|
|
|
@ -5,6 +5,8 @@ import { Metrics } from './metrics';
|
|
|
|
|
|
|
|
|
|
|
|
export class IdentityService {
|
|
|
|
export class IdentityService {
|
|
|
|
static dbInstance: Database = db;
|
|
|
|
static dbInstance: Database = db;
|
|
|
|
|
|
|
|
// Caché en memoria como respaldo si la tabla user_aliases no está disponible (tests o migraciones incompletas)
|
|
|
|
|
|
|
|
private static readonly inMemoryAliases = new Map<string, string>();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Registra o actualiza un alias (LID u otro identificador) apuntando al user_id real (número).
|
|
|
|
* Registra o actualiza un alias (LID u otro identificador) apuntando al user_id real (número).
|
|
|
|
@ -23,11 +25,13 @@ export class IdentityService {
|
|
|
|
source = COALESCE(excluded.source, source),
|
|
|
|
source = COALESCE(excluded.source, source),
|
|
|
|
updated_at = excluded.updated_at
|
|
|
|
updated_at = excluded.updated_at
|
|
|
|
`).run(a, u, source ?? null);
|
|
|
|
`).run(a, u, source ?? null);
|
|
|
|
try { Metrics.inc('identity_alias_upserts_total'); } catch {}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
} catch {
|
|
|
|
} catch {
|
|
|
|
return false;
|
|
|
|
// Si la tabla no existe o hay error de DB, continuamos con la caché en memoria
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Actualizar siempre la caché en memoria para disponibilizar el alias inmediatamente
|
|
|
|
|
|
|
|
this.inMemoryAliases.set(a, u);
|
|
|
|
|
|
|
|
try { Metrics.inc('identity_alias_upserts_total'); } catch {}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
@ -36,15 +40,29 @@ export class IdentityService {
|
|
|
|
static resolveAliasOrNull(id: string | null | undefined): string | null {
|
|
|
|
static resolveAliasOrNull(id: string | null | undefined): string | null {
|
|
|
|
const n = normalizeWhatsAppId(id || '');
|
|
|
|
const n = normalizeWhatsAppId(id || '');
|
|
|
|
if (!n) return null;
|
|
|
|
if (!n) return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Primero, comprobar la caché en memoria
|
|
|
|
|
|
|
|
const mem = this.inMemoryAliases.get(n);
|
|
|
|
|
|
|
|
if (mem) {
|
|
|
|
|
|
|
|
try { Metrics.inc('identity_alias_resolved_total'); } catch {}
|
|
|
|
|
|
|
|
return mem;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Después, intentar en la base de datos
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
const row = this.dbInstance.prepare(`SELECT user_id FROM user_aliases WHERE alias = ?`).get(n) as any;
|
|
|
|
const row = this.dbInstance.prepare(`SELECT user_id FROM user_aliases WHERE alias = ?`).get(n) as any;
|
|
|
|
if (row?.user_id) {
|
|
|
|
if (row?.user_id) {
|
|
|
|
|
|
|
|
const v = String(row.user_id);
|
|
|
|
|
|
|
|
// Mantener caché en memoria para futuras resoluciones rápidas
|
|
|
|
|
|
|
|
this.inMemoryAliases.set(n, v);
|
|
|
|
try { Metrics.inc('identity_alias_resolved_total'); } catch {}
|
|
|
|
try { Metrics.inc('identity_alias_resolved_total'); } catch {}
|
|
|
|
return String(row.user_id);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try { Metrics.inc('identity_alias_unresolved_total'); } catch {}
|
|
|
|
try { Metrics.inc('identity_alias_unresolved_total'); } catch {}
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
} catch {
|
|
|
|
} catch {
|
|
|
|
|
|
|
|
// En caso de error de DB, consideramos no resuelto
|
|
|
|
|
|
|
|
try { Metrics.inc('identity_alias_unresolved_total'); } catch {}
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|