Compare commits

..

10 Commits

Author SHA1 Message Date
手瓜一十雪
389695a0d6 fix: 1.4.5 2024-05-31 21:22:17 +08:00
手瓜一十雪
07f1afb312 fix 2024-05-31 21:03:00 +08:00
手瓜一十雪
ae91e61304 refactor:NTEvent 2024-05-31 21:02:39 +08:00
手瓜一十雪
6248991b01 refactor: NTEvent 2024-05-31 20:38:31 +08:00
手瓜一十雪
7f2d57ef62 refactor: event 2024-05-31 20:29:01 +08:00
手瓜一十雪
31f8f884f1 refactor: NTEvent 2024-05-31 19:09:03 +08:00
手瓜一十雪
4f4af5985a fix: type check & type output 2024-05-31 18:55:18 +08:00
手瓜一十雪
a716fdf6d4 refactor:NTEventDispatch 2024-05-31 14:07:35 +08:00
手瓜一十雪
9717f64abd refactor:NTEvent 2024-05-31 13:55:28 +08:00
手瓜一十雪
adf239183a docs: change 2024-05-31 10:12:59 +08:00
9 changed files with 167 additions and 72 deletions

View File

@@ -0,0 +1,12 @@
# v1.4.5
QQ Version: Windows 9.9.10-24108 / Linux 3.2.7-23361
## 修复与优化
* 紧急修复二维扫码问题
## 新增与调整
新增的 API 详细见[API文档](https://napneko.github.io/zh-CN/develop/extends_api)

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "1.4.4",
"version": "1.4.5",
"scripts": {
"watch:dev": "vite --mode development",
"watch:prod": "vite --mode production",

View File

@@ -1,99 +1,165 @@
import { NodeIKernelMsgListener } from "@/core";
import { NodeIQQNTWrapperSession } from "@/core/wrapper";
import { randomUUID } from "crypto";
export enum NTEventMode {
Once = 1,
Twice = 2
}
export interface NTEventType<U extends (...args: any[]) => any> {
EventName: string,
EventFunction: U,
ListenerName: string,
ListenerFunction: Function
}
interface Internal_MapKey {
mode: NTEventMode,
timeout: number,
createtime: number,
func: Function
}
export class NTEvent<T extends (...args: any[]) => any, R = any> {
EventData: NTEventType<T>;
EventTask: Map<string, Internal_MapKey> = new Map<string, Internal_MapKey>();
constructor(params: NTEventType<T>) {
params.ListenerFunction = this.DispatcherListener.bind(this);
this.EventData = params;
this.EventData.EventFunction = params.EventFunction.bind(this) as any;
export class ListenerClassBase {
[key: string]: string;
}
export class NTEventWrapper {
private ListenerMap: Map<string, typeof ListenerClassBase> | undefined;//ListenerName-Unique -> Listener构造函数
private WrapperSession: NodeIQQNTWrapperSession | undefined;//WrapperSession
private ListenerManger: Map<string, ListenerClassBase> = new Map<string, ListenerClassBase>(); //ListenerName-Unique -> Listener实例
private EventTask: Map<string, Map<string, Internal_MapKey>> = new Map<string, Map<string, Internal_MapKey>>();//tasks ListenerName -> uuid -> {timeout,createtime,func}
private ListenerInit: Map<string, boolean> = new Map<string, boolean>();
constructor() {
}
async DispatcherListener(...args: any[]) {
console.log(...args);
this.EventTask.forEach((task, uuid) => {
init({ ListenerMap, WrapperSession }: { ListenerMap: Map<string, typeof ListenerClassBase>, WrapperSession: NodeIQQNTWrapperSession }) {
this.ListenerMap = ListenerMap;
this.WrapperSession = WrapperSession;
}
CreatEventFunction<T extends (...args: any) => any>(eventName: string): T | undefined {
let eventNameArr = eventName.split('/');
type eventType = {
[key: string]: () => { [key: string]: (...params: Parameters<T>) => Promise<ReturnType<T>> }
}
if (eventNameArr.length > 1) {
let serviceName = 'get' + eventNameArr[0].replace('NodeIKernel', '');
let eventName = eventNameArr[1];
let services = (this.WrapperSession as unknown as eventType)[serviceName]();
let event = services[eventName];
//重新绑定this
event = event.bind(services);
if (event) {
return event as T;
}
return undefined;
}
}
// 获取某个Listener 存在返回 不存在创建
CreatListenerFunction<T>(listenerName: string, uniqueCode: string = ""): T {
let ListenerType = this.ListenerMap!.get(listenerName);
let Listener = this.ListenerManger.get(listenerName + uniqueCode);
if (!Listener && ListenerType) {
Listener = new ListenerType();
let ServiceSubName = listenerName.match(/^NodeIKernel(.*?)Listener$/);
let Service = "NodeIKernel" + ServiceSubName + "Service/addKernel" + ServiceSubName + "Listener";
let addfunc = this.CreatEventFunction<(listener: T) => number>(Service);
addfunc!(Listener as T);
this.ListenerManger.set(listenerName + uniqueCode, Listener);
}
return Listener as T;
}
// 如果存在覆盖注册 不存在则创建Listener
RigisterListener<T extends { [key: string]: (...args: any) => any }>(listenerName: string, uniqueCode: string = "NTEvent", cb: (...args: any) => any) {
let ListenerNameList = listenerName.split('/');
let ListenerMain = ListenerNameList[0];
let ListenerMethod = ListenerNameList[1];
let Listener = this.CreatListenerFunction<T>(ListenerMain, uniqueCode); //uniqueCode NTEvent
(Listener[ListenerMethod] as any) = cb;
}
//初始化Listener回调
initNTListener(ListenerName: string) {
if (this.ListenerInit.get(ListenerName)) {
return;
}
this.RigisterListener(ListenerName, "NTEvent", (...args) => {
console.log('wait... DispatcherListener');
this.DispatcherListener(ListenerName, ...args).then().catch();
})
this.ListenerInit.set(ListenerName, true);
}
//统一回调清理事件
async DispatcherListener(ListenerName: string, ...args: any[]) {
this.EventTask.get(ListenerName)?.forEach((task, uuid) => {
if (task.createtime + task.timeout > Date.now()) {
this.EventTask.delete(uuid);
this.EventTask.get(ListenerName)?.delete(uuid);
return;
}
task.func(...args);
})
}
async CallTwiceEvent(timeout: number = 3000, ...args: Parameters<T>) {
return new Promise<R>((resolve, reject) => {
async CallNoListenerEvent<EventType extends (...args: any[]) => Promise<any>,>(EventName = '', timeout: number = 3000, ...args: Parameters<EventType>) {
return new Promise<ReturnType<EventType>>(async (resolve, reject) => {
let EventFunc = this.CreatEventFunction<EventType>(EventName);
let complete = false;
let Timeouter = setTimeout(() => {
if (!complete) {
reject(new Error('NTEvent EventName:' + EventName + ' timeout'));
}
}, timeout);
let retData = await EventFunc!(...args);
complete = true;
resolve(retData);
});
}
async CallNormalEvent<EventType extends (...args: any[]) => Promise<any>, ListenerType extends (...args: any[]) => void>(EventName = '', ListenerName = '', waitTimes = 1, timeout: number = 3000, ...args: Parameters<EventType>) {
return new Promise<ArrayLike<Parameters<ListenerType>>>(async (resolve, reject) => {
const id = randomUUID();
let complete = 0;
let retData: R | undefined = undefined;
let retData: ArrayLike<Parameters<ListenerType>> | undefined = undefined;
let databack = () => {
if (!complete) {
this.EventTask.delete(id);
reject(new Error('NTEvent EventName:' + this.EventData.EventName + ' EventListener:' + this.EventData.ListenerName + ' timeout'));
if (complete < waitTimes) {
reject(new Error('NTEvent EventName:' + EventName + ' ListenerName:' + ListenerName + ' timeout'));
} else {
resolve(retData as R);
resolve(retData as ArrayLike<Parameters<ListenerType>>);
}
}
this.initNTListener(ListenerName);
let Timeouter = setTimeout(databack, timeout);
let ListenerNameList = ListenerName.split('/');
let ListenerMain = ListenerNameList[0];
let ListenerMethod = ListenerNameList[1];
this.EventTask.set(id, {
mode: NTEventMode.Once,
this.EventTask.get(ListenerMain)?.set(id, {
timeout: timeout,
createtime: Date.now(),
func: (...args: any[]) => {
complete++;
retData = args as R;
if (complete == 2) {
retData = args as ArrayLike<Parameters<ListenerType>>;
if (complete == waitTimes) {
clearTimeout(Timeouter);
databack();
}
}
});
this.EventData.EventFunction(...args);
let EventFunc = this.CreatEventFunction<EventType>(EventName);
await EventFunc!(...args);
});
}
async CallOnceEvent(timeout: number = 3000, ...args: Parameters<T>) {
return new Promise<R>((resolve, reject) => {
const id = randomUUID();
let complete = false;
let retData: R | undefined = undefined;
let databack = () => {
if (!complete) {
this.EventTask.delete(id);
reject(new Error('NTEvent EventName:' + this.EventData.EventName + ' EventListener:' + this.EventData.ListenerName + ' timeout'));
} else {
resolve(retData as R);
}
}
let Timeouter = setTimeout(databack, timeout);
this.EventTask.set(id, {
mode: NTEventMode.Once,
timeout: timeout,
createtime: Date.now(),
func: (...args: any[]) => {
clearTimeout(Timeouter);
complete = true;
retData = args as R;
databack();
}
});
this.EventData.EventFunction(...args);
});
}
}
// 示例代码 快速创建事件
//let NTEvent = new NTEventWrapper();
// let TestEvent = NTEvent.CreatEventFunction<(force: boolean) => Promise<Number>>('NodeIKernelProfileLikeService/GetTest');
// if (TestEvent) {
// TestEvent(true);
// }
// 示例代码 快速创建监听Listener类
// let NTEvent = new NTEventWrapper();
// NTEvent.CreatListenerFunction<NodeIKernelMsgListener>('NodeIKernelMsgListener', 'core')
// 调用接口
//let NTEvent = new NTEventWrapper();
//let ret = await NTEvent.CallNormalEvent<(force: boolean) => Promise<Number>, (data1: string, data2: number) => void>('NodeIKernelProfileLikeService/GetTest', 'NodeIKernelMsgListener/onAddSendMsg', 1, 3000, true);
// 注册监听 解除监听
// NTEventDispatch.RigisterListener('NodeIKernelMsgListener/onAddSendMsg','core',cb);
// NTEventDispatch.UnRigisterListener('NodeIKernelMsgListener/onAddSendMsg','core');
// let GetTest = NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode);
// GetTest('test');
// always模式
// NTEventDispatch.CreatEvent('NodeIKernelProfileLikeService/GetTest','NodeIKernelMsgListener/onAddSendMsg',Mode,(...args:any[])=>{ console.log(args) });

View File

@@ -9,11 +9,12 @@ import { logDebug } from '@/common/utils/log';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { ob11Config } from '@/onebot11/config';
import { dbUtil } from '@/common/utils/db';
import { TypeConvert } from '@/common/utils/type';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: [ 'number' , 'string' ] },
group_id: { type: ['number', 'string'] },
no_cache: { type: ['boolean', 'string'] },
},
required: ['group_id']
@@ -58,12 +59,12 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
MemberData.join_time = webGroupMembers[i]?.join_time;
MemberData.last_sent_time = webGroupMembers[i]?.last_speak_time;
MemberData.qage = webGroupMembers[i]?.qage;
MemberData.level = webGroupMembers[i]?.lv.level;
MemberData.level = webGroupMembers[i]?.lv.level.toString();
MemberMap.set(webGroupMembers[i]?.uin, MemberData);
}
}
} else if (ob11Config.GroupLocalTime.Record && ob11Config.GroupLocalTime.RecordList[0] === '-1' || ob11Config.GroupLocalTime.RecordList.includes(payload.group_id.toString())) {
const _sendAndJoinRember = await dbUtil.getLastSentTimeAndJoinTime(payload.group_id);
const _sendAndJoinRember = await dbUtil.getLastSentTimeAndJoinTime(TypeConvert.toNumber(payload.group_id));
_sendAndJoinRember.forEach((element) => {
let MemberData = MemberMap.get(element.user_id);
if (MemberData) {
@@ -73,6 +74,15 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
});
}
// 还原索引到Array 一同返回
// let retData: any[] = [];
// for (let retMem of MemberMap.values()) {
// retMem.level = TypeConvert.toString(retMem.level) as any;
// retData.push(retMem)
// }
// _groupMembers = Array.from(retData);
_groupMembers = Array.from(MemberMap.values());
return _groupMembers;
}

View File

@@ -506,7 +506,7 @@ export class OB11Constructor {
sex: OB11Constructor.sex(member.sex!),
age: 0,
area: '',
level: 0,
level: '0',
qq_level: member.qqLevel && calcQQLevel(member.qqLevel) || 0,
join_time: 0, // 暂时没法获取
last_sent_time: 0, // 暂时没法获取

View File

@@ -30,7 +30,7 @@ export interface OB11GroupMember {
age?: number
join_time?: number
last_sent_time?: number
level?: number
level?: string
qq_level?: number
role?: OB11GroupMemberRole
title?: string

View File

@@ -1 +1 @@
export const version = '1.4.4';
export const version = '1.4.5';

7
static/assets/qrcode.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -167,7 +167,7 @@ async function onSettingWindowCreated(view) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
void 0,
SettingButton("V1.4.4", "napcat-update-button", "secondary")
SettingButton("V1.4.5", "napcat-update-button", "secondary")
)
]),
SettingList([