Compare commits

...

15 Commits

Author SHA1 Message Date
idranme
9b32140f87 Merge pull request #470 from LLOneBot/dev
release: 4.0.8
2024-10-13 16:36:12 +08:00
idranme
dc5982c6b2 chore: bump versions 2024-10-13 16:34:35 +08:00
idranme
ce46c99330 fix 2024-10-13 16:32:39 +08:00
idranme
d3abaf806f optimize 2024-10-13 16:32:18 +08:00
idranme
e10a67ce05 Merge pull request #468 from LLOneBot/dev
release: 4.0.7
2024-10-13 01:30:01 +08:00
idranme
c8e897abdb chore: bump versions 2024-10-13 01:29:19 +08:00
idranme
e07c06f3e9 Merge pull request #467 from LLOneBot/dev
...
2024-10-13 01:17:06 +08:00
idranme
9c694a11b5 fix: poke 2024-10-13 01:12:12 +08:00
idranme
6e3bb7c9cf fix 2024-10-13 01:10:39 +08:00
idranme
0d8d3ac24f Merge pull request #466 from LLOneBot/dev
release: 4.0.6
2024-10-13 00:48:36 +08:00
idranme
c96d032820 chore: bump versions 2024-10-13 00:47:31 +08:00
idranme
837f48b63a fix: poke 2024-10-13 00:45:30 +08:00
idranme
9d0f9e7096 Merge pull request #465 from LLOneBot/dev
release: 4.0.5
2024-10-12 23:58:07 +08:00
idranme
801d79d79d chore: bump versions 2024-10-12 23:55:32 +08:00
idranme
0d5640046c feat: poke 2024-10-12 23:50:58 +08:00
19 changed files with 169 additions and 28 deletions

7
.gitattributes vendored
View File

@@ -1,7 +0,0 @@
* text eol=lf
*.png -text
*.jpg -text
*.ico -text
*.gif -text
*.webp -text

View File

