Merge pull request from LLOneBot/dev

release: 4.0.10
This commit is contained in:
idranme 2024-10-15 21:09:42 +08:00 committed by GitHub
commit 951afea794
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 360 additions and 128 deletions

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

@ -12,7 +12,7 @@
"deploy-win": "cmd /c \"xcopy /C /S /Y dist\\* %LITELOADERQQNT_PROFILE%\\plugins\\LLOneBot\\\"", "deploy-win": "cmd /c \"xcopy /C /S /Y dist\\* %LITELOADERQQNT_PROFILE%\\plugins\\LLOneBot\\\"",
"format": "prettier -cw .", "format": "prettier -cw .",
"check": "tsc", "check": "tsc",
"compile:proto": "pbjs --no-create --no-convert --no-encode --no-verify -t static-module -w es6 -p src/ntqqapi/proto -o src/ntqqapi/proto/compiled.js systemMessage.proto profileLikeTip.proto && pbts -o src/ntqqapi/proto/compiled.d.ts src/ntqqapi/proto/compiled.js" "compile:proto": "pbjs --no-create --no-convert --no-encode --no-verify -t static-module -w es6 -p src/ntqqapi/proto -o src/ntqqapi/proto/compiled.js systemMessage.proto profileLikeTip.proto groupMemberIncrease.proto && pbts -o src/ntqqapi/proto/compiled.d.ts src/ntqqapi/proto/compiled.js"
}, },
"author": "", "author": "",
"license": "MIT", "license": "MIT",
@ -43,7 +43,7 @@
"electron-vite": "^2.3.0", "electron-vite": "^2.3.0",
"protobufjs-cli": "^1.1.3", "protobufjs-cli": "^1.1.3",
"typescript": "^5.6.3", "typescript": "^5.6.3",
"vite": "^5.4.8", "vite": "^5.4.9",
"vite-plugin-cp": "^4.0.8" "vite-plugin-cp": "^4.0.8"
}, },
"packageManager": "yarn@4.5.0" "packageManager": "yarn@4.5.0"

@ -1,6 +1,5 @@
export const CHANNEL_GET_CONFIG = 'llonebot_get_config' export const CHANNEL_GET_CONFIG = 'llonebot_get_config'
export const CHANNEL_SET_CONFIG = 'llonebot_set_config' export const CHANNEL_SET_CONFIG = 'llonebot_set_config'
export const CHANNEL_SET_CONFIG_CONFIRMED = 'llonebot_set_config_confirmed'
export const CHANNEL_LOG = 'llonebot_log' export const CHANNEL_LOG = 'llonebot_log'
export const CHANNEL_ERROR = 'llonebot_error' export const CHANNEL_ERROR = 'llonebot_error'
export const CHANNEL_UPDATE = 'llonebot_update' export const CHANNEL_UPDATE = 'llonebot_update'

