Skip to content

Commit 9a2b80f

Browse files
fix: cleanup method per extension type
1 parent 5eb15cc commit 9a2b80f

File tree

4 files changed

+112
-18
lines changed

4 files changed

+112
-18
lines changed

api/src/channel/channel.service.ts

+35-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@
66
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
77
*/
88

9-
import { Injectable, UnauthorizedException } from '@nestjs/common';
9+
import {
10+
Injectable,
11+
OnApplicationBootstrap,
12+
UnauthorizedException,
13+
} from '@nestjs/common';
1014
import { Request, Response } from 'express';
1115

1216
import { SubscriberService } from '@/chat/services/subscriber.service';
1317
import { CONSOLE_CHANNEL_NAME } from '@/extensions/channels/console/settings';
1418
import { WEB_CHANNEL_NAME } from '@/extensions/channels/web/settings';
1519
import { LoggerService } from '@/logger/logger.service';
20+
import { SettingService } from '@/setting/services/setting.service';
1621
import { getSessionStore } from '@/utils/constants/session-store';
1722
import {
1823
SocketGet,
@@ -27,14 +32,42 @@ import ChannelHandler from './lib/Handler';
2732
import { ChannelName } from './types';
2833

2934
@Injectable()
30-
export class ChannelService {
35+
export class ChannelService implements OnApplicationBootstrap {
3136
private registry: Map<string, ChannelHandler<ChannelName>> = new Map();
3237

3338
constructor(
3439
private readonly logger: LoggerService,
40+
private readonly settingService: SettingService,
3541
private readonly subscriberService: SubscriberService,
3642
) {}
3743

44+
async onApplicationBootstrap(): Promise<void> {
45+
await this.cleanup();
46+
}
47+
48+
/**
49+
* Cleanups the unregisterd channels from settings.
50+
*
51+
*/
52+
async cleanup(): Promise<void> {
53+
const activePlugins = this.getAll().map((handler) =>
54+
handler.getNamespace(),
55+
);
56+
57+
const channelSettings = (await this.settingService.getAllGroups()).filter(
58+
(group) => group.split('_').pop() === 'channel',
59+
) as HyphenToUnderscore<ChannelName>[];
60+
61+
const orphanSettings = channelSettings.filter(
62+
(group) => !activePlugins.includes(group),
63+
);
64+
65+
for (const group of orphanSettings) {
66+
this.logger.log(`Deleting orphaned settings for ${group}...`);
67+
await this.settingService.deleteGroup(group);
68+
}
69+
}
70+
3871
/**
3972
* Registers a channel with a specific handler.
4073
*

api/src/extra/index.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,9 @@
11
/*
2-
* Copyright © 2025 Hexastack. All rights reserved.
2+
* Copyright © 2024 Hexastack. All rights reserved.
33
*
44
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
55
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
66
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
77
*/
88

9-
import { Module } from '@nestjs/common';
10-
11-
import { CleanupService } from './cleanup.service';
12-
13-
@Module({
14-
providers: [CleanupService],
15-
})
16-
class CleanupModule {}
17-
18-
export default [CleanupModule];
9+
export default [];

api/src/helper/helper.service.ts

+33-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
77
*/
88

9-
import { Injectable, InternalServerErrorException } from '@nestjs/common';
9+
import {
10+
Injectable,
11+
InternalServerErrorException,
12+
OnApplicationBootstrap,
13+
} from '@nestjs/common';
1014

1115
import { LoggerService } from '@/logger/logger.service';
1216
import { SettingService } from '@/setting/services/setting.service';
@@ -15,7 +19,7 @@ import BaseHelper from './lib/base-helper';
1519
import { HelperName, HelperRegistry, HelperType, TypeOfHelper } from './types';
1620

1721
@Injectable()
18-
export class HelperService {
22+
export class HelperService implements OnApplicationBootstrap {
1923
private registry: HelperRegistry = new Map();
2024

2125
constructor(
@@ -28,6 +32,33 @@ export class HelperService {
2832
});
2933
}
3034

35+
async onApplicationBootstrap(): Promise<void> {
36+
await this.cleanup();
37+
}
38+
39+
/**
40+
* Cleanups the unregisterd helpers from settings.
41+
*
42+
*/
43+
async cleanup(): Promise<void> {
44+
const activeHelpers = this.getAll().map((handler) =>
45+
handler.getNamespace(),
46+
);
47+
48+
const helperSettings = (await this.settingService.getAllGroups()).filter(
49+
(group) => group.split('_').pop() === 'helper',
50+
) as HyphenToUnderscore<HelperName>[];
51+
52+
const orphanSettings = helperSettings.filter(
53+
(group) => !activeHelpers.includes(group),
54+
);
55+
56+
for (const group of orphanSettings) {
57+
this.logger.log(`Deleting orphaned settings for ${group}...`);
58+
await this.settingService.deleteGroup(group);
59+
}
60+
}
61+
3162
/**
3263
* Registers a helper.
3364
*

api/src/plugins/plugins.service.ts

+42-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
77
*/
88

9-
import { Injectable, InternalServerErrorException } from '@nestjs/common';
9+
import {
10+
Injectable,
11+
InternalServerErrorException,
12+
OnApplicationBootstrap,
13+
} from '@nestjs/common';
14+
15+
import { LoggerService } from '@/logger/logger.service';
16+
import { SettingService } from '@/setting/services/setting.service';
1017

1118
import { BasePlugin } from './base-plugin.service';
1219
import { PluginInstance } from './map-types';
@@ -26,7 +33,9 @@ import { PluginName, PluginType } from './types';
2633
* @typeparam T - The plugin type, which extends from `BasePlugin`. By default, it uses `BaseBlockPlugin`.
2734
*/
2835
@Injectable()
29-
export class PluginService<T extends BasePlugin = BasePlugin> {
36+
export class PluginService<T extends BasePlugin = BasePlugin>
37+
implements OnApplicationBootstrap
38+
{
3039
/**
3140
* The registry of plugins, stored as a map where the first key is the type of plugin,
3241
* the second key is the name of the plugin and the value is a plugin of type `T`.
@@ -35,7 +44,37 @@ export class PluginService<T extends BasePlugin = BasePlugin> {
3544
Object.keys(PluginType).map((t) => [t as PluginType, new Map()]),
3645
);
3746

38-
constructor() {}
47+
constructor(
48+
private readonly settingService: SettingService,
49+
private readonly logger: LoggerService,
50+
) {}
51+
52+
async onApplicationBootstrap(): Promise<void> {
53+
await this.cleanup();
54+
}
55+
56+
/**
57+
* Cleanups the unregisterd plugins from settings.
58+
*
59+
*/
60+
async cleanup(): Promise<void> {
61+
const activePlugins = this.getAll().map((handler) =>
62+
handler.getNamespace(),
63+
);
64+
65+
const pluginSettings = (await this.settingService.getAllGroups()).filter(
66+
(group) => group.split('_').pop() === 'plugin',
67+
) as HyphenToUnderscore<PluginName>[];
68+
69+
const orphanSettings = pluginSettings.filter(
70+
(group) => !activePlugins.includes(group),
71+
);
72+
73+
for (const group of orphanSettings) {
74+
this.logger.log(`Deleting orphaned settings for ${group}...`);
75+
await this.settingService.deleteGroup(group);
76+
}
77+
}
3978

4079
/**
4180
* Registers a plugin with a given name.

0 commit comments

Comments
 (0)