mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-18 20:30:08 +08:00
Add service handler registration and DI support
Introduces dependency injection via Inversify and reflect-metadata, adds a service handler registry for packet handling, and updates core initialization to auto-register and bind service handlers. Also updates Vite configs and auto-include logic to support protocol service files.
This commit is contained in:
parent
a2a73ce2dd
commit
f04ffa5dc6
@ -14,6 +14,8 @@
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||
"@vitejs/plugin-react-swc": "^4.2.2",
|
||||
"inversify": "^7.10.4",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"typescript": "^5.3.0",
|
||||
"vite": "^6.4.1",
|
||||
"vite-plugin-cp": "^6.0.3"
|
||||
|
||||
@ -25,18 +25,18 @@ export class NTEventWrapper {
|
||||
private readonly listenerManager: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); // ListenerName-Unique -> Listener实例
|
||||
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); // tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||
|
||||
constructor (
|
||||
constructor(
|
||||
wrapperSession: NodeIQQNTWrapperSession
|
||||
) {
|
||||
this.WrapperSession = wrapperSession;
|
||||
}
|
||||
|
||||
createProxyDispatch (ListenerMainName: string) {
|
||||
createProxyDispatch(ListenerMainName: string) {
|
||||
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get (target: any, prop: any, receiver: any) {
|
||||
get(target: any, prop: any, receiver: any) {
|
||||
if (typeof target[prop] === 'undefined') {
|
||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||
return (...args: any[]) => {
|
||||
@ -54,7 +54,7 @@ export class NTEventWrapper {
|
||||
Service extends keyof ServiceNamingMapping,
|
||||
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
||||
> (eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
||||
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
||||
const eventNameArr = eventName.split('/');
|
||||
type eventType = {
|
||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>>; };
|
||||
@ -78,8 +78,8 @@ export class NTEventWrapper {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
createListenerFunction<T, Listener extends keyof ListenerNamingMapping,
|
||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>> (listenerMainName: string, uniqueCode: string = ''): T {
|
||||
createListenerFunction<T, Listener extends keyof ListenerNamingMapping,
|
||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||
const existListener = this.listenerManager.get(listenerMainName + uniqueCode);
|
||||
if (!existListener) {
|
||||
const Listener = this.createProxyDispatch(listenerMainName);
|
||||
@ -97,7 +97,7 @@ export class NTEventWrapper {
|
||||
}
|
||||
|
||||
// 统一回调清理事件
|
||||
async dispatcherListener (ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||
async dispatcherListener(ListenerMainName: string, ListenerSubName: string, ...args: any[]) {
|
||||
this.EventTask.get(ListenerMainName)
|
||||
?.get(ListenerSubName)
|
||||
?.forEach((task, uuid) => {
|
||||
@ -115,7 +115,7 @@ export class NTEventWrapper {
|
||||
Service extends keyof ServiceNamingMapping,
|
||||
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
||||
> (
|
||||
>(
|
||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||
...args: Parameters<EventType>
|
||||
): Promise<Awaited<ReturnType<EventType>>> {
|
||||
@ -126,7 +126,7 @@ export class NTEventWrapper {
|
||||
Listener extends keyof ListenerNamingMapping,
|
||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
||||
> (
|
||||
>(
|
||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||
waitTimes = 1,
|
||||
@ -140,7 +140,7 @@ export class NTEventWrapper {
|
||||
let complete = 0;
|
||||
let retData: Parameters<ListenerType> | undefined;
|
||||
|
||||
function sendDataCallback () {
|
||||
function sendDataCallback() {
|
||||
if (complete === 0) {
|
||||
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
|
||||
} else {
|
||||
@ -180,7 +180,7 @@ export class NTEventWrapper {
|
||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
||||
> (
|
||||
>(
|
||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||
args: Parameters<EventType>,
|
||||
@ -194,7 +194,7 @@ export class NTEventWrapper {
|
||||
let retData: Parameters<ListenerType> | undefined;
|
||||
let retEvent: any = {};
|
||||
|
||||
function sendDataCallback (resolve: any, reject: any) {
|
||||
function sendDataCallback(resolve: any, reject: any) {
|
||||
if (complete === 0) {
|
||||
reject(
|
||||
new Error(
|
||||
|
||||
@ -31,6 +31,7 @@ import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/napcat-cor
|
||||
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
|
||||
import { NTQQPacketApi } from './apis/packet';
|
||||
import { NativePacketHandler } from './packet/handler/client';
|
||||
import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister';
|
||||
export * from './wrapper';
|
||||
export * from './types/index';
|
||||
export * from './services/index';
|
||||
@ -118,6 +119,15 @@ export class NapCatCore {
|
||||
UserApi: new NTQQUserApi(this.context, this),
|
||||
GroupApi: new NTQQGroupApi(this.context, this),
|
||||
};
|
||||
container.bind(NapCatCore).toConstantValue(this);
|
||||
ReceiverServiceRegistry.forEach((ServiceClass, serviceName) => {
|
||||
container.bind(ServiceClass).toSelf();
|
||||
console.log(`Registering service handler for: ${serviceName}`);
|
||||
this.context.packetHandler.onCmd(serviceName, ({ seq, hex_data }) => {
|
||||
const serviceInstance = container.get(ServiceClass);
|
||||
return serviceInstance.handler(seq, hex_data);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async initCore () {
|
||||
|
||||
24
packages/napcat-core/packet/handler/serviceRegister.ts
Normal file
24
packages/napcat-core/packet/handler/serviceRegister.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import "reflect-metadata";
|
||||
import { Container, injectable } from "inversify";
|
||||
import { NapCatCore } from "../..";
|
||||
|
||||
export const container = new Container();
|
||||
|
||||
export const ReceiverServiceRegistry = new Map<string, new (...args: any[]) => ServiceBase>();
|
||||
|
||||
export abstract class ServiceBase {
|
||||
get core(): NapCatCore {
|
||||
return container.get(NapCatCore);
|
||||
}
|
||||
|
||||
abstract handler(seq: number, hex_data: string): Promise<void> | void;
|
||||
}
|
||||
|
||||
export function ReceiveService(serviceName: string) {
|
||||
return function <T extends new (...args: any[]) => ServiceBase>(constructor: T) {
|
||||
injectable()(constructor);
|
||||
ReceiverServiceRegistry.set(serviceName, constructor);
|
||||
return constructor;
|
||||
};
|
||||
}
|
||||
|
||||
8
packages/napcat-core/protocol/OlpushSerivce.ts
Normal file
8
packages/napcat-core/protocol/OlpushSerivce.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { ReceiveService, ServiceBase } from "../packet/handler/serviceRegister";
|
||||
|
||||
// @ReceiveService('trpc.msg.olpush.OlPushService.MsgPush')
|
||||
// export class OlPushService extends ServiceBase {
|
||||
// async handler(seq: number, hex_data: string) {
|
||||
// console.log(`OlPushService handler called with seq: ${seq} and data: ${hex_data}`);
|
||||
// }
|
||||
// }
|
||||
@ -16,6 +16,7 @@ const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].
|
||||
const FrameworkBaseConfigPlugin: PluginOption[] = [
|
||||
autoIncludeTSPlugin({
|
||||
entries: [
|
||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
||||
]
|
||||
}),
|
||||
|
||||
@ -19,6 +19,7 @@ const ShellBaseConfigPlugin: PluginOption[] = [
|
||||
react({ tsDecorators: true }),
|
||||
autoIncludeTSPlugin({
|
||||
entries: [
|
||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
||||
]
|
||||
}),
|
||||
|
||||
@ -12,6 +12,9 @@ export function autoIncludeTSPlugin(options) {
|
||||
async buildStart() {
|
||||
tsFilesMap = {};
|
||||
for (const { entry, dir } of entries) {
|
||||
if (!tsFilesMap[entry]) {
|
||||
tsFilesMap[entry] = [];
|
||||
}
|
||||
const fullDir = path.resolve(dir);
|
||||
const allTsFiles = await findTSFiles(fullDir);
|
||||
|
||||
@ -29,7 +32,7 @@ export function autoIncludeTSPlugin(options) {
|
||||
}
|
||||
});
|
||||
|
||||
tsFilesMap[entry] = validFiles;
|
||||
tsFilesMap[entry].push(...validFiles);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user