@ -50,7 +50,7 @@ export class ConfigUtil {
token: '', token: '',
enableLocalFile2Url: false, enableLocalFile2Url: false,
debug: false, debug: false,
log: false, log: true,
autoDeleteFile: false, autoDeleteFile: false,
autoDeleteFileSecond: 60, autoDeleteFileSecond: 60,
musicSignUrl: '', musicSignUrl: '',

@ -15,8 +15,7 @@ import {
CHANNEL_LOG, CHANNEL_LOG,
CHANNEL_SELECT_FILE, CHANNEL_SELECT_FILE,
CHANNEL_SET_CONFIG, CHANNEL_SET_CONFIG,
CHANNEL_UPDATE, CHANNEL_UPDATE
CHANNEL_SET_CONFIG_CONFIRMED
} from '../common/channels' } from '../common/channels'
import { startHook } from '../ntqqapi/hook' import { startHook } from '../ntqqapi/hook'
import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade' import { checkNewVersion, upgradeLLOneBot } from '../common/utils/upgrade'
@ -35,7 +34,6 @@ import {
NTQQWebApi, NTQQWebApi,
NTQQWindowApi NTQQWindowApi
} from '../ntqqapi/api' } from '../ntqqapi/api'
import { mkdir } from 'node:fs/promises'
import { existsSync, mkdirSync } from 'node:fs' import { existsSync, mkdirSync } from 'node:fs'
declare module 'cordis' { declare module 'cordis' {
@ -56,6 +54,29 @@ function onLoad() {
mkdirSync(LOG_DIR) mkdirSync(LOG_DIR)
} }
if (!existsSync(TEMP_DIR)) {
mkdirSync(TEMP_DIR)
}
const dbDir = path.join(DATA_DIR, 'database')
if (!existsSync(dbDir)) {
mkdirSync(dbDir)
}
const ctx = new Context()
ctx.plugin(NTQQFileApi)
ctx.plugin(NTQQFileCacheApi)
ctx.plugin(NTQQFriendApi)
ctx.plugin(NTQQGroupApi)
ctx.plugin(NTQQMsgApi)
ctx.plugin(NTQQUserApi)
ctx.plugin(NTQQWebApi)
ctx.plugin(NTQQWindowApi)
ctx.plugin(Database)
let started = false
ipcMain.handle(CHANNEL_CHECK_VERSION, async () => { ipcMain.handle(CHANNEL_CHECK_VERSION, async () => {
return checkNewVersion() return checkNewVersion()
}) })
@ -114,7 +135,9 @@ function onLoad() {
if (!ask) { if (!ask) {
getConfigUtil().setConfig(config) getConfigUtil().setConfig(config)
log('配置已更新', config) log('配置已更新', config)
checkFfmpeg(config.ffmpeg).then() if (started) {
ctx.parallel('llob/config-updated', config)
}
resolve(true) resolve(true)
return return
} }
@ -131,7 +154,9 @@ function onLoad() {
if (result.response === 0) { if (result.response === 0) {
getConfigUtil().setConfig(config) getConfigUtil().setConfig(config)
log('配置已更新', config) log('配置已更新', config)
checkFfmpeg(config.ffmpeg).then() if (started) {
ctx.parallel('llob/config-updated', config)
}
resolve(true) resolve(true)
} }
}) })
@ -146,61 +171,6 @@ function onLoad() {
log(arg) log(arg)
}) })
async function start() {
log('process pid', process.pid)
const config = getConfigUtil().getConfig()
if (!existsSync(TEMP_DIR)) {
await mkdir(TEMP_DIR)
}
const dbDir = path.join(DATA_DIR, 'database')
if (!existsSync(dbDir)) {
await mkdir(dbDir)
}
const ctx = new Context()
ctx.plugin(Log, {
enable: config.log!,
filename: logFileName
})
ctx.plugin(NTQQFileApi)
ctx.plugin(NTQQFileCacheApi)
ctx.plugin(NTQQFriendApi)
ctx.plugin(NTQQGroupApi)
ctx.plugin(NTQQMsgApi)
ctx.plugin(NTQQUserApi)
ctx.plugin(NTQQWebApi)
ctx.plugin(NTQQWindowApi)
ctx.plugin(Core, config)
ctx.plugin(Database)
ctx.plugin(SQLiteDriver, {
path: path.join(dbDir, `${selfInfo.uin}.db`)
})
ctx.plugin(Store, {
msgCacheExpire: config.msgCacheExpire! * 1000
})
if (config.ob11.enable) {
ctx.plugin(OneBot11Adapter, {
...config.ob11,
heartInterval: config.heartInterval,
token: config.token!,
debug: config.debug!,
musicSignUrl: config.musicSignUrl,
enableLocalFile2Url: config.enableLocalFile2Url!,
ffmpeg: config.ffmpeg,
})
}
if (config.satori.enable) {
ctx.plugin(SatoriAdapter, {
...config.satori,
ffmpeg: config.ffmpeg,
})
}
ctx.start()
llonebotError.otherError = ''
ipcMain.on(CHANNEL_SET_CONFIG_CONFIRMED, (event, config: LLOBConfig) => {
ctx.parallel('llob/config-updated', config)
})
}
const intervalId = setInterval(() => { const intervalId = setInterval(() => {
const self = Object.assign(selfInfo, { const self = Object.assign(selfInfo, {
uin: globalThis.authData?.uin, uin: globalThis.authData?.uin,
@ -209,7 +179,41 @@ function onLoad() {
}) })
if (self.uin) { if (self.uin) {
clearInterval(intervalId) clearInterval(intervalId)
start() log('process pid', process.pid)
const config = getConfigUtil().getConfig()
ctx.plugin(Log, {
enable: config.log!,
filename: logFileName
})
ctx.plugin(SQLiteDriver, {
path: path.join(dbDir, `${selfInfo.uin}.db`)
})
ctx.plugin(Store, {
msgCacheExpire: config.msgCacheExpire! * 1000
})
ctx.plugin(Core, config)
if (config.ob11.enable) {
ctx.plugin(OneBot11Adapter, {
...config.ob11,
heartInterval: config.heartInterval,
token: config.token!,
debug: config.debug!,
musicSignUrl: config.musicSignUrl,
enableLocalFile2Url: config.enableLocalFile2Url!,
ffmpeg: config.ffmpeg,
})
}
if (config.satori.enable) {
ctx.plugin(SatoriAdapter, {
...config.satori,
ffmpeg: config.ffmpeg,
})
}
ctx.start()
started = true
llonebotError.otherError = ''
} }
}, 600) }, 600)
} }

