fix(plugins): desacoplamiento total en PluginService y gestion agnostica de estado de particiones (v1.24.6)
parent
e8259bb1fc
commit
1ee3b6d465
|
|
@ -1,5 +1,14 @@
|
|||
# Changelog
|
||||
|
||||
## [1.24.6] - 2026-10-31
|
||||
|
||||
### Fixed
|
||||
- **Desacoplamiento Estricto y Sincronización Agnóstica en `PluginService`**:
|
||||
- Eliminadas todas las cadenas hardcodeadas de estados específicos de plugins (`['REMOVING', 'CHECKING', 'FREEZING', 'UNFREEZING']`, `'FREE'`, `'UNFROZEN'`).
|
||||
- Implementada gestión genérica del ciclo de vida de particiones (`handlePartitionClear` y `syncGlobalStatusFromPartitions`): al recibir un estado `NONE` para una partición, se comprueba dinámicamente si al cliente le quedan otras particiones con estado activo; si no queda ninguna, se purga de forma inmediata el estado global en memoria evitando badges fantasma o residuales.
|
||||
- La resolución de badges a nivel de equipo comprueba directamente contra el catálogo declarado por el plugin en su `manifest.json` (`plugin.badges`), eliminando filtros ad-hoc.
|
||||
- El guardado y borrado de metadatos se gestiona de forma agnóstica según la presencia efectiva de datos contextuales en el payload.
|
||||
|
||||
## [1.24.5] - 2026-10-30
|
||||
|
||||
### Added
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "og-webconsole",
|
||||
"version": "1.24.5",
|
||||
"version": "1.24.6",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
|
|
|
|||
|
|
@ -186,6 +186,30 @@ export class PluginService {
|
|||
this.clientPluginMetadataMap.delete(this.getStatusKey(pluginName, idOrUuid));
|
||||
}
|
||||
|
||||
private handlePartitionClear(pluginName: string, idOrUuid: string, disk: number, part: number): void {
|
||||
const partKey = this.getPartitionStatusKey(pluginName, idOrUuid, disk, part);
|
||||
this.clientPluginStatusMap.delete(partKey);
|
||||
this.syncGlobalStatusFromPartitions(pluginName, idOrUuid);
|
||||
}
|
||||
|
||||
private syncGlobalStatusFromPartitions(pluginName: string, idOrUuid: string): void {
|
||||
const prefix = `${pluginName}:${idOrUuid}:`;
|
||||
let remainingStatus: string | null = null;
|
||||
for (const [key, val] of this.clientPluginStatusMap.entries()) {
|
||||
if (key.startsWith(prefix) && val && val !== 'NONE') {
|
||||
remainingStatus = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const globalKey = this.getStatusKey(pluginName, idOrUuid);
|
||||
if (remainingStatus) {
|
||||
this.clientPluginStatusMap.set(globalKey, remainingStatus);
|
||||
} else {
|
||||
this.clientPluginStatusMap.delete(globalKey);
|
||||
}
|
||||
}
|
||||
|
||||
private initMercureSubscription(): void {
|
||||
const mercureUrl = this.configService.mercureUrl;
|
||||
if (!mercureUrl || this.mercureEventSource) {
|
||||
|
|
@ -218,33 +242,27 @@ export class PluginService {
|
|||
if (data.status === 'NONE') {
|
||||
if (data.clientId !== undefined && data.clientId !== null) {
|
||||
const idStr = String(data.clientId);
|
||||
this.clientPluginMetadataMap.delete(this.getStatusKey(data.plugin, idStr));
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
this.clientPluginStatusMap.delete(this.getPartitionStatusKey(data.plugin, idStr, Number(disk), Number(part)));
|
||||
const curGlobal = this.clientPluginStatusMap.get(this.getStatusKey(data.plugin, idStr));
|
||||
if (curGlobal && ['REMOVING', 'CHECKING', 'FREEZING', 'UNFREEZING'].includes(curGlobal.toUpperCase())) {
|
||||
this.clientPluginStatusMap.delete(this.getStatusKey(data.plugin, idStr));
|
||||
}
|
||||
this.handlePartitionClear(data.plugin, idStr, Number(disk), Number(part));
|
||||
} else if (disk !== undefined && disk !== null) {
|
||||
clearEntriesForPrefix(`${data.plugin}:${idStr}:${disk}:`);
|
||||
this.syncGlobalStatusFromPartitions(data.plugin, idStr);
|
||||
} else {
|
||||
this.clientPluginStatusMap.delete(this.getStatusKey(data.plugin, idStr));
|
||||
this.clientPluginMetadataMap.delete(this.getStatusKey(data.plugin, idStr));
|
||||
clearEntriesForPrefix(`${data.plugin}:${idStr}:`);
|
||||
}
|
||||
}
|
||||
if (data.clientUuid) {
|
||||
const uuidStr = data.clientUuid;
|
||||
this.clientPluginMetadataMap.delete(this.getStatusKey(data.plugin, uuidStr));
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
this.clientPluginStatusMap.delete(this.getPartitionStatusKey(data.plugin, uuidStr, Number(disk), Number(part)));
|
||||
const curGlobal = this.clientPluginStatusMap.get(this.getStatusKey(data.plugin, uuidStr));
|
||||
if (curGlobal && ['REMOVING', 'CHECKING', 'FREEZING', 'UNFREEZING'].includes(curGlobal.toUpperCase())) {
|
||||
this.clientPluginStatusMap.delete(this.getStatusKey(data.plugin, uuidStr));
|
||||
}
|
||||
this.handlePartitionClear(data.plugin, uuidStr, Number(disk), Number(part));
|
||||
} else if (disk !== undefined && disk !== null) {
|
||||
clearEntriesForPrefix(`${data.plugin}:${uuidStr}:${disk}:`);
|
||||
this.syncGlobalStatusFromPartitions(data.plugin, uuidStr);
|
||||
} else {
|
||||
this.clientPluginStatusMap.delete(this.getStatusKey(data.plugin, uuidStr));
|
||||
this.clientPluginMetadataMap.delete(this.getStatusKey(data.plugin, uuidStr));
|
||||
clearEntriesForPrefix(`${data.plugin}:${uuidStr}:`);
|
||||
}
|
||||
}
|
||||
|
|
@ -262,9 +280,9 @@ export class PluginService {
|
|||
if (data.clientId !== undefined && data.clientId !== null) {
|
||||
const idStr = String(data.clientId);
|
||||
this.setPluginStatus(data.plugin, idStr, data.status);
|
||||
if (hasMeta && data.status !== 'FREE') {
|
||||
if (hasMeta) {
|
||||
this.setPluginMetadata(data.plugin, idStr, metadata);
|
||||
} else if (data.status === 'FREE') {
|
||||
} else {
|
||||
this.clearPluginMetadata(data.plugin, idStr);
|
||||
}
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
|
|
@ -273,9 +291,9 @@ export class PluginService {
|
|||
}
|
||||
if (data.clientUuid) {
|
||||
this.setPluginStatus(data.plugin, data.clientUuid, data.status);
|
||||
if (hasMeta && data.status !== 'FREE') {
|
||||
if (hasMeta) {
|
||||
this.setPluginMetadata(data.plugin, data.clientUuid, metadata);
|
||||
} else if (data.status === 'FREE') {
|
||||
} else {
|
||||
this.clearPluginMetadata(data.plugin, data.clientUuid);
|
||||
}
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
|
|
@ -416,9 +434,9 @@ export class PluginService {
|
|||
if (id !== undefined && id !== null) {
|
||||
const idStr = String(id);
|
||||
this.setPluginStatus(plugin.name, idStr, status);
|
||||
if (hasMeta && status !== 'FREE') {
|
||||
if (hasMeta) {
|
||||
this.setPluginMetadata(plugin.name, idStr, metadata);
|
||||
} else if (status === 'FREE') {
|
||||
} else {
|
||||
this.clearPluginMetadata(plugin.name, idStr);
|
||||
}
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
|
|
@ -427,9 +445,9 @@ export class PluginService {
|
|||
}
|
||||
if (uuid) {
|
||||
this.setPluginStatus(plugin.name, uuid, status);
|
||||
if (hasMeta && status !== 'FREE') {
|
||||
if (hasMeta) {
|
||||
this.setPluginMetadata(plugin.name, uuid, metadata);
|
||||
} else if (status === 'FREE') {
|
||||
} else {
|
||||
this.clearPluginMetadata(plugin.name, uuid);
|
||||
}
|
||||
if (disk !== undefined && disk !== null && part !== undefined && part !== null) {
|
||||
|
|
@ -686,14 +704,17 @@ export class PluginService {
|
|||
let currentStatus = (idKey ? this.getPluginStatus(plugin.name, idKey) : null)
|
||||
|| (uuidKey ? this.getPluginStatus(plugin.name, uuidKey) : null);
|
||||
|
||||
// 2. Si no hay estado global explícito, buscar si alguna partición del equipo tiene un estado activo
|
||||
// 2. Si no hay estado global explícito, buscar si alguna partición del equipo tiene un estado con badge declarado en el plugin
|
||||
if (!currentStatus) {
|
||||
for (const [key, val] of this.clientPluginStatusMap.entries()) {
|
||||
const isMatch = (idKey && key.startsWith(`${plugin.name}:${idKey}:`)) ||
|
||||
(uuidKey && key.startsWith(`${plugin.name}:${uuidKey}:`));
|
||||
if (isMatch && val && val !== 'NONE' && val !== 'UNFROZEN') {
|
||||
currentStatus = val;
|
||||
break;
|
||||
if (isMatch && val && val !== 'NONE') {
|
||||
const hasBadge = plugin.badges.some(b => b.status.toUpperCase() === val.toUpperCase());
|
||||
if (hasBadge) {
|
||||
currentStatus = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue