mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-19 05:05:44 +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": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^16.0.3",
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
||||||
"@vitejs/plugin-react-swc": "^4.2.2",
|
"@vitejs/plugin-react-swc": "^4.2.2",
|
||||||
|
"inversify": "^7.10.4",
|
||||||
|
"reflect-metadata": "^0.2.2",
|
||||||
"typescript": "^5.3.0",
|
"typescript": "^5.3.0",
|
||||||
"vite": "^6.4.1",
|
"vite": "^6.4.1",
|
||||||
"vite-plugin-cp": "^6.0.3"
|
"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 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}
|
private readonly EventTask = new Map<string, Map<string, Map<string, InternalMapKey>>>(); // tasks ListenerMainName -> ListenerSubName-> uuid -> {timeout,createtime,func}
|
||||||
|
|
||||||
constructor (
|
constructor(
|
||||||
wrapperSession: NodeIQQNTWrapperSession
|
wrapperSession: NodeIQQNTWrapperSession
|
||||||
) {
|
) {
|
||||||
this.WrapperSession = wrapperSession;
|
this.WrapperSession = wrapperSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
createProxyDispatch (ListenerMainName: string) {
|
createProxyDispatch(ListenerMainName: string) {
|
||||||
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
|
const dispatcherListenerFunc = this.dispatcherListener.bind(this);
|
||||||
return new Proxy(
|
return new Proxy(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
get (target: any, prop: any, receiver: any) {
|
get(target: any, prop: any, receiver: any) {
|
||||||
if (typeof target[prop] === 'undefined') {
|
if (typeof target[prop] === 'undefined') {
|
||||||
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
// 如果方法不存在,返回一个函数,这个函数调用existentMethod
|
||||||
return (...args: any[]) => {
|
return (...args: any[]) => {
|
||||||
@ -54,7 +54,7 @@ export class NTEventWrapper {
|
|||||||
Service extends keyof ServiceNamingMapping,
|
Service extends keyof ServiceNamingMapping,
|
||||||
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||||
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
T extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
||||||
> (eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
>(eventName: `${Service}/${ServiceMethod}`): T | undefined {
|
||||||
const eventNameArr = eventName.split('/');
|
const eventNameArr = eventName.split('/');
|
||||||
type eventType = {
|
type eventType = {
|
||||||
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>>; };
|
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>>; };
|
||||||
@ -78,8 +78,8 @@ export class NTEventWrapper {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
createListenerFunction<T, Listener extends keyof ListenerNamingMapping,
|
createListenerFunction<T, Listener extends keyof ListenerNamingMapping,
|
||||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>> (listenerMainName: string, uniqueCode: string = ''): T {
|
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>>(listenerMainName: string, uniqueCode: string = ''): T {
|
||||||
const existListener = this.listenerManager.get(listenerMainName + uniqueCode);
|
const existListener = this.listenerManager.get(listenerMainName + uniqueCode);
|
||||||
if (!existListener) {
|
if (!existListener) {
|
||||||
const Listener = this.createProxyDispatch(listenerMainName);
|
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)
|
this.EventTask.get(ListenerMainName)
|
||||||
?.get(ListenerSubName)
|
?.get(ListenerSubName)
|
||||||
?.forEach((task, uuid) => {
|
?.forEach((task, uuid) => {
|
||||||
@ -115,7 +115,7 @@ export class NTEventWrapper {
|
|||||||
Service extends keyof ServiceNamingMapping,
|
Service extends keyof ServiceNamingMapping,
|
||||||
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
ServiceMethod extends FuncKeys<ServiceNamingMapping[Service]>,
|
||||||
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>
|
||||||
> (
|
>(
|
||||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||||
...args: Parameters<EventType>
|
...args: Parameters<EventType>
|
||||||
): Promise<Awaited<ReturnType<EventType>>> {
|
): Promise<Awaited<ReturnType<EventType>>> {
|
||||||
@ -126,7 +126,7 @@ export class NTEventWrapper {
|
|||||||
Listener extends keyof ListenerNamingMapping,
|
Listener extends keyof ListenerNamingMapping,
|
||||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
||||||
> (
|
>(
|
||||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||||
checker: (...args: Parameters<ListenerType>) => boolean,
|
checker: (...args: Parameters<ListenerType>) => boolean,
|
||||||
waitTimes = 1,
|
waitTimes = 1,
|
||||||
@ -140,7 +140,7 @@ export class NTEventWrapper {
|
|||||||
let complete = 0;
|
let complete = 0;
|
||||||
let retData: Parameters<ListenerType> | undefined;
|
let retData: Parameters<ListenerType> | undefined;
|
||||||
|
|
||||||
function sendDataCallback () {
|
function sendDataCallback() {
|
||||||
if (complete === 0) {
|
if (complete === 0) {
|
||||||
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
|
reject(new Error(' ListenerName:' + listenerAndMethod + ' timeout'));
|
||||||
} else {
|
} else {
|
||||||
@ -180,7 +180,7 @@ export class NTEventWrapper {
|
|||||||
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
ListenerMethod extends FuncKeys<ListenerNamingMapping[Listener]>,
|
||||||
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
EventType extends (...args: any) => any = EnsureFunc<ServiceNamingMapping[Service][ServiceMethod]>,
|
||||||
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
ListenerType extends (...args: any) => any = EnsureFunc<ListenerNamingMapping[Listener][ListenerMethod]>
|
||||||
> (
|
>(
|
||||||
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
serviceAndMethod: `${Service}/${ServiceMethod}`,
|
||||||
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
listenerAndMethod: `${Listener}/${ListenerMethod}`,
|
||||||
args: Parameters<EventType>,
|
args: Parameters<EventType>,
|
||||||
@ -194,7 +194,7 @@ export class NTEventWrapper {
|
|||||||
let retData: Parameters<ListenerType> | undefined;
|
let retData: Parameters<ListenerType> | undefined;
|
||||||
let retEvent: any = {};
|
let retEvent: any = {};
|
||||||
|
|
||||||
function sendDataCallback (resolve: any, reject: any) {
|
function sendDataCallback(resolve: any, reject: any) {
|
||||||
if (complete === 0) {
|
if (complete === 0) {
|
||||||
reject(
|
reject(
|
||||||
new Error(
|
new Error(
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/napcat-cor
|
|||||||
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
|
import { proxiedListenerOf } from 'napcat-common/src/proxy-handler';
|
||||||
import { NTQQPacketApi } from './apis/packet';
|
import { NTQQPacketApi } from './apis/packet';
|
||||||
import { NativePacketHandler } from './packet/handler/client';
|
import { NativePacketHandler } from './packet/handler/client';
|
||||||
|
import { container, ReceiverServiceRegistry } from './packet/handler/serviceRegister';
|
||||||
export * from './wrapper';
|
export * from './wrapper';
|
||||||
export * from './types/index';
|
export * from './types/index';
|
||||||
export * from './services/index';
|
export * from './services/index';
|
||||||
@ -118,6 +119,15 @@ export class NapCatCore {
|
|||||||
UserApi: new NTQQUserApi(this.context, this),
|
UserApi: new NTQQUserApi(this.context, this),
|
||||||
GroupApi: new NTQQGroupApi(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 () {
|
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[] = [
|
const FrameworkBaseConfigPlugin: PluginOption[] = [
|
||||||
autoIncludeTSPlugin({
|
autoIncludeTSPlugin({
|
||||||
entries: [
|
entries: [
|
||||||
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -19,6 +19,7 @@ const ShellBaseConfigPlugin: PluginOption[] = [
|
|||||||
react({ tsDecorators: true }),
|
react({ tsDecorators: true }),
|
||||||
autoIncludeTSPlugin({
|
autoIncludeTSPlugin({
|
||||||
entries: [
|
entries: [
|
||||||
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-core/protocol') },
|
||||||
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
{ entry: 'napcat.ts', dir: path.resolve(__dirname, '../napcat-onebot/action/test') }
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -12,6 +12,9 @@ export function autoIncludeTSPlugin(options) {
|
|||||||
async buildStart() {
|
async buildStart() {
|
||||||
tsFilesMap = {};
|
tsFilesMap = {};
|
||||||
for (const { entry, dir } of entries) {
|
for (const { entry, dir } of entries) {
|
||||||
|
if (!tsFilesMap[entry]) {
|
||||||
|
tsFilesMap[entry] = [];
|
||||||
|
}
|
||||||
const fullDir = path.resolve(dir);
|
const fullDir = path.resolve(dir);
|
||||||
const allTsFiles = await findTSFiles(fullDir);
|
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