Compare commits

...

13 Commits

Author SHA1 Message Date
linyuchen
55d046b4f9 fix: reply msg id 2024-03-07 14:18:24 +08:00
linyuchen
ac417cedd3 fix: reply msg id 2024-03-07 10:43:17 +08:00
linyuchen
ade509f26d perf: 优化数据库缓存 2024-03-07 09:00:22 +08:00
linyuchen
a66c1a9779 Merge remote-tracking branch 'origin/main' 2024-03-06 23:33:35 +08:00
linyuchen
239cf18887 fix: init db failed 2024-03-06 23:33:19 +08:00
linyuchen
936554cca2 chore: ver 3.13.2 2024-03-06 22:57:36 +08:00
linyuchen
e1d47f55bf fix: hotfix db initialize failed 2024-03-06 22:55:33 +08:00
linyuchen
cc8e8f108b docs: update readme, file msg add new field name 2024-03-06 22:02:11 +08:00
linyuchen
e6d36dc6c3 fix: send video filename
fix: send msg don't return message_id on Linux
2024-03-06 21:14:13 +08:00
linyuchen
aedc8cfc91 Merge branch 'main' into dev 2024-03-06 20:30:59 +08:00
linyuchen
00c80bf181 feat: send file api add name field 2024-03-06 20:30:26 +08:00
linyuchen
72890a8b59 Merge pull request #111 from lgc2333/patch-1
fix typo
2024-03-06 19:48:53 +08:00
student_2333
3b2577bcad fix typo 2024-03-06 19:46:15 +08:00
21 changed files with 328 additions and 283 deletions

View File

@@ -92,7 +92,8 @@ wget -O fastboot.sh https://cdn.jsdelivr.net/gh/LLOneBot/llonebot-docker/fastboo
{ {
"type": "file", "type": "file",
"data": { "data": {
"file": "file:///D:/1.txt" "file": "file:///D:/1.txt",
"name": "自定义显示的文件名" // 此字段不是必须的
} }
} }
``` ```

View File