@ -64,11 +64,8 @@ export namespace SysMsg {
/** Properties of a SystemMessageHeader. */ /** Properties of a SystemMessageHeader. */
interface ISystemMessageHeader { interface ISystemMessageHeader {
/** SystemMessageHeader peerNumber */ /** SystemMessageHeader peerUin */
peerNumber?: (number|null); peerUin?: (number|null);
/** SystemMessageHeader peerString */
peerString?: (string|null);
/** SystemMessageHeader uin */ /** SystemMessageHeader uin */
uin?: (number|null); uin?: (number|null);
@ -86,11 +83,8 @@ export namespace SysMsg {
*/ */
constructor(properties?: SysMsg.ISystemMessageHeader); constructor(properties?: SysMsg.ISystemMessageHeader);
/** SystemMessageHeader peerNumber. */ /** SystemMessageHeader peerUin. */
public peerNumber: number; public peerUin: number;
/** SystemMessageHeader peerString. */
public peerString: string;
/** SystemMessageHeader uin. */ /** SystemMessageHeader uin. */
public uin: number; public uin: number;
@ -160,10 +154,10 @@ export namespace SysMsg {
public msgType: number; public msgType: number;
/** SystemMessageMsgSpec subType. */ /** SystemMessageMsgSpec subType. */
public subType: number; public subType?: (number|null);
/** SystemMessageMsgSpec subSubType. */ /** SystemMessageMsgSpec subSubType. */
public subSubType: number; public subSubType?: (number|null);
/** SystemMessageMsgSpec msgSeq. */ /** SystemMessageMsgSpec msgSeq. */
public msgSeq: number; public msgSeq: number;
@ -172,7 +166,7 @@ export namespace SysMsg {
public time: number; public time: number;
/** SystemMessageMsgSpec other. */ /** SystemMessageMsgSpec other. */
public other: number; public other?: (number|null);
/** /**
* Decodes a SystemMessageMsgSpec message from the specified reader or buffer. * Decodes a SystemMessageMsgSpec message from the specified reader or buffer.
@ -466,4 +460,68 @@ export namespace SysMsg {
*/ */
public static getTypeUrl(typeUrlPrefix?: string): string; public static getTypeUrl(typeUrlPrefix?: string): string;
} }
/** Properties of a GroupMemberIncrease. */
interface IGroupMemberIncrease {
/** GroupMemberIncrease groupCode */
groupCode?: (number|null);
/** GroupMemberIncrease memberUid */
memberUid?: (string|null);
/** GroupMemberIncrease type */
type?: (number|null);
/** GroupMemberIncrease adminUid */
adminUid?: (string|null);
}
/** Represents a GroupMemberIncrease. */
class GroupMemberIncrease implements IGroupMemberIncrease {
/**
* Constructs a new GroupMemberIncrease.
* @param [properties] Properties to set
*/
constructor(properties?: SysMsg.IGroupMemberIncrease);
/** GroupMemberIncrease groupCode. */
public groupCode: number;
/** GroupMemberIncrease memberUid. */
public memberUid: string;
/** GroupMemberIncrease type. */
public type: number;
/** GroupMemberIncrease adminUid. */
public adminUid: string;
/**
* Decodes a GroupMemberIncrease message from the specified reader or buffer.
* @param reader Reader or buffer to decode from
* @param [length] Message length if known beforehand
* @returns GroupMemberIncrease
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(reader: ($protobuf.Reader|Uint8Array), length?: number): SysMsg.GroupMemberIncrease;
/**
* Decodes a GroupMemberIncrease message from the specified reader or buffer, length delimited.
* @param reader Reader or buffer to decode from
* @returns GroupMemberIncrease
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decodeDelimited(reader: ($protobuf.Reader|Uint8Array)): SysMsg.GroupMemberIncrease;
/**
* Gets the default type url for GroupMemberIncrease
* @param [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns The default type url
*/
public static getTypeUrl(typeUrlPrefix?: string): string;
}
} }

@ -150,8 +150,7 @@ export const SysMsg = $root.SysMsg = (() => {
* Properties of a SystemMessageHeader. * Properties of a SystemMessageHeader.
* @memberof SysMsg * @memberof SysMsg
* @interface ISystemMessageHeader * @interface ISystemMessageHeader
* @property {number|null} [peerNumber] SystemMessageHeader peerNumber * @property {number|null} [peerUin] SystemMessageHeader peerUin
* @property {string|null} [peerString] SystemMessageHeader peerString
* @property {number|null} [uin] SystemMessageHeader uin * @property {number|null} [uin] SystemMessageHeader uin
* @property {string|null} [uid] SystemMessageHeader uid * @property {string|null} [uid] SystemMessageHeader uid
*/ */
@ -172,20 +171,12 @@ export const SysMsg = $root.SysMsg = (() => {
} }
/** /**
* SystemMessageHeader peerNumber. * SystemMessageHeader peerUin.
* @member {number} peerNumber * @member {number} peerUin
* @memberof SysMsg.SystemMessageHeader * @memberof SysMsg.SystemMessageHeader
* @instance * @instance
*/ */
SystemMessageHeader.prototype.peerNumber = 0; SystemMessageHeader.prototype.peerUin = 0;
/**
* SystemMessageHeader peerString.
* @member {string} peerString
* @memberof SysMsg.SystemMessageHeader
* @instance
*/
SystemMessageHeader.prototype.peerString = "";
/** /**
* SystemMessageHeader uin. * SystemMessageHeader uin.
@ -231,11 +222,7 @@ export const SysMsg = $root.SysMsg = (() => {
let tag = reader.uint32(); let tag = reader.uint32();
switch (tag >>> 3) { switch (tag >>> 3) {
case 1: { case 1: {
message.peerNumber = reader.uint32(); message.peerUin = reader.uint32();
break;
}
case 2: {
message.peerString = reader.string();
break; break;
} }
case 5: { case 5: {
@ -327,19 +314,19 @@ export const SysMsg = $root.SysMsg = (() => {
/** /**
* SystemMessageMsgSpec subType. * SystemMessageMsgSpec subType.
* @member {number} subType * @member {number|null|undefined} subType
* @memberof SysMsg.SystemMessageMsgSpec * @memberof SysMsg.SystemMessageMsgSpec
* @instance * @instance
*/ */
SystemMessageMsgSpec.prototype.subType = 0; SystemMessageMsgSpec.prototype.subType = null;
/** /**
* SystemMessageMsgSpec subSubType. * SystemMessageMsgSpec subSubType.
* @member {number} subSubType * @member {number|null|undefined} subSubType
* @memberof SysMsg.SystemMessageMsgSpec * @memberof SysMsg.SystemMessageMsgSpec
* @instance * @instance
*/ */
SystemMessageMsgSpec.prototype.subSubType = 0; SystemMessageMsgSpec.prototype.subSubType = null;
/** /**
* SystemMessageMsgSpec msgSeq. * SystemMessageMsgSpec msgSeq.
@ -359,11 +346,32 @@ export const SysMsg = $root.SysMsg = (() => {
/** /**
* SystemMessageMsgSpec other. * SystemMessageMsgSpec other.
* @member {number} other * @member {number|null|undefined} other
* @memberof SysMsg.SystemMessageMsgSpec * @memberof SysMsg.SystemMessageMsgSpec
* @instance * @instance
*/ */
SystemMessageMsgSpec.prototype.other = 0; SystemMessageMsgSpec.prototype.other = null;
// OneOf field names bound to virtual getters and setters
let $oneOfFields;
// Virtual OneOf for proto3 optional field
Object.defineProperty(SystemMessageMsgSpec.prototype, "_subType", {
get: $util.oneOfGetter($oneOfFields = ["subType"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(SystemMessageMsgSpec.prototype, "_subSubType", {
get: $util.oneOfGetter($oneOfFields = ["subSubType"]),
set: $util.oneOfSetter($oneOfFields)
});
// Virtual OneOf for proto3 optional field
Object.defineProperty(SystemMessageMsgSpec.prototype, "_other", {
get: $util.oneOfGetter($oneOfFields = ["other"]),
set: $util.oneOfSetter($oneOfFields)
});
/** /**
* Decodes a SystemMessageMsgSpec message from the specified reader or buffer. * Decodes a SystemMessageMsgSpec message from the specified reader or buffer.
@ -1007,6 +1015,141 @@ export const SysMsg = $root.SysMsg = (() => {
return ProfileLikeTip; return ProfileLikeTip;
})(); })();
SysMsg.GroupMemberIncrease = (function() {
/**
* Properties of a GroupMemberIncrease.
* @memberof SysMsg
* @interface IGroupMemberIncrease
* @property {number|null} [groupCode] GroupMemberIncrease groupCode
* @property {string|null} [memberUid] GroupMemberIncrease memberUid
* @property {number|null} [type] GroupMemberIncrease type
* @property {string|null} [adminUid] GroupMemberIncrease adminUid
*/
/**
* Constructs a new GroupMemberIncrease.
* @memberof SysMsg
* @classdesc Represents a GroupMemberIncrease.
* @implements IGroupMemberIncrease
* @constructor
* @param {SysMsg.IGroupMemberIncrease=} [properties] Properties to set
*/
function GroupMemberIncrease(properties) {
if (properties)
for (let keys = Object.keys(properties), i = 0; i < keys.length; ++i)
if (properties[keys[i]] != null)
this[keys[i]] = properties[keys[i]];
}
/**
* GroupMemberIncrease groupCode.
* @member {number} groupCode
* @memberof SysMsg.GroupMemberIncrease
* @instance
*/
GroupMemberIncrease.prototype.groupCode = 0;
/**
* GroupMemberIncrease memberUid.
* @member {string} memberUid
* @memberof SysMsg.GroupMemberIncrease
* @instance
*/
GroupMemberIncrease.prototype.memberUid = "";
/**
* GroupMemberIncrease type.
* @member {number} type
* @memberof SysMsg.GroupMemberIncrease
* @instance
*/
GroupMemberIncrease.prototype.type = 0;
/**
* GroupMemberIncrease adminUid.
* @member {string} adminUid
* @memberof SysMsg.GroupMemberIncrease
* @instance
*/
GroupMemberIncrease.prototype.adminUid = "";
/**
* Decodes a GroupMemberIncrease message from the specified reader or buffer.
* @function decode
* @memberof SysMsg.GroupMemberIncrease
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @param {number} [length] Message length if known beforehand
* @returns {SysMsg.GroupMemberIncrease} GroupMemberIncrease
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
GroupMemberIncrease.decode = function decode(reader, length) {
if (!(reader instanceof $Reader))
reader = $Reader.create(reader);
let end = length === undefined ? reader.len : reader.pos + length, message = new $root.SysMsg.GroupMemberIncrease();
while (reader.pos < end) {
let tag = reader.uint32();
switch (tag >>> 3) {
case 1: {
message.groupCode = reader.uint32();
break;
}
case 3: {
message.memberUid = reader.string();
break;
}
case 4: {
message.type = reader.uint32();
break;
}
case 5: {
message.adminUid = reader.string();
break;
}
default:
reader.skipType(tag & 7);
break;
}
}
return message;
};
/**
* Decodes a GroupMemberIncrease message from the specified reader or buffer, length delimited.
* @function decodeDelimited
* @memberof SysMsg.GroupMemberIncrease
* @static
* @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from
* @returns {SysMsg.GroupMemberIncrease} GroupMemberIncrease
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
GroupMemberIncrease.decodeDelimited = function decodeDelimited(reader) {
if (!(reader instanceof $Reader))
reader = new $Reader(reader);
return this.decode(reader, reader.uint32());
};
/**
* Gets the default type url for GroupMemberIncrease
* @function getTypeUrl
* @memberof SysMsg.GroupMemberIncrease
* @static
* @param {string} [typeUrlPrefix] your custom typeUrlPrefix(default "type.googleapis.com")
* @returns {string} The default type url
*/
GroupMemberIncrease.getTypeUrl = function getTypeUrl(typeUrlPrefix) {
if (typeUrlPrefix === undefined) {
typeUrlPrefix = "type.googleapis.com";
}
return typeUrlPrefix + "/SysMsg.GroupMemberIncrease";
};
return GroupMemberIncrease;
})();
return SysMsg; return SysMsg;
})(); })();

@ -0,0 +1,10 @@
syntax = "proto3";
package SysMsg;
// GroupChange?
message GroupMemberIncrease {
uint32 groupCode = 1;
string memberUid = 3;
uint32 type = 4; // 130: 131:
string adminUid = 5;
}

@ -8,23 +8,22 @@ message SystemMessage {
} }
message SystemMessageHeader { message SystemMessageHeader {
uint32 peerNumber = 1; uint32 peerUin = 1;
string peerString = 2; //string peerUid = 2;
uint32 uin = 5; uint32 uin = 5;
optional string uid = 6; optional string uid = 6;
} }
message SystemMessageMsgSpec { message SystemMessageMsgSpec {
uint32 msgType = 1; uint32 msgType = 1;
uint32 subType = 2; optional uint32 subType = 2;
uint32 subSubType = 3; optional uint32 subSubType = 3;
uint32 msgSeq = 5; uint32 msgSeq = 5;
uint32 time = 6; uint32 time = 6;
//uint64 msgId = 12; //uint64 msgId = 12;
uint32 other = 13; optional uint32 other = 13;
} }
message SystemMessageBodyWrapper { message SystemMessageBodyWrapper {
bytes body = 2; bytes body = 2;
// Find the first [08], or ignore the first 7 bytes? }
}

@ -2,25 +2,27 @@ import { BaseAction, Schema } from '../BaseAction'
import { OB11GroupMember } from '../../types' import { OB11GroupMember } from '../../types'
import { OB11Entities } from '../../entities' import { OB11Entities } from '../../entities'
import { ActionName } from '../types' import { ActionName } from '../types'
import { calcQQLevel } from '@/common/utils/misc' import { calcQQLevel, parseBool } from '@/common/utils/misc'
interface Payload { interface Payload {
group_id: number | string group_id: number | string
user_id: number | string user_id: number | string
no_cache: boolean
} }
class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> { class GetGroupMemberInfo extends BaseAction<Payload, OB11GroupMember> {
actionName = ActionName.GetGroupMemberInfo actionName = ActionName.GetGroupMemberInfo
payloadSchema = Schema.object({ payloadSchema = Schema.object({
group_id: Schema.union([Number, String]).required(), group_id: Schema.union([Number, String]).required(),
user_id: Schema.union([Number, String]).required() user_id: Schema.union([Number, String]).required(),
no_cache: Schema.union([Boolean, Schema.transform(String, parseBool)]).default(false)
}) })
protected async _handle(payload: Payload) { protected async _handle(payload: Payload) {
const groupCode = payload.group_id.toString() const groupCode = payload.group_id.toString()
const uid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString()) const uid = await this.ctx.ntUserApi.getUidByUin(payload.user_id.toString())
if (!uid) throw new Error('无法获取用户信息') if (!uid) throw new Error('无法获取用户信息')
const member = await this.ctx.ntGroupApi.getGroupMember(groupCode, uid) const member = await this.ctx.ntGroupApi.getGroupMember(groupCode, uid, payload.no_cache)
if (member) { if (member) {
const ret = OB11Entities.groupMember(groupCode, member) const ret = OB11Entities.groupMember(groupCode, member)
const date = Math.round(Date.now() / 1000) const date = Math.round(Date.now() / 1000)

@ -23,6 +23,7 @@ import { llonebotError } from '../common/globalVars'
import { OB11GroupAdminNoticeEvent } from './event/notice/OB11GroupAdminNoticeEvent' import { OB11GroupAdminNoticeEvent } from './event/notice/OB11GroupAdminNoticeEvent'
import { OB11ProfileLikeEvent } from './event/notice/OB11ProfileLikeEvent' import { OB11ProfileLikeEvent } from './event/notice/OB11ProfileLikeEvent'
import { SysMsg } from '@/ntqqapi/proto/compiled' import { SysMsg } from '@/ntqqapi/proto/compiled'
import { OB11GroupIncreaseEvent } from './event/notice/OB11GroupIncreaseEvent'
declare module 'cordis' { declare module 'cordis' {
interface Context { interface Context {
@ -349,7 +350,7 @@ class OneBot11Adapter extends Service {
this.ctx.on('nt/friend-request', input => { this.ctx.on('nt/friend-request', input => {
this.handleFriendRequest(input) this.handleFriendRequest(input)
}) })
this.ctx.on('nt/system-message-created', input => { this.ctx.on('nt/system-message-created', async input => {
const sysMsg = SysMsg.SystemMessage.decode(input) const sysMsg = SysMsg.SystemMessage.decode(input)
const { msgType, subType, subSubType } = sysMsg.msgSpec[0] ?? {} const { msgType, subType, subSubType } = sysMsg.msgSpec[0] ?? {}
if (msgType === 528 && subType === 39 && subSubType === 39) { if (msgType === 528 && subType === 39 && subSubType === 39) {
@ -358,8 +359,16 @@ class OneBot11Adapter extends Service {
const detail = tip.content?.msg?.detail const detail = tip.content?.msg?.detail
if (!detail) return if (!detail) return
const [times] = detail.txt?.match(/\d+/) ?? ['0'] const [times] = detail.txt?.match(/\d+/) ?? ['0']
const profileLikeEvent = new OB11ProfileLikeEvent(detail.uin!, detail.nickname!, +times) const event = new OB11ProfileLikeEvent(detail.uin!, detail.nickname!, +times)
this.dispatch(profileLikeEvent) this.dispatch(event)
} else if (msgType === 33) {
const tip = SysMsg.GroupMemberIncrease.decode(sysMsg.bodyWrapper!.body!)
if (tip.type !== 130) return
this.ctx.logger.info('群成员增加', tip)
const memberUin = await this.ctx.ntUserApi.getUinByUid(tip.memberUid)
const operatorUin = await this.ctx.ntUserApi.getUinByUid(tip.adminUid)
const event = new OB11GroupIncreaseEvent(tip.groupCode, +memberUin, +operatorUin)
this.dispatch(event)
} }
}) })
} }

@ -134,11 +134,13 @@ namespace OB11Http {
class OB11HttpPost { class OB11HttpPost {
private disposeInterval?: () => void private disposeInterval?: () => void
private activated = false
constructor(protected ctx: Context, public config: OB11HttpPost.Config) { constructor(protected ctx: Context, public config: OB11HttpPost.Config) {
} }
public start() { public start() {
this.activated = true
if (this.config.enableHttpHeart && !this.disposeInterval) { if (this.config.enableHttpHeart && !this.disposeInterval) {
this.disposeInterval = this.ctx.setInterval(() => { this.disposeInterval = this.ctx.setInterval(() => {
// ws的心跳是ws自己维护的 // ws的心跳是ws自己维护的
@ -148,10 +150,14 @@ class OB11HttpPost {
} }
public stop() { public stop() {
this.activated = false
this.disposeInterval?.() this.disposeInterval?.()
} }
public async emitEvent(event: OB11BaseEvent | OB11Message) { public async emitEvent(event: OB11BaseEvent | OB11Message) {
if (!this.activated) {
return
}
const msgStr = JSON.stringify(event) const msgStr = JSON.stringify(event)
const headers: Dict = { const headers: Dict = {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

@ -423,11 +423,11 @@ export namespace OB11Entities {
const groupElement = grayTipElement?.groupElement const groupElement = grayTipElement?.groupElement
if (groupElement) { if (groupElement) {
if (groupElement.type === TipGroupElementType.MemberIncrease) { if (groupElement.type === TipGroupElementType.MemberIncrease) {
ctx.logger.info('收到群成员增加消息', groupElement) /*ctx.logger.info('', groupElement)
const { memberUid, adminUid } = groupElement const { memberUid, adminUid } = groupElement
const memberUin = await ctx.ntUserApi.getUinByUid(memberUid) const memberUin = await ctx.ntUserApi.getUinByUid(memberUid)
const operatorUin = adminUid ? await ctx.ntUserApi.getUinByUid(adminUid) : memberUin const operatorUin = adminUid ? await ctx.ntUserApi.getUinByUid(adminUid) : memberUin
return new OB11GroupIncreaseEvent(+msg.peerUid, +memberUin, +operatorUin) return new OB11GroupIncreaseEvent(+msg.peerUid, +memberUin, +operatorUin)*/
} }
else if (groupElement.type === TipGroupElementType.Ban) { else if (groupElement.type === TipGroupElementType.Ban) {
ctx.logger.info('收到群成员禁言提示', groupElement) ctx.logger.info('收到群成员禁言提示', groupElement)

@ -7,11 +7,8 @@ import {
CHANNEL_SELECT_FILE, CHANNEL_SELECT_FILE,
CHANNEL_SET_CONFIG, CHANNEL_SET_CONFIG,
CHANNEL_UPDATE, CHANNEL_UPDATE,
CHANNEL_SET_CONFIG_CONFIRMED,
} from './common/channels' } from './common/channels'
import { contextBridge, ipcRenderer } from 'electron'
const { contextBridge } = require('electron')
const { ipcRenderer } = require('electron')
const llonebot = { const llonebot = {
log: (data: unknown) => { log: (data: unknown) => {
@ -24,8 +21,7 @@ const llonebot = {
return ipcRenderer.invoke(CHANNEL_UPDATE) return ipcRenderer.invoke(CHANNEL_UPDATE)
}, },
setConfig: async (ask: boolean, config: Config) => { setConfig: async (ask: boolean, config: Config) => {
const isSuccess = await ipcRenderer.invoke(CHANNEL_SET_CONFIG, ask, config) return ipcRenderer.invoke(CHANNEL_SET_CONFIG, ask, config)
if (isSuccess) ipcRenderer.send(CHANNEL_SET_CONFIG_CONFIRMED, config)
}, },
getConfig: async (): Promise<Config> => { getConfig: async (): Promise<Config> => {
return ipcRenderer.invoke(CHANNEL_GET_CONFIG) return ipcRenderer.invoke(CHANNEL_GET_CONFIG)

@ -25,9 +25,6 @@ async function onSettingWindowCreated(view: Element) {
} else { } else {
Object.assign(config, { [key]: value }) Object.assign(config, { [key]: value })
} }
if (!['heartInterval', 'token', 'ffmpeg'].includes(key)) {
window.llonebot.setConfig(false, config)
}
} }
} }

@ -99,6 +99,15 @@ export class SatoriServer {
} }
public async stop() { public async stop() {
if (this.wsClients.length > 0) {
for (const socket of this.wsClients) {
try {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000)
}
} catch { }
}
}
if (this.wsServer) { if (this.wsServer) {
const close = promisify(this.wsServer.close) const close = promisify(this.wsServer.close)
await close.call(this.wsServer) await close.call(this.wsServer)

@ -1 +1 @@
export const version = '4.0.9' export const version = '4.0.10'