@@ -4,7 +4,7 @@
"name": "LLOneBot",
"slug": "LLOneBot",
"description": "实现 OneBot 11 和 Satori 协议,用于 QQ 机器人开发",
"version": "4.0.4",
"version": "4.0.8",
"icon": "./icon.webp",
"authors": [
{

View File

@@ -45,8 +45,11 @@ export class NTQQGroupApi extends Service {
return result.groupList
}
async getGroupMembers(groupCode: string, num = 3000): Promise<Map<string, GroupMember>> {
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{ groupCode, scene: 'groupMemberList_MainWindow' }])
async getGroupMembers(groupCode: string, num = 3000) {
const sceneId = await invoke(NTMethod.GROUP_MEMBER_SCENE, [{
groupCode,
scene: 'groupMemberList_MainWindow'
}])
const data = await invoke(NTMethod.GROUP_MEMBERS, [{ sceneId, num }])
if (data.errCode !== 0) {
throw new Error('获取群成员列表出错,' + data.errMsg)

View File

@@ -263,4 +263,8 @@ export class NTQQMsgApi extends Service {
async getServerTime() {
return await invoke('nodeIKernelMSFService/getServerTime', [])
}
async fetchUnitedCommendConfig(groups: string[]) {
return await invoke('nodeIKernelUnitedConfigService/fetchUnitedCommendConfig', [{ groups }])
}
}

View File

@@ -118,7 +118,7 @@ export class NTQQUserApi extends Service {
await this.ctx.sleep(30)
member = await this.ctx.ntGroupApi.searchMember(groupCode, uin)
}
uid = member.values().find(e => e.uin === uin)?.uid
uid = Array.from(member.values()).find(e => e.uin === uin)?.uid
}
if (!uid) {
const unveifyUid = (await this.getUserDetailInfoByUin(uin)).info.uid

View File

@@ -19,6 +19,7 @@ import {
import { selfInfo, llonebotError } from '../common/globalVars'
import { version } from '../version'
import { invoke } from './ntcall'
import { Native } from './native/index'
declare module 'cordis' {
interface Context {
@@ -38,9 +39,11 @@ declare module 'cordis' {
class Core extends Service {
static inject = ['ntMsgApi', 'ntFriendApi', 'ntGroupApi', 'store']
public startTime = 0
public native
constructor(protected ctx: Context, public config: Core.Config) {
super(ctx, 'app', true)
this.native = new Native(ctx)
}
public start() {

Binary file not shown.

View File

@@ -0,0 +1,54 @@
import { Context } from 'cordis'
import { Dict } from 'cosmokit'
import { getBuildVersion } from '@/common/utils/misc'
import addon from './external/crychic-win32-x64.node?asset'
export class Native {
private crychic?: Dict
constructor(private ctx: Context) {
ctx.on('ready', () => {
this.start()
})
}
checkPlatform() {
return process.platform === 'win32' && process.arch === 'x64'
}
checkVersion() {
const version = getBuildVersion()
// 27187—27597
return version >= 27187 && version < 28060
}
start() {
if (this.crychic) {
return
}
if (!this.checkPlatform()) {
return
}
if (!this.checkVersion()) {
return
}
try {
this.crychic = require(addon)
this.crychic!.init()
} catch (e) {
this.ctx.logger.warn('crychic 加载失败', e)
}
}
async sendFriendPoke(uin: number) {
if (!this.crychic) return
this.crychic.sendFriendPoke(uin)
await this.ctx.ntMsgApi.fetchUnitedCommendConfig(['100243'])
}
async sendGroupPoke(groupCode: number, memberUin: number) {
if (!this.crychic) return
this.crychic.sendGroupPoke(memberUin, groupCode)
await this.ctx.ntMsgApi.fetchUnitedCommendConfig(['100243'])
}
}

View File

@@ -124,7 +124,12 @@ export function invoke<
return new Promise<R>((resolve, reject) => {
const apiArgs = [method, ...args]
const callbackId = randomUUID()
let eventId: string
const timeoutId = setTimeout(() => {
if (eventId) {
removeReceiveHook(eventId)
}
log(`ntqq api timeout ${channel}, ${eventName}, ${method}`, args)
reject(`ntqq api timeout ${channel}, ${eventName}, ${method}, ${JSON.stringify(args)}`)
}, timeout)
@@ -140,16 +145,16 @@ export function invoke<
let result: unknown
// 这里的callback比较特殊QQ后端先返回是否调用成功再返回一条结果数据
const secondCallback = () => {
const hookId = registerReceiveHook<R>(options.cbCmd!, (payload) => {
eventId = registerReceiveHook<R>(options.cbCmd!, (payload) => {
if (options.cmdCB) {
if (options.cmdCB(payload, result)) {
removeReceiveHook(hookId)
removeReceiveHook(eventId)
clearTimeout(timeoutId)
resolve(payload)
}
}
else {
removeReceiveHook(hookId)
removeReceiveHook(eventId)
clearTimeout(timeoutId)
resolve(payload)
}

View File

@@ -294,6 +294,9 @@ export interface GrayTipElement {
jsonGrayTipElement?: {
busiId: string
jsonStr: string
xmlToJsonParam?: {
templParam: Map<string, string>
}
}
}

View File

@@ -17,7 +17,10 @@ class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
protected async _handle(payload: Payload) {
const groupCode = payload.group_id.toString()
let groupMembers = await this.ctx.ntGroupApi.getGroupMembers(groupCode)
if (groupMembers.size === 0) {
for (let i = 0; i < 5; i++) {
if (groupMembers.size > 0) {
break
}
await this.ctx.sleep(100)
groupMembers = await this.ctx.ntGroupApi.getGroupMembers(groupCode)
}

View File

@@ -74,6 +74,8 @@ import { GetGroupNotice } from './go-cqhttp/GetGroupNotice'
import { GetRobotUinRange } from './llonebot/GetRobotUinRange'
import { DeleteFriend } from './go-cqhttp/DeleteFriend'
import { OCRImage } from './go-cqhttp/OCRImage'
import { GroupPoke } from './llonebot/GroupPoke'
import { FriendPoke } from './llonebot/FriendPoke'
export function initActionMap(adapter: Adapter) {
const actionHandlers = [
@@ -92,6 +94,8 @@ export function initActionMap(adapter: Adapter) {
new FetchCustomFace(adapter),
new SetMsgEmojiLike(adapter),
new GetRobotUinRange(adapter),
new GroupPoke(adapter),
new FriendPoke(adapter),
// onebot11
new SendLike(adapter),
new GetMsg(adapter),

View File

@@ -0,0 +1,25 @@
import { BaseAction, Schema } from '../BaseAction'
import { ActionName } from '../types'
import { getBuildVersion } from '@/common/utils/misc'
interface Payload {
user_id: number | string
}
export class FriendPoke extends BaseAction<Payload, null> {
actionName = ActionName.FriendPoke
payloadSchema = Schema.object({
user_id: Schema.union([Number, String]).required()
})
async _handle(payload: Payload) {
if (!this.ctx.app.native.checkPlatform()) {
throw new Error('当前系统平台或架构不支持')
}
if (!this.ctx.app.native.checkVersion()) {
throw new Error(`当前 QQ 版本 ${getBuildVersion()} 不支持,可尝试其他版本 27187—27597`)
}
await this.ctx.app.native.sendFriendPoke(+payload.user_id)
return null
}
}

View File

@@ -0,0 +1,27 @@
import { BaseAction, Schema } from '../BaseAction'
import { ActionName } from '../types'
import { getBuildVersion } from '@/common/utils/misc'
interface Payload {
group_id: number | string
user_id: number | string
}
export class GroupPoke extends BaseAction<Payload, null> {
actionName = ActionName.GroupPoke
payloadSchema = Schema.object({
group_id: Schema.union([Number, String]).required(),
user_id: Schema.union([Number, String]).required()
})
async _handle(payload: Payload) {
if (!this.ctx.app.native.checkPlatform()) {
throw new Error('当前系统平台或架构不支持')
}
if (!this.ctx.app.native.checkVersion()) {
throw new Error(`当前 QQ 版本 ${getBuildVersion()} 不支持,可尝试其他版本 27187—27597`)
}
await this.ctx.app.native.sendGroupPoke(+payload.group_id, +payload.user_id)
return null
}
}

View File

@@ -27,6 +27,8 @@ export enum ActionName {
SendForwardMsg = 'send_forward_msg',
SetMsgEmojiLike = 'set_msg_emoji_like',
GetRobotUinRange = 'get_robot_uin_range',
GroupPoke = 'group_poke',
FriendPoke = 'friend_poke',
// onebot 11
SendLike = 'send_like',
GetLoginInfo = 'get_login_info',

View File

@@ -33,12 +33,13 @@ declare module 'cordis' {
class OneBot11Adapter extends Service {
static inject = [
'ntMsgApi', 'ntFileApi', 'ntFileCacheApi', 'ntFriendApi',
'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi', 'store'
'ntGroupApi', 'ntUserApi', 'ntWindowApi', 'ntWebApi',
'store', 'app'
]
private ob11WebSocket: OB11WebSocket
private ob11WebSocketReverseManager: OB11WebSocketReverseManager
private ob11Http: OB11Http
private ob11HttpPost: OB11HttpPost
private ob11WebSocket
private ob11WebSocketReverseManager
private ob11Http
private ob11HttpPost
constructor(public ctx: Context, public config: OneBot11Adapter.Config) {
super(ctx, 'onebot', true)

View File

@@ -548,14 +548,23 @@ export namespace OB11Entities {
else if (grayTipElement.subElementType == GrayTipElementSubType.JSON) {
const json = JSON.parse(grayTipElement.jsonGrayTipElement!.jsonStr)
if (grayTipElement.jsonGrayTipElement?.busiId === '1061') {
const param = grayTipElement.jsonGrayTipElement.xmlToJsonParam
if (param) {
return new OB11GroupPokeEvent(
Number(msg.peerUid),
Number(param.templParam.get('uin_str1')),
Number(param.templParam.get('uin_str2')),
json.items
)
}
const pokedetail: Dict[] = json.items
//筛选item带有uid的元素
const poke_uid = pokedetail.filter(item => item.uid)
if (poke_uid.length == 2) {
return new OB11GroupPokeEvent(
parseInt(msg.peerUid),
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid) ?? 0),
parseInt(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid) ?? 0),
Number(msg.peerUid),
Number(await ctx.ntUserApi.getUinByUid(poke_uid[0].uid) ?? 0),
Number(await ctx.ntUserApi.getUinByUid(poke_uid[1].uid) ?? 0),
pokedetail
)
}
@@ -665,11 +674,13 @@ export namespace OB11Entities {
}
export function groupMember(group_id: string, member: GroupMember): OB11GroupMember {
const titleExpireTime = +member.specialTitleExpireTime
const int32Max = Math.pow(2, 31) - 1
return {
group_id: parseInt(group_id),
user_id: parseInt(member.uin),
nickname: member.nick,
card: member.cardName,
card: member.cardName || member.nick,
sex: OB11UserSex.Unknown,
age: 0,
area: '',
@@ -677,7 +688,7 @@ export namespace OB11Entities {
qq_level: 0,
join_time: member.joinTime,
last_sent_time: member.lastSpeakTime,
title_expire_time: +member.specialTitleExpireTime,
title_expire_time: titleExpireTime > int32Max ? 0 : titleExpireTime,
unfriendly: false,
card_changeable: true,
is_robot: member.isRobot,

View File

@@ -1 +1 @@
export const version = '4.0.4'
export const version = '4.0.8'

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "ESNext",
"target": "ES2023",
"module": "CommonJS",
"outDir": "./dist",
"strict": true,
@@ -20,7 +20,10 @@
"./src/ntqqapi/*"
]
},
"noEmit": true
"noEmit": true,
"types": [
"electron-vite/node"
]
},
"include": [
"src",