@@ -1,10 +1,10 @@
{ {
"manifest_version": 4, "manifest_version": 4,
"type": "extension", "type": "extension",
"name": "LLOneBot v3.12.0", "name": "LLOneBot v3.13.4",
"slug": "LLOneBot", "slug": "LLOneBot",
"description": "LiteLoaderQQNT的OneBotApi", "description": "LiteLoaderQQNT的OneBotApi",
"version": "3.12.0", "version": "3.13.4",
"thumbnail": "./icon.png", "thumbnail": "./icon.png",
"authors": [ "authors": [
{ {

194
package-lock.json generated
View File

@@ -986,16 +986,6 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@eslint/eslintrc/node_modules/globals": { "node_modules/@eslint/eslintrc/node_modules/globals": {
"version": "13.24.0", "version": "13.24.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/globals/-/globals-13.24.0.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/globals/-/globals-13.24.0.tgz",
@@ -1011,18 +1001,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@eslint/eslintrc/node_modules/type-fest": { "node_modules/@eslint/eslintrc/node_modules/type-fest": {
"version": "0.20.2", "version": "0.20.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/type-fest/-/type-fest-0.20.2.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/type-fest/-/type-fest-0.20.2.tgz",
@@ -1058,28 +1036,6 @@
"node": ">=10.10.0" "node": ">=10.10.0"
} }
}, },
"node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/@humanwhocodes/module-importer": { "node_modules/@humanwhocodes/module-importer": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://mirrors.cloud.tencent.com/npm/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
@@ -3225,16 +3181,6 @@
"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
} }
}, },
"node_modules/eslint-plugin-import/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": { "node_modules/eslint-plugin-import/node_modules/debug": {
"version": "3.2.7", "version": "3.2.7",
"resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-3.2.7.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-3.2.7.tgz",
@@ -3256,18 +3202,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/eslint-plugin-import/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint-plugin-n": { "node_modules/eslint-plugin-n": {
"version": "16.6.2", "version": "16.6.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
@@ -3296,16 +3230,6 @@
"eslint": ">=7.0.0" "eslint": ">=7.0.0"
} }
}, },
"node_modules/eslint-plugin-n/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint-plugin-n/node_modules/globals": { "node_modules/eslint-plugin-n/node_modules/globals": {
"version": "13.24.0", "version": "13.24.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/globals/-/globals-13.24.0.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/globals/-/globals-13.24.0.tgz",
@@ -3321,18 +3245,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/eslint-plugin-n/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint-plugin-n/node_modules/semver": { "node_modules/eslint-plugin-n/node_modules/semver": {
"version": "7.6.0", "version": "7.6.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/semver/-/semver-7.6.0.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/semver/-/semver-7.6.0.tgz",
@@ -3384,16 +3296,6 @@
"url": "https://opencollective.com/eslint" "url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/eslint/node_modules/eslint-scope": { "node_modules/eslint/node_modules/eslint-scope": {
"version": "7.2.2", "version": "7.2.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/eslint-scope/-/eslint-scope-7.2.2.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/eslint-scope/-/eslint-scope-7.2.2.tgz",
@@ -3477,18 +3379,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/eslint/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/eslint/node_modules/p-limit": { "node_modules/eslint/node_modules/p-limit": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://mirrors.cloud.tencent.com/npm/p-limit/-/p-limit-3.1.0.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/p-limit/-/p-limit-3.1.0.tgz",
@@ -4012,6 +3902,26 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
} }
}, },
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": { "node_modules/glob-parent": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
@@ -4922,6 +4832,28 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimatch/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/minimist": { "node_modules/minimist": {
"version": "1.2.8", "version": "1.2.8",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimist/-/minimist-1.2.8.tgz", "resolved": "https://mirrors.cloud.tencent.com/npm/minimist/-/minimist-1.2.8.tgz",
@@ -5509,48 +5441,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/rimraf/node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://mirrors.cloud.tencent.com/npm/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/rimraf/node_modules/glob": {
"version": "7.2.3",
"resolved": "https://mirrors.cloud.tencent.com/npm/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/rimraf/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://mirrors.cloud.tencent.com/npm/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/roarr": { "node_modules/roarr": {
"version": "2.15.4", "version": "2.15.4",
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",

View File

@@ -4,6 +4,8 @@ import {mergeNewProperties} from "./utils";
export const HOOK_LOG = false; export const HOOK_LOG = false;
export const ALLOW_SEND_TEMP_MSG = false;
export class ConfigUtil { export class ConfigUtil {
private readonly configPath: string; private readonly configPath: string;
private config: Config | null = null; private config: Config | null = null;

View File

@@ -11,6 +11,7 @@ import {
import {type FileCache, type LLOneBotError} from './types' import {type FileCache, type LLOneBotError} from './types'
import {dbUtil} from "./db"; import {dbUtil} from "./db";
import {raw} from "express"; import {raw} from "express";
import {log} from "./utils";
export const selfInfo: SelfInfo = { export const selfInfo: SelfInfo = {
uid: '', uid: '',
@@ -30,28 +31,33 @@ export const llonebotError: LLOneBotError = {
export const fileCache = new Map<string, FileCache>() export const fileCache = new Map<string, FileCache>()
export async function getHistoryMsgByShortId(shortId: number) { export async function getFriend(qq: string, uid: string = ""): Promise<Friend | undefined> {
// log("getHistoryMsgByShortId", shortId, Object.values(msgHistory).map(m=>m.msgShortId)) let filterKey = uid ? "uid" : "uin"
return await dbUtil.getMsgByShortId(shortId); let filterValue = uid ? uid : qq
} let friend = friends.find(friend => friend[filterKey] === filterValue.toString())
// if (!friend) {
export async function getFriend(qq: string): Promise<Friend | undefined> { // try {
let friend = friends.find(friend => friend.uin === qq) // friends = (await NTQQApi.getFriends(true))
if (!friend){ // friend = friends.find(friend => friend[filterKey] === filterValue.toString())
friends = (await NTQQApi.getFriends(true)) // } catch (e) {
friend = friends.find(friend => friend.uin === qq) // // log("刷新好友列表失败", e.stack.toString())
} // }
// }
return friend return friend
} }
export async function getGroup(qq: string): Promise<Group | undefined> { export async function getGroup(qq: string): Promise<Group | undefined> {
let group = groups.find(group => group.groupCode === qq) let group = groups.find(group => group.groupCode === qq.toString())
if (!group){ if (!group) {
const _groups = await NTQQApi.getGroups(true); try {
group = _groups.find(group => group.groupCode === qq) const _groups = await NTQQApi.getGroups(true);
if (group){ group = _groups.find(group => group.groupCode === qq.toString())
groups.push(group) if (group) {
groups.push(group)
}
} catch (e) {
} }
} }
return group return group
} }
@@ -63,22 +69,25 @@ export async function getGroupMember(groupQQ: string | number, memberQQ: string
} }
const group = await getGroup(groupQQ) const group = await getGroup(groupQQ)
if (group) { if (group) {
let filterFunc: (member: GroupMember) => boolean const filterKey = memberQQ ? "uin" : "uid"
if (memberQQ) { const filterValue = memberQQ ? memberQQ : memberUid
filterFunc = member => member.uin === memberQQ let filterFunc: (member: GroupMember) => boolean = member => member[filterKey] === filterValue
} else if (memberUid) {
filterFunc = member => member.uid === memberUid
}
let member = group.members?.find(filterFunc) let member = group.members?.find(filterFunc)
if (!member) { if (!member) {
const _members = await NTQQApi.getGroupMembers(groupQQ) try {
if (_members.length > 0) { const _members = await NTQQApi.getGroupMembers(groupQQ)
group.members = _members if (_members.length > 0) {
group.members = _members
}
} catch (e) {
// log("刷新群成员列表失败", e.stack.toString())
} }
member = group.members?.find(filterFunc) member = group.members?.find(filterFunc)
} }
return member return member
} }
return null
} }
export async function refreshGroupMembers(groupQQ: string) { export async function refreshGroupMembers(groupQQ: string) {

View File

@@ -1,8 +1,9 @@
// import {DATA_DIR} from "./utils"; // import {DATA_DIR} from "./utils";
import {Level} from "level"; import {Level} from "level";
import {RawMessage} from "../ntqqapi/types"; import {RawMessage} from "../ntqqapi/types";
import {DATA_DIR} from "./utils"; import {DATA_DIR, log} from "./utils";
import {selfInfo} from "./data"; import {selfInfo} from "./data";
import * as wasi from "wasi";
class DBUtil { class DBUtil {
@@ -11,6 +12,7 @@ class DBUtil {
private readonly DB_KEY_PREFIX_MSG_SEQ_ID = "msg_seq_id_"; private readonly DB_KEY_PREFIX_MSG_SEQ_ID = "msg_seq_id_";
private db: Level; private db: Level;
private cache: Record<string, RawMessage> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: RawMessage private cache: Record<string, RawMessage> = {} // <msg_id_ | msg_short_id_ | msg_seq_id_><id>: RawMessage
private currentShortId: number;
/* /*
* 数据库结构 * 数据库结构
@@ -24,9 +26,9 @@ class DBUtil {
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const initDB = () => { const initDB = () => {
initCount++; initCount++;
if (initCount > 50) { // if (initCount > 50) {
return reject("init db fail") // return reject("init db fail")
} // }
try { try {
if (!selfInfo.uin) { if (!selfInfo.uin) {
@@ -38,7 +40,7 @@ class DBUtil {
console.log("llonebot init db success") console.log("llonebot init db success")
resolve(null) resolve(null)
} catch (e) { } catch (e) {
// console.log("init db fail", e.stack.toString()) console.log("init db fail", e.stack.toString())
setTimeout(initDB, 300); setTimeout(initDB, 300);
} }
} }
@@ -53,7 +55,7 @@ class DBUtil {
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + msg.msgShortId const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + msg.msgShortId
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq
this.cache[longIdKey] = this.cache[shortIdKey] = this.cache[seqIdKey] = msg this.cache[longIdKey] = this.cache[shortIdKey] = msg
} }
async getMsgByShortId(shortMsgId: number): Promise<RawMessage> { async getMsgByShortId(shortMsgId: number): Promise<RawMessage> {
@@ -91,16 +93,18 @@ class DBUtil {
async addMsg(msg: RawMessage) { async addMsg(msg: RawMessage) {
// 有则更新,无则添加 // 有则更新,无则添加
// log("addMsg", msg.msgId, msg.msgSeq, msg.msgShortId);
const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId const longIdKey = this.DB_KEY_PREFIX_MSG_ID + msg.msgId
let existMsg = this.cache[longIdKey] let existMsg = this.cache[longIdKey]
if (!existMsg){ if (!existMsg) {
try { try {
existMsg = await this.getMsgByLongId(msg.msgId) existMsg = await this.getMsgByLongId(msg.msgId)
}catch (e) { } catch (e) {
} }
} }
if (existMsg){ if (existMsg) {
// log("消息已存在", existMsg.msgSeq, existMsg.msgShortId, existMsg.msgId)
this.updateMsg(msg).then() this.updateMsg(msg).then()
return existMsg.msgShortId return existMsg.msgShortId
} }
@@ -108,11 +112,25 @@ class DBUtil {
const shortMsgId = await this.genMsgShortId(); const shortMsgId = await this.genMsgShortId();
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId; const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + shortMsgId;
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq; const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq;
await this.db.put(shortIdKey, msg.msgId);
msg.msgShortId = shortMsgId; msg.msgShortId = shortMsgId;
await this.db.put(longIdKey, JSON.stringify(msg)); try {
await this.db.put(seqIdKey, msg.msgId); this.db.put(shortIdKey, msg.msgId).then();
this.cache[seqIdKey] = this.cache[shortIdKey] = this.cache[longIdKey] = msg; this.db.put(longIdKey, JSON.stringify(msg)).then();
try {
if (!(await this.db.get(seqIdKey))) {
this.db.put(seqIdKey, msg.msgId).then();
}
} catch (e) {
}
this.cache[shortIdKey] = this.cache[longIdKey] = msg;
if (!this.cache[seqIdKey]) {
this.cache[seqIdKey] = msg;
}
// log(`消息入库 ${seqIdKey}: ${msg.msgId}, ${shortMsgId}: ${msg.msgId}`);
} catch (e) {
// log("addMsg db error", e.stack.toString());
}
return shortMsgId return shortMsgId
} }
@@ -128,20 +146,38 @@ class DBUtil {
} }
Object.assign(existMsg, msg) Object.assign(existMsg, msg)
await this.db.put(longIdKey, JSON.stringify(existMsg)); this.db.put(longIdKey, JSON.stringify(existMsg)).then();
const shortIdKey = this.DB_KEY_PREFIX_MSG_SHORT_ID + existMsg.msgShortId;
const seqIdKey = this.DB_KEY_PREFIX_MSG_SEQ_ID + msg.msgSeq;
if (!this.cache[seqIdKey]) {
this.cache[seqIdKey] = existMsg;
}
this.db.put(shortIdKey, msg.msgId).then();
try {
if (!(await this.db.get(seqIdKey))) {
this.db.put(seqIdKey, msg.msgId).then();
}
} catch (e) {
}
// log("更新消息", existMsg.msgSeq, existMsg.msgShortId, existMsg.msgId);
} }
private async genMsgShortId(): Promise<number> { private async genMsgShortId(): Promise<number> {
let shortId = -2147483640
const key = "msg_current_short_id"; const key = "msg_current_short_id";
try { if (this.currentShortId === undefined) {
let id: string = await this.db.get(key); try {
shortId = parseInt(id); let id: string = await this.db.get(key);
} catch (e) { this.currentShortId = parseInt(id);
} catch (e) {
this.currentShortId = -2147483640
}
} }
shortId++;
await this.db.put(key, shortId.toString()); this.currentShortId++;
return shortId; await this.db.put(key, this.currentShortId.toString());
return this.currentShortId;
} }
} }

View File

@@ -13,7 +13,7 @@ import {
import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer"; import {ob11WebsocketServer} from "../onebot11/server/ws/WebsocketServer";
import {checkFfmpeg, DATA_DIR, getConfigUtil, log} from "../common/utils"; import {checkFfmpeg, DATA_DIR, getConfigUtil, log} from "../common/utils";
import { import {
friendRequests, friendRequests, getFriend,
getGroup, getGroup,
getGroupMember, getGroupMember,
groupNotifies, groupNotifies,
@@ -155,7 +155,7 @@ function onLoad() {
async function postReceiveMsg(msgList: RawMessage[]) { async function postReceiveMsg(msgList: RawMessage[]) {
const {debug, reportSelfMessage} = getConfigUtil().getConfig(); const {debug, reportSelfMessage} = getConfigUtil().getConfig();
for (let message of msgList) { for (let message of msgList) {
// log("收到新消息", message) // log("收到新消息", message.msgSeq)
message.msgShortId = await dbUtil.addMsg(message) message.msgShortId = await dbUtil.addMsg(message)
OB11Constructor.message(message).then((msg) => { OB11Constructor.message(message).then((msg) => {
@@ -177,7 +177,7 @@ function onLoad() {
try { try {
await postReceiveMsg(payload.msgList); await postReceiveMsg(payload.msgList);
} catch (e) { } catch (e) {
log("report message error: ", e.toString()); log("report message error: ", e.stack.toString());
} }
}) })
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, async (payload) => { registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, async (payload) => {
@@ -213,7 +213,7 @@ function onLoad() {
// 不让入库覆盖原来消息,不然就获取不到撤回的消息内容了 // 不让入库覆盖原来消息,不然就获取不到撤回的消息内容了
continue continue
} }
dbUtil.addMsg(message).then(); dbUtil.updateMsg(message).then();
} }
}) })
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, async (payload) => { registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, async (payload) => {
@@ -245,14 +245,15 @@ function onLoad() {
const notifies = notify.notifies.slice(0, payload.unreadCount) const notifies = notify.notifies.slice(0, payload.unreadCount)
// log("获取群通知详情完成", notifies, payload); // log("获取群通知详情完成", notifies, payload);
try {
for (const notify of notifies) { for (const notify of notifies) {
try {
notify.time = Date.now(); notify.time = Date.now();
const notifyTime = parseInt(notify.seq) / 1000 const notifyTime = parseInt(notify.seq) / 1000
// log(`加群通知时间${notifyTime}`, `LLOneBot启动时间${startTime}`); // log(`加群通知时间${notifyTime}`, `LLOneBot启动时间${startTime}`);
if (notifyTime < startTime) { // if (notifyTime < startTime) {
continue; // continue;
} // }
let existNotify = groupNotifies[notify.seq]; let existNotify = groupNotifies[notify.seq];
if (existNotify) { if (existNotify) {
if (Date.now() - existNotify.time < 3000) { if (Date.now() - existNotify.time < 3000) {
@@ -261,14 +262,14 @@ function onLoad() {
} }
log("收到群通知", notify); log("收到群通知", notify);
groupNotifies[notify.seq] = notify; groupNotifies[notify.seq] = notify;
const member1 = await getGroupMember(notify.group.groupCode, null, notify.user1.uid); // let member2: GroupMember;
refreshGroupMembers(notify.group.groupCode).then() // if (notify.user2.uid) {
let member2: GroupMember; // member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid);
if (notify.user2.uid) { // }
member2 = await getGroupMember(notify.group.groupCode, null, notify.user2.uid);
}
if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) { if ([GroupNotifyTypes.ADMIN_SET, GroupNotifyTypes.ADMIN_UNSET].includes(notify.type)) {
const member1 = await getGroupMember(notify.group.groupCode, null, notify.user1.uid);
log("有管理员变动通知"); log("有管理员变动通知");
refreshGroupMembers(notify.group.groupCode).then()
let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent() let groupAdminNoticeEvent = new OB11GroupAdminNoticeEvent()
groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode); groupAdminNoticeEvent.group_id = parseInt(notify.group.groupCode);
log("开始获取变动的管理员") log("开始获取变动的管理员")
@@ -281,8 +282,9 @@ function onLoad() {
log("获取群通知的成员信息失败", notify, getGroup(notify.group.groupCode)); log("获取群通知的成员信息失败", notify, getGroup(notify.group.groupCode));
} }
} else if (notify.type == GroupNotifyTypes.MEMBER_EXIT) { } else if (notify.type == GroupNotifyTypes.MEMBER_EXIT) {
log("有成员退出通知"); // log("有成员退出通知");
let groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(notify.group.groupCode), parseInt(member1.uin)) // const member1 = await getGroupMember(notify.group.groupCode, null, notify.user1.uid);
// let groupDecreaseEvent = new OB11GroupDecreaseEvent(parseInt(notify.group.groupCode), parseInt(member1.uin))
// postEvent(groupDecreaseEvent, true); // postEvent(groupDecreaseEvent, true);
} else if ([GroupNotifyTypes.JOIN_REQUEST].includes(notify.type)) { } else if ([GroupNotifyTypes.JOIN_REQUEST].includes(notify.type)) {
log("有加群请求"); log("有加群请求");
@@ -300,20 +302,24 @@ function onLoad() {
groupRequestEvent.flag = notify.seq; groupRequestEvent.flag = notify.seq;
postOB11Event(groupRequestEvent); postOB11Event(groupRequestEvent);
} else if (notify.type == GroupNotifyTypes.INVITE_ME) { } else if (notify.type == GroupNotifyTypes.INVITE_ME) {
log("收到邀请我加群通知")
let groupInviteEvent = new OB11GroupRequestEvent(); let groupInviteEvent = new OB11GroupRequestEvent();
groupInviteEvent.group_id = parseInt(notify.group.groupCode); groupInviteEvent.group_id = parseInt(notify.group.groupCode);
let user_id = (await NTQQApi.getUserDetailInfo(notify.user2.uid))?.uin let user_id = (await getFriend("", notify.user2.uid))?.uin
if (!user_id){
user_id = (await NTQQApi.getUserDetailInfo(notify.user2.uid))?.uin
}
groupInviteEvent.user_id = parseInt(user_id); groupInviteEvent.user_id = parseInt(user_id);
groupInviteEvent.sub_type = "invite"; groupInviteEvent.sub_type = "invite";
groupInviteEvent.flag = notify.seq; groupInviteEvent.flag = notify.seq;
postOB11Event(groupInviteEvent); postOB11Event(groupInviteEvent);
} }
} catch (e) {
log("解析群通知失败", e.stack.toString());
} }
} catch (e) {
log("解析群通知失败", e.stack);
} }
}
else if (payload.doubt){ } else if (payload.doubt) {
// 可能有群管理员变动 // 可能有群管理员变动
} }
}) })

View File

@@ -81,19 +81,19 @@ export class SendMsgElementConstructor {
}; };
} }
static async file(filePath: string, isVideo: boolean = false): Promise<SendFileElement> { static async file(filePath: string, showPreview: boolean = false, fileName: string = ""): Promise<SendFileElement> {
let picHeight = 0; let picHeight = 0;
let picWidth = 0; let picWidth = 0;
if (isVideo) { if (showPreview) {
picHeight = 1024; picHeight = 1024;
picWidth = 768; picWidth = 768;
} }
const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(filePath, ElementType.FILE); const {md5, fileName: _fileName, path, fileSize} = await NTQQApi.uploadFile(filePath, ElementType.FILE);
let element: SendFileElement = { let element: SendFileElement = {
elementType: ElementType.FILE, elementType: ElementType.FILE,
elementId: "", elementId: "",
fileElement: { fileElement: {
fileName, fileName: fileName || _fileName,
"filePath": path, "filePath": path,
"fileSize": (fileSize).toString(), "fileSize": (fileSize).toString(),
picHeight, picHeight,
@@ -104,8 +104,8 @@ export class SendMsgElementConstructor {
return element; return element;
} }
static video(filePath: string): Promise<SendFileElement> { static video(filePath: string, fileName: string=""): Promise<SendFileElement> {
return SendMsgElementConstructor.file(filePath, true); return SendMsgElementConstructor.file(filePath, true, fileName);
} }
static async ptt(pttPath: string): Promise<SendPttElement> { static async ptt(pttPath: string): Promise<SendPttElement> {

View File

@@ -233,7 +233,7 @@ registerReceiveHook<{
registerReceiveHook<{ msgList: RawMessage[] }>(ReceiveCmd.NEW_MSG, (payload) => { registerReceiveHook<{ msgList: RawMessage[] }>(ReceiveCmd.NEW_MSG, (payload) => {
const {autoDeleteFile, autoDeleteFileSecond} = getConfigUtil().getConfig() const {autoDeleteFile, autoDeleteFileSecond} = getConfigUtil().getConfig()
for (const message of payload.msgList) { for (const message of payload.msgList) {
// log("收到新消息push到历史记录", message) // log("收到新消息push到历史记录", message.msgSeq)
dbUtil.addMsg(message).then() dbUtil.addMsg(message).then()
// 清理文件 // 清理文件
if (!autoDeleteFile) { if (!autoDeleteFile) {
@@ -268,6 +268,8 @@ registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, ({msgRe
const message = msgRecord const message = msgRecord
const peerUid = message.peerUid const peerUid = message.peerUid
// log("收到自己发送成功的消息", Object.keys(sendMessagePool), message); // log("收到自己发送成功的消息", Object.keys(sendMessagePool), message);
// log("收到自己发送成功的消息", message.msgSeq);
dbUtil.addMsg(message).then()
const sendCallback = sendMessagePool[peerUid] const sendCallback = sendMessagePool[peerUid]
if (sendCallback) { if (sendCallback) {
try { try {

View File

@@ -17,7 +17,7 @@ import {
type User type User
} from './types' } from './types'
import * as fs from 'node:fs' import * as fs from 'node:fs'
import {friendRequests, groupNotifies, selfInfo} from '../common/data' import {friendRequests, groupNotifies, selfInfo, uidMaps} from '../common/data'
import {v4 as uuidv4} from 'uuid' import {v4 as uuidv4} from 'uuid'
import path from 'path' import path from 'path'
import {dbUtil} from "../common/db"; import {dbUtil} from "../common/db";
@@ -292,7 +292,7 @@ export class NTQQApi {
const members: GroupMember[] = Array.from(values) const members: GroupMember[] = Array.from(values)
for (const member of members) { for (const member of members) {
// uidMaps[member.uid] = member.uin; uidMaps[member.uid] = member.uin;
} }
// log(uidMaps); // log(uidMaps);
// log("members info", values); // log("members info", values);
@@ -422,7 +422,7 @@ export class NTQQApi {
}) })
} }
static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = false, timeout = 10000) { static async sendMsg(peer: Peer, msgElements: SendMessageElement[], waitComplete = true, timeout = 10000) {
const peerUid = peer.peerUid const peerUid = peer.peerUid
// 等待上一个相同的peer发送完 // 等待上一个相同的peer发送完
@@ -455,22 +455,21 @@ export class NTQQApi {
if (waitComplete) { if (waitComplete) {
if ((await dbUtil.getMsgByLongId(sentMessage.msgId)).sendStatus == 2) { if ((await dbUtil.getMsgByLongId(sentMessage.msgId)).sendStatus == 2) {
return sentMessage return sentMessage
} else {
return await checkSendComplete()
} }
} }
// log(`给${peerUid}发送消息成功`) else{
return sentMessage return sentMessage
} else {
checkSendCompleteUsingTime += 500
if (checkSendCompleteUsingTime > timeout) {
throw ('发送超时')
} }
await sleep(500) // log(`给${peerUid}发送消息成功`)
return await checkSendComplete()
} }
checkSendCompleteUsingTime += 500
if (checkSendCompleteUsingTime > timeout) {
throw ('发送超时')
}
await sleep(500)
return await checkSendComplete()
} }
log("开始发送消息", peer, msgElements)
callNTQQApi({ callNTQQApi({
methodName: NTQQApiMethod.SEND_MSG, methodName: NTQQApiMethod.SEND_MSG,
args: [{ args: [{

View File

@@ -283,6 +283,30 @@ export interface TipAioOpGrayTipElement{
fromGrpCodeOfTmpChat: string, fromGrpCodeOfTmpChat: string,
} }
export interface TipGroupElement {
"type": 1, // 1是表示有人加入群, 自己加入群也会收到这个
"role": 0,
"groupName": string, // 暂时获取不到
"memberUid": string,
"memberNick": string,
"memberRemark": string,
"adminUid": string, // 同意加群的管理员uid
"adminNick": string,
"adminRemark": string,
"createGroup": null,
"memberAdd": {
"showType": 1,
"otherAdd": null,
"otherAddByOtherQRCode": null,
"otherAddByYourQRCode": null,
"youAddByOtherQRCode": null,
"otherInviteOther": null,
"otherInviteYou": null,
"youInviteOther": null
},
"shutUp": null
}
export interface RawMessage { export interface RawMessage {
msgId: string; msgId: string;

View File

@@ -21,7 +21,7 @@ class BaseAction<PayloadType, ReturnDataType> {
const resData = await this._handle(payload); const resData = await this._handle(payload);
return OB11Response.ok(resData); return OB11Response.ok(resData);
} catch (e) { } catch (e) {
log("发错误", e.stack) log("发错误", e.stack)
return OB11Response.error(e.toString(), 200); return OB11Response.error(e.toString(), 200);
} }
} }

View File

@@ -1,9 +1,17 @@
import SendMsg from "./SendMsg"; import SendMsg from "./SendMsg";
import {ActionName} from "./types"; import {ActionName, BaseCheckResult} from "./types";
import {OB11PostSendMsg} from "../types";
import {log} from "../../common/utils";
class SendGroupMsg extends SendMsg { class SendGroupMsg extends SendMsg {
actionName = ActionName.SendGroupMsg actionName = ActionName.SendGroupMsg
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
delete payload.user_id;
payload.message_type = "group"
return super.check(payload);
}
} }
export default SendGroupMsg export default SendGroupMsg

View File

@@ -1,5 +1,5 @@
import BaseAction from "./BaseAction"; import BaseAction from "./BaseAction";
import {getFriend} from "../../common/data"; import {getFriend, getUidByUin, uidMaps} from "../../common/data";
import {NTQQApi} from "../../ntqqapi/ntcall"; import {NTQQApi} from "../../ntqqapi/ntcall";
import {ActionName} from "./types"; import {ActionName} from "./types";
@@ -14,11 +14,15 @@ export default class SendLike extends BaseAction<Payload, null> {
protected async _handle(payload: Payload): Promise<null> { protected async _handle(payload: Payload): Promise<null> {
const qq = payload.user_id.toString(); const qq = payload.user_id.toString();
const friend = await getFriend(qq) const friend = await getFriend(qq)
let uid: string;
if (!friend) { if (!friend) {
throw (`点赞失败,${qq}不是好友`) uid = getUidByUin(qq)
}
else{
uid = friend.uid
} }
try { try {
let result = await NTQQApi.likeFriend(friend.uid, parseInt(payload.times.toString()) || 1); let result = await NTQQApi.likeFriend(uid, parseInt(payload.times?.toString()) || 1);
if (result.result !== 0) { if (result.result !== 0) {
throw result.errMsg throw result.errMsg
} }

View File

@@ -1,5 +1,5 @@
import {AtType, ChatType, Group, RawMessage, SendArkElement, SendMessageElement} from "../../ntqqapi/types"; import {AtType, ChatType, Group, RawMessage, SendArkElement, SendMessageElement} from "../../ntqqapi/types";
import {friends, getGroup, getGroupMember, getUidByUin, selfInfo,} from "../../common/data"; import {friends, getFriend, getGroup, getGroupMember, getUidByUin, selfInfo,} from "../../common/data";
import { import {
OB11MessageCustomMusic, OB11MessageCustomMusic,
OB11MessageData, OB11MessageData,
@@ -17,6 +17,7 @@ import * as fs from "node:fs";
import {log} from "../../common/utils"; import {log} from "../../common/utils";
import {decodeCQCode} from "../cqcode"; import {decodeCQCode} from "../cqcode";
import {dbUtil} from "../../common/db"; import {dbUtil} from "../../common/db";
import {ALLOW_SEND_TEMP_MSG} from "../../common/config";
function checkSendMessage(sendMsgList: OB11MessageData[]) { function checkSendMessage(sendMsgList: OB11MessageData[]) {
function checkUri(uri: string): boolean { function checkUri(uri: string): boolean {
@@ -69,6 +70,22 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
message: "转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素" message: "转发消息不能和普通消息混在一起发送,转发需要保证message只有type为node的元素"
} }
} }
if (payload.group_id && !(await getGroup(payload.group_id))) {
return {
valid: false,
message: `${payload.group_id}不存在`
}
}
if (payload.user_id && payload.message_type !== "group") {
if (!(await getFriend(payload.user_id))) {
if (!ALLOW_SEND_TEMP_MSG) {
return {
valid: false,
message: `不能发送临时消息`
}
}
}
}
return { return {
valid: true, valid: true,
} }
@@ -79,17 +96,16 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
chatType: ChatType.friend, chatType: ChatType.friend,
peerUid: "" peerUid: ""
} }
let isTempMsg = false;
let group: Group | undefined = undefined; let group: Group | undefined = undefined;
if (payload?.group_id) { const genGroupPeer = async () => {
group = await getGroup(payload.group_id.toString()) group = await getGroup(payload.group_id.toString())
if (!group) {
throw (`${payload.group_id}不存在`)
}
peer.chatType = ChatType.group peer.chatType = ChatType.group
// peer.name = group.name // peer.name = group.name
peer.peerUid = group.groupCode peer.peerUid = group.groupCode
} else if (payload?.user_id) { }
const genFriendPeer = () => {
const friend = friends.find(f => f.uin == payload.user_id.toString()) const friend = friends.find(f => f.uin == payload.user_id.toString())
if (friend) { if (friend) {
// peer.name = friend.nickName // peer.name = friend.nickName
@@ -101,9 +117,20 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
throw (`找不到私聊对象${payload.user_id}`) throw (`找不到私聊对象${payload.user_id}`)
} }
// peer.name = tempUser.nickName // peer.name = tempUser.nickName
isTempMsg = true;
peer.peerUid = tempUserUid; peer.peerUid = tempUserUid;
} }
} }
if (payload?.group_id && payload.message_type === "group") {
await genGroupPeer()
} else if (payload?.user_id) {
genFriendPeer()
} else if (payload.group_id) {
await genGroupPeer()
} else {
throw ("发送消息参数错误, 请指定group_id或user_id")
}
const messages = this.convertMessage2List(payload.message); const messages = this.convertMessage2List(payload.message);
if (this.getSpecialMsgNum(payload, OB11MessageDataType.node)) { if (this.getSpecialMsgNum(payload, OB11MessageDataType.node)) {
try { try {
@@ -133,6 +160,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
const returnMsg = await this.send(peer, sendElements, deleteAfterSentFiles) const returnMsg = await this.send(peer, sendElements, deleteAfterSentFiles)
return {message_id: returnMsg.msgShortId} return {message_id: returnMsg.msgShortId}
} catch (e) { } catch (e) {
log("发送消息失败", e.stack.toString())
throw (e.toString()) throw (e.toString())
} }
} }
@@ -277,7 +305,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
case OB11MessageDataType.reply: { case OB11MessageDataType.reply: {
let replyMsgId = sendMsg.data.id; let replyMsgId = sendMsg.data.id;
if (replyMsgId) { if (replyMsgId) {
const replyMsg = await dbUtil.getMsgByShortId(parseInt(replyMsgId)) const replyMsg = await dbUtil.getMsgBySeqId(replyMsgId)
if (replyMsg) { if (replyMsg) {
sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin, replyMsg.senderUin)) sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsg.msgId, replyMsg.senderUin, replyMsg.senderUin))
} }
@@ -297,8 +325,9 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
case OB11MessageDataType.video: case OB11MessageDataType.video:
case OB11MessageDataType.voice: { case OB11MessageDataType.voice: {
const file = sendMsg.data?.file const file = sendMsg.data?.file
const payloadFileName = sendMsg.data?.name
if (file) { if (file) {
const {path, isLocal} = (await uri2local(file)) const {path, isLocal, fileName} = (await uri2local(file))
if (path) { if (path) {
if (!isLocal) { // 只删除http和base64转过来的文件 if (!isLocal) { // 只删除http和base64转过来的文件
deleteAfterSentFiles.push(path) deleteAfterSentFiles.push(path)
@@ -309,7 +338,15 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
[OB11MessageDataType.video]: SendMsgElementConstructor.video, [OB11MessageDataType.video]: SendMsgElementConstructor.video,
[OB11MessageDataType.file]: SendMsgElementConstructor.file, [OB11MessageDataType.file]: SendMsgElementConstructor.file,
} }
sendElements.push(await constructorMap[sendMsg.type](path)); if (sendMsg.type === OB11MessageDataType.file) {
log("发送文件", path, payloadFileName || fileName)
sendElements.push(await SendMsgElementConstructor.file(path, false, payloadFileName || fileName));
} else if (sendMsg.type === OB11MessageDataType.video) {
log("发送视频", path, payloadFileName || fileName)
sendElements.push(await SendMsgElementConstructor.video(path, payloadFileName || fileName));
} else {
sendElements.push(await constructorMap[sendMsg.type](path));
}
} }
} }
} }
@@ -329,7 +366,8 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
throw ("消息体无法解析") throw ("消息体无法解析")
} }
const returnMsg = await NTQQApi.sendMsg(peer, sendElements, waitComplete, 20000); const returnMsg = await NTQQApi.sendMsg(peer, sendElements, waitComplete, 20000);
await dbUtil.addMsg(returnMsg) log("消息发送结果", returnMsg)
returnMsg.msgShortId = await dbUtil.addMsg(returnMsg)
deleteAfterSentFiles.map(f => fs.unlink(f, () => { deleteAfterSentFiles.map(f => fs.unlink(f, () => {
})) }))
return returnMsg return returnMsg

View File

@@ -1,8 +1,14 @@
import SendMsg from "./SendMsg"; import SendMsg from "./SendMsg";
import {ActionName} from "./types"; import {ActionName, BaseCheckResult} from "./types";
import {OB11PostSendMsg} from "../types";
class SendPrivateMsg extends SendMsg { class SendPrivateMsg extends SendMsg {
actionName = ActionName.SendPrivateMsg actionName = ActionName.SendPrivateMsg
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
payload.message_type = "private"
return super.check(payload);
}
} }
export default SendPrivateMsg export default SendPrivateMsg

View File

@@ -96,12 +96,19 @@ export class OB11Constructor {
message_data["data"]["text"] = text message_data["data"]["text"] = text
} else if (element.replyElement) { } else if (element.replyElement) {
message_data["type"] = "reply" message_data["type"] = "reply"
const replyMsg = await dbUtil.getMsgBySeqId(element.replyElement.replayMsgSeq) // log("收到回复消息", element.replyElement.replayMsgSeq)
if (replyMsg) { try{
message_data["data"]["id"] = replyMsg.msgShortId.toString() const replyMsg = await dbUtil.getMsgBySeqId(element.replyElement.replayMsgSeq)
} else { // log("找到回复消息", replyMsg.msgShortId, replyMsg.msgId)
continue if (replyMsg) {
message_data["data"]["id"] = replyMsg.msgShortId.toString()
} else {
continue
}
}catch (e) {
log("获取不到引用的消息", e.stack)
} }
} else if (element.picElement) { } else if (element.picElement) {
message_data["type"] = "image" message_data["type"] = "image"
// message_data["data"]["file"] = element.picElement.sourcePath // message_data["data"]["file"] = element.picElement.sourcePath
@@ -117,7 +124,7 @@ export class OB11Constructor {
url: IMAGE_HTTP_HOST + element.picElement.originImageUrl, url: IMAGE_HTTP_HOST + element.picElement.originImageUrl,
downloadFunc: async () => { downloadFunc: async () => {
await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid, await NTQQApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid,
element.elementId, element.picElement.thumbPath.get(0), element.picElement.sourcePath) element.elementId, element.picElement.thumbPath?.get(0) || "", element.picElement.sourcePath)
} }
}) })
// 不在自动下载图片 // 不在自动下载图片

View File

@@ -3,12 +3,12 @@ import {OB11GroupNoticeEvent} from "./OB11GroupNoticeEvent";
export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent { export class OB11GroupIncreaseEvent extends OB11GroupNoticeEvent {
notice_type = "group_increase"; notice_type = "group_increase";
sub_type = "approve"; // TODO: 实现其他几种子类型的识别 ("approve" | "invite") sub_type = "approve"; // TODO: 实现其他几种子类型的识别 ("approve" | "invite")
operate_id: number; operator_id: number;
constructor(groupId: number, userId: number) { constructor(groupId: number, userId: number) {
super(); super();
this.group_id = groupId; this.group_id = groupId;
this.operate_id = userId; // 实际上不应该这么实现,但是现在还没有办法识别用户是被邀请的,还是主动加入的 this.operator_id = userId; // 实际上不应该这么实现,但是现在还没有办法识别用户是被邀请的,还是主动加入的
this.user_id = userId; this.user_id = userId;
} }
} }

View File

@@ -113,6 +113,7 @@ export interface OB11MessageText {
interface OB11MessageFileBase { interface OB11MessageFileBase {
data: { data: {
name?: string;
file: string, file: string,
url?: string; url?: string;
} }

View File

@@ -15,6 +15,8 @@ export async function uri2local(uri: string, fileName: string = null) {
let res = { let res = {
success: false, success: false,
errMsg: "", errMsg: "",
fileName: "",
ext: "",
path: "", path: "",
isLocal: false isLocal: false
} }
@@ -39,7 +41,15 @@ export async function uri2local(uri: string, fileName: string = null) {
let blob = await fetchRes.blob(); let blob = await fetchRes.blob();
let buffer = await blob.arrayBuffer(); let buffer = await blob.arrayBuffer();
try { try {
fileName = path.parse(url.pathname).name || fileName const pathInfo = path.parse(decodeURIComponent(url.pathname))
if (pathInfo.name){
fileName = pathInfo.name
if (pathInfo.ext){
fileName += pathInfo.ext
res.ext = pathInfo.ext
}
}
res.fileName = fileName
filePath = path.join(DATA_DIR, uuidv4() + fileName) filePath = path.join(DATA_DIR, uuidv4() + fileName)
await fs.writeFile(filePath, Buffer.from(buffer)); await fs.writeFile(filePath, Buffer.from(buffer));
} catch (e: any) { } catch (e: any) {
@@ -75,15 +85,17 @@ export async function uri2local(uri: string, fileName: string = null) {
// await fs.rename(filePath, filePath + ".gif"); // await fs.rename(filePath, filePath + ".gif");
// filePath += ".gif"; // filePath += ".gif";
// } // }
if (!res.isLocal) { if (!res.isLocal && !res.ext) {
try{ try {
const {ext} = await fileType.fileTypeFromFile(filePath) let ext: string = (await fileType.fileTypeFromFile(filePath)).ext
if (ext) { if (ext) {
log("获取文件类型", ext, filePath) log("获取文件类型", ext, filePath)
await fs.rename(filePath, filePath + `.${ext}`) await fs.rename(filePath, filePath + `.${ext}`)
filePath += `.${ext}` filePath += `.${ext}`
} res.fileName += `.${ext}`
}catch (e){ res.ext = ext
}
} catch (e) {
// log("获取文件类型失败", filePath,e.stack) // log("获取文件类型失败", filePath,e.stack)
} }
} }

View File

@@ -1 +1 @@
export const version = "3.12.0" export const version = "3.13.4"