Skip to content

Commit 1b31990

Browse files
committed
refactor: extension dispatcher
Signed-off-by: Philippe Martin <[email protected]>
1 parent 5b60084 commit 1b31990

10 files changed

+399
-189
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { ContainerModule } from 'inversify';
20+
import { ActiveResourcesCountDispatcher } from './active-resources-count-dispatcher';
21+
import { ContextsHealthsDispatcher } from './contexts-healths-dispatcher';
22+
import { ContextsPermissionsDispatcher } from './contexts-permissions-dispatcher';
23+
import { ResourcesCountDispatcher } from './resources-count-dispatcher';
24+
25+
const dispatchersModule = new ContainerModule(options => {
26+
options.bind<ActiveResourcesCountDispatcher>(ActiveResourcesCountDispatcher).toSelf().inSingletonScope();
27+
options.bind<ContextsHealthsDispatcher>(ContextsHealthsDispatcher).toSelf().inSingletonScope();
28+
options.bind<ContextsPermissionsDispatcher>(ContextsPermissionsDispatcher).toSelf().inSingletonScope();
29+
options.bind<ResourcesCountDispatcher>(ResourcesCountDispatcher).toSelf().inSingletonScope();
30+
});
31+
32+
export { dispatchersModule };
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { inject, injectable } from 'inversify';
20+
import type { DispatcherObject } from './util/dispatcher-object';
21+
import { AbsDispatcherObjectImpl } from './util/dispatcher-object';
22+
import { ContextsManager } from '../manager/contexts-manager';
23+
import { ACTIVE_RESOURCES_COUNT } from '/@common/channels';
24+
import { RpcExtension } from '/@common/rpc/rpc';
25+
import { ActiveResourcesCountInfo } from '/@common/model/active-resources-count-info';
26+
27+
@injectable()
28+
export class ActiveResourcesCountDispatcher
29+
extends AbsDispatcherObjectImpl<void, ActiveResourcesCountInfo>
30+
implements DispatcherObject<void>
31+
{
32+
@inject(ContextsManager)
33+
private manager: ContextsManager;
34+
35+
constructor(@inject(RpcExtension) rpcExtension: RpcExtension) {
36+
super(rpcExtension, ACTIVE_RESOURCES_COUNT);
37+
}
38+
39+
getData(): ActiveResourcesCountInfo {
40+
return {
41+
counts: this.manager.getActiveResourcesCount(),
42+
};
43+
}
44+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { beforeAll, expect, test, vi } from 'vitest';
20+
import type { ContextHealthState } from '../manager/context-health-checker';
21+
import type { KubeConfigSingleContext } from '../types/kubeconfig-single-context';
22+
import { ContextsHealthsDispatcher } from './contexts-healths-dispatcher';
23+
import { InversifyBinding } from '../inject/inversify-binding';
24+
import type { ExtensionContext, TelemetryLogger } from '@podman-desktop/api';
25+
import type { RpcExtension } from '/@common/rpc/rpc';
26+
import type { Container } from 'inversify';
27+
import { ContextsManager } from '../manager/contexts-manager';
28+
29+
let container: Container;
30+
const contextsManagerMock = {
31+
getHealthCheckersStates: vi.fn(),
32+
isContextOffline: vi.fn(),
33+
} as unknown as ContextsManager;
34+
35+
beforeAll(async () => {
36+
const inversifyBinding = new InversifyBinding({} as RpcExtension, {} as ExtensionContext, {} as TelemetryLogger);
37+
container = await inversifyBinding.initBindings();
38+
(await container.rebind(ContextsManager)).toConstantValue(contextsManagerMock);
39+
});
40+
41+
test('getData should return the values of the map returned by manager.getHealthCheckersStates without kubeConfig', () => {
42+
const dispatcher = container.get<ContextsHealthsDispatcher>(ContextsHealthsDispatcher);
43+
const context1State = {
44+
contextName: 'context1',
45+
checking: true,
46+
reachable: false,
47+
};
48+
const context2State = {
49+
contextName: 'context2',
50+
checking: false,
51+
reachable: true,
52+
};
53+
const context3State = {
54+
contextName: 'context3',
55+
checking: false,
56+
reachable: false,
57+
errorMessage: 'an error',
58+
};
59+
const value = new Map<string, ContextHealthState>([
60+
['context1', { ...context1State, kubeConfig: {} as unknown as KubeConfigSingleContext }],
61+
['context2', { ...context2State, kubeConfig: {} as unknown as KubeConfigSingleContext }],
62+
['context3', { ...context3State, kubeConfig: {} as unknown as KubeConfigSingleContext }],
63+
]);
64+
vi.mocked(contextsManagerMock.getHealthCheckersStates).mockReturnValue(value);
65+
const result = dispatcher.getData();
66+
expect(result).toEqual({ healths: [context1State, context2State, context3State] });
67+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { inject, injectable } from 'inversify';
20+
import type { DispatcherObject } from './util/dispatcher-object';
21+
import { AbsDispatcherObjectImpl } from './util/dispatcher-object';
22+
import { ContextsManager } from '../manager/contexts-manager';
23+
import { CONTEXTS_HEALTHS } from '/@common/channels';
24+
import { ContextHealth } from '/@common/model/kubernetes-contexts-healths';
25+
import { RpcExtension } from '/@common/rpc/rpc';
26+
import { ContextsHealthsInfo } from '/@common/model/contexts-healths-info';
27+
28+
@injectable()
29+
export class ContextsHealthsDispatcher
30+
extends AbsDispatcherObjectImpl<void, ContextsHealthsInfo>
31+
implements DispatcherObject<void>
32+
{
33+
@inject(ContextsManager)
34+
private manager: ContextsManager;
35+
36+
constructor(@inject(RpcExtension) rpcExtension: RpcExtension) {
37+
super(rpcExtension, CONTEXTS_HEALTHS);
38+
}
39+
40+
getData(): ContextsHealthsInfo {
41+
const value: ContextHealth[] = [];
42+
for (const [contextName, health] of this.manager.getHealthCheckersStates()) {
43+
value.push({
44+
contextName,
45+
checking: health.checking,
46+
reachable: health.reachable,
47+
offline: this.manager.isContextOffline(contextName),
48+
errorMessage: health.errorMessage,
49+
});
50+
}
51+
return {
52+
healths: value,
53+
};
54+
}
55+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { inject, injectable } from 'inversify';
20+
import type { DispatcherObject } from './util/dispatcher-object';
21+
import { AbsDispatcherObjectImpl } from './util/dispatcher-object';
22+
import { ContextsManager } from '../manager/contexts-manager';
23+
import { CONTEXTS_PERMISSIONS } from '/@common/channels';
24+
import { RpcExtension } from '/@common/rpc/rpc';
25+
import { ContextsPermissionsInfo } from '/@common/model/contexts-permissions-info';
26+
27+
@injectable()
28+
export class ContextsPermissionsDispatcher
29+
extends AbsDispatcherObjectImpl<void, ContextsPermissionsInfo>
30+
implements DispatcherObject<void>
31+
{
32+
@inject(ContextsManager)
33+
private manager: ContextsManager;
34+
35+
constructor(@inject(RpcExtension) rpcExtension: RpcExtension) {
36+
super(rpcExtension, CONTEXTS_PERMISSIONS);
37+
}
38+
39+
getData(): ContextsPermissionsInfo {
40+
return {
41+
permissions: this.manager.getPermissions(),
42+
};
43+
}
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import { inject, injectable } from 'inversify';
20+
import type { DispatcherObject } from './util/dispatcher-object';
21+
import { AbsDispatcherObjectImpl } from './util/dispatcher-object';
22+
import { ContextsManager } from '../manager/contexts-manager';
23+
import { RESOURCES_COUNT } from '/@common/channels';
24+
import { RpcExtension } from '/@common/rpc/rpc';
25+
import { ResourcesCountInfo } from '/@common/model/resources-count-info';
26+
27+
@injectable()
28+
export class ResourcesCountDispatcher
29+
extends AbsDispatcherObjectImpl<void, ResourcesCountInfo>
30+
implements DispatcherObject<void>
31+
{
32+
@inject(ContextsManager)
33+
private manager: ContextsManager;
34+
35+
constructor(@inject(RpcExtension) rpcExtension: RpcExtension) {
36+
super(rpcExtension, RESOURCES_COUNT);
37+
}
38+
39+
getData(): ResourcesCountInfo {
40+
return {
41+
counts: this.manager.getResourcesCount(),
42+
};
43+
}
44+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**********************************************************************
2+
* Copyright (C) 2025 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
***********************************************************************/
18+
19+
import type { RpcChannel } from '/@common/rpc';
20+
import type { RpcExtension } from '/@common/rpc/rpc';
21+
22+
export interface DispatcherObject<T> {
23+
dispatch(options: T): Promise<void>;
24+
}
25+
26+
// Allow to receive event for a given object
27+
export abstract class AbsDispatcherObjectImpl<T, U> implements DispatcherObject<T> {
28+
#channel: RpcChannel<U>;
29+
30+
constructor(
31+
private rpcExtension: RpcExtension,
32+
channel: RpcChannel<U>,
33+
) {
34+
this.#channel = channel;
35+
}
36+
37+
async dispatch(options?: T): Promise<void> {
38+
await this.rpcExtension.fire(this.#channel, this.getData(options));
39+
}
40+
41+
abstract getData(options?: T): U;
42+
}

packages/extension/src/inject/inversify-binding.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { Container } from 'inversify';
2424
import { ExtensionContextSymbol, TelemetryLoggerSymbol } from '/@/inject/symbol';
2525
import { RpcExtension } from '/@common/rpc/rpc';
2626
import { managersModule } from '/@/manager/_manager-module';
27+
import { dispatchersModule } from '/@/dispatcher/_dispatcher-module';
2728

2829
export class InversifyBinding {
2930
#container: Container | undefined;
@@ -52,6 +53,7 @@ export class InversifyBinding {
5253
this.#container.bind(TelemetryLoggerSymbol).toConstantValue(this.#telemetryLogger);
5354

5455
await this.#container.load(managersModule);
56+
await this.#container.load(dispatchersModule);
5557

5658
return this.#container;
5759
}

0 commit comments

Comments
 (0)