|
1 | 1 | import * as ChildProcess from 'node:child_process'; |
2 | 2 |
|
3 | 3 | import { config } from '../project-configs'; |
| 4 | +import { validateTypeRecordStringUnknown } from '../utils/validator'; |
| 5 | +import { PluginMessage } from './entities/message'; |
4 | 6 | import { Plugin } from './entities/plugin'; |
5 | 7 |
|
6 | 8 | export class PluginIpcBridge { |
7 | 9 |
|
8 | 10 | static async initializePlugin(directory: string, name: string): Promise<Plugin> { |
9 | | - const childProcess = ChildProcess.fork(location + config.defaultPluginEntryPoint); |
| 11 | + const childProcess = ChildProcess.fork( |
| 12 | + directory + '/' + name + config.defaultPluginEntryPoint, |
| 13 | + [], |
| 14 | + { execArgv: ['-r', 'ts-node/register'], silent: true }, |
| 15 | + ); |
10 | 16 | const plugin = new Plugin(directory, name, childProcess); |
| 17 | + |
| 18 | + childProcess.stdout!.on('data', (data) => { |
| 19 | + console.log(data.toString()); |
| 20 | + }); |
| 21 | + |
| 22 | + childProcess.stderr!.on('data', (data) => { |
| 23 | + console.log(data.toString()); |
| 24 | + }) |
| 25 | + |
11 | 26 | await this.initializeResourceDefinitions(plugin); |
12 | 27 |
|
13 | 28 | return plugin; |
14 | 29 | } |
15 | 30 |
|
16 | 31 | static async initializeResourceDefinitions(plugin: Plugin): Promise<void> { |
17 | | - const resourceDefinitions = await this.sendMessageForResult(plugin, 'getResourceDefinitions'); |
| 32 | + const resourceDefinitions = await this.sendMessageForResult(plugin, { cmd: 'getResourceDefinitions' }); |
18 | 33 | plugin.setResourceDefinitions(resourceDefinitions); |
19 | 34 | } |
20 | 35 |
|
21 | | - private static async sendMessageForResult(plugin: Plugin, rpcFunctionName: string): Promise<void> { |
| 36 | + static killPlugin(plugin: Plugin): void { |
| 37 | + plugin.process.kill(); |
| 38 | + } |
| 39 | + |
| 40 | + private static async sendMessageForResult(plugin: Plugin, message: PluginMessage): Promise<unknown> { |
22 | 41 | return new Promise((resolve, reject) => { |
23 | | - setTimeout(() => reject(new Error(`Plugin did respond in 10s to call: ${rpcFunctionName}`)), 10_000); |
24 | | - plugin.process.on(this.getResultFunctionName(rpcFunctionName), (message) => { |
25 | | - resolve(message); |
26 | | - }); |
| 42 | + const timer = setTimeout(() => { |
| 43 | + plugin.process.kill(); |
| 44 | + reject(new Error(`Plugin did not respond in 10s to call: ${message.cmd}`)) |
| 45 | + }, 10_000); |
27 | 46 |
|
28 | | - plugin.process.send(rpcFunctionName); |
| 47 | + const errorListener = (error: Buffer) => { |
| 48 | + plugin.process.kill(); |
| 49 | + reject(error.toString()); |
| 50 | + } |
| 51 | + |
| 52 | + const messageListener = (incomingMessage: unknown) => { |
| 53 | + console.log(incomingMessage); |
| 54 | + |
| 55 | + if (!validateTypeRecordStringUnknown(incomingMessage)) { |
| 56 | + return reject(new Error(`Bad message from plugin ${plugin.name}. ${JSON.stringify(incomingMessage, null, 2)}`)) |
| 57 | + } |
| 58 | + |
| 59 | + if (incomingMessage.cmd === this.getResultFunctionName(message.cmd)) { |
| 60 | + clearTimeout(timer); |
| 61 | + plugin.process.removeListener('message', messageListener); |
| 62 | + plugin.process.removeListener('error', errorListener); |
| 63 | + resolve(incomingMessage.data); |
| 64 | + } |
| 65 | + }; |
| 66 | + |
| 67 | + plugin.process.on('message', messageListener); |
| 68 | + plugin.process.stderr!.on('data', errorListener); |
| 69 | + plugin.process.send(message); |
29 | 70 | }); |
30 | 71 | } |
31 | 72 |
|
| 73 | + private sendMessage(plugin: Plugin, message: PluginMessage): void { |
| 74 | + plugin.process.send(message); |
| 75 | + } |
| 76 | + |
32 | 77 | private static getResultFunctionName(rpcFunctionName: string): string { |
33 | 78 | return rpcFunctionName + 'Result'; |
34 | 79 | } |
|
0 commit comments