mirror of
https://github.com/LLOneBot/LLOneBot.git
synced 2024-11-22 01:56:33 +00:00
refactor: pre-release
This commit is contained in:
@@ -1,16 +1,3 @@
|
||||
export const CHANNEL_SEND_MSG = "llonebot_send_msg"
|
||||
export const CHANNEL_SEND_BACK_MSG = "llonebot_send_back_msg"
|
||||
export const CHANNEL_RECALL_MSG = "llonebot_recall_msg"
|
||||
export const CHANNEL_GET_CONFIG = "llonebot_get_config"
|
||||
export const CHANNEL_SET_CONFIG = "llonebot_set_config"
|
||||
export const CHANNEL_START_HTTP_SERVER = "llonebot_start_http_server"
|
||||
export const CHANNEL_UPDATE_GROUPS = "llonebot_update_groups"
|
||||
export const CHANNEL_UPDATE_FRIENDS = "llonebot_update_friends"
|
||||
export const CHANNEL_LOG = "llonebot_log"
|
||||
export const CHANNEL_POST_ONEBOT_DATA = "llonebot_post_onebot_data"
|
||||
export const CHANNEL_SET_SELF_INFO= "llonebot_set_self_info"
|
||||
export const CHANNEL_DOWNLOAD_FILE= "llonebot_download_file"
|
||||
export const CHANNEL_DELETE_FILE= "llonebot_delete_file"
|
||||
export const CHANNEL_GET_RUNNING_STATUS= "llonebot_get_running_status"
|
||||
export const CHANNEL_FILE2BASE64= "llonebot_file2base64"
|
||||
export const CHANNEL_GET_HISTORY_MSG= "llonebot_get_history_msg"
|
@@ -1,26 +1,25 @@
|
||||
import {SelfInfo} from "./types";
|
||||
import { NTQQApi } from '../ntqqapi/ntcall';
|
||||
import { Group, RawMessage, User } from "../ntqqapi/types";
|
||||
import { Friend, Group, RawMessage, SelfInfo } from "../ntqqapi/types";
|
||||
|
||||
export let groups: Group[] = []
|
||||
export let friends: User[] = []
|
||||
export let friends: Friend[] = []
|
||||
export let msgHistory: Record<string, RawMessage> = {} // msgId: RawMessage
|
||||
|
||||
export async function getFriend(qq: string): Promise<User | undefined> {
|
||||
export async function getFriend(qq: string): Promise<Friend | undefined> {
|
||||
let friend = friends.find(friend => friend.uin === qq)
|
||||
if (!friend){
|
||||
friends = await NTQQApi.getFriends(true)
|
||||
friend = friends.find(friend => friend.uin === qq)
|
||||
}
|
||||
// if (!friend){
|
||||
// friends = (await NTQQApi.getFriends(true))
|
||||
// friend = friends.find(friend => friend.uin === qq)
|
||||
// }
|
||||
return friend
|
||||
}
|
||||
|
||||
export async function getGroup(qq: string): Promise<Group | undefined> {
|
||||
let group = groups.find(group => group.groupCode === qq)
|
||||
if (!group){
|
||||
groups = await NTQQApi.getGroups(true);
|
||||
group = groups.find(group => group.groupCode === qq)
|
||||
}
|
||||
// if (!group){
|
||||
// groups = await NTQQApi.getGroups(true);
|
||||
// group = groups.find(group => group.groupCode === qq)
|
||||
// }
|
||||
return group
|
||||
}
|
||||
|
||||
@@ -29,7 +28,10 @@ export async function getGroupMember(groupQQ: string, memberQQ: string) {
|
||||
if (group) {
|
||||
let member = group.members?.find(member => member.uin === memberQQ)
|
||||
if (!member){
|
||||
group.members = await NTQQApi.getGroupMembers(groupQQ)
|
||||
const _members = await NTQQApi.getGroupMembers(groupQQ)
|
||||
if (_members.length){
|
||||
group.members = _members
|
||||
}
|
||||
member = group.members?.find(member => member.uin === memberQQ)
|
||||
}
|
||||
return member
|
||||
@@ -37,8 +39,9 @@ export async function getGroupMember(groupQQ: string, memberQQ: string) {
|
||||
}
|
||||
|
||||
export let selfInfo: SelfInfo = {
|
||||
user_id: "",
|
||||
nickname: ""
|
||||
uid: "",
|
||||
uin: "",
|
||||
nick: "",
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +50,7 @@ export function getHistoryMsgBySeq(seq: string) {
|
||||
}
|
||||
|
||||
|
||||
export let uidMaps:Record<string, User> = {} // 一串加密的字符串(uid) -> qq号
|
||||
export let uidMaps:Record<string, Friend> = {} // 一串加密的字符串(uid) -> qq号
|
||||
|
||||
export function getStrangerByUin(uin: string) {
|
||||
for (const key in uidMaps) {
|
||||
|
@@ -1,10 +1,3 @@
|
||||
import {OB11ApiName, OB11MessageData} from "../onebot11/types";
|
||||
|
||||
export interface SelfInfo {
|
||||
user_id: string;
|
||||
nickname: string;
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
port: number
|
||||
hosts: string[]
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import * as path from "path";
|
||||
import {json} from "express";
|
||||
import {selfInfo} from "./data";
|
||||
import {ConfigUtil} from "./config";
|
||||
import util from "util";
|
||||
import { sendLog } from '../main/ipcsend';
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
export const CONFIG_DIR = global.LiteLoader.plugins["LLOneBot"].path.data;
|
||||
|
||||
export function getConfigUtil() {
|
||||
const configFilePath = path.join(CONFIG_DIR, `config_${selfInfo.user_id}.json`)
|
||||
const configFilePath = path.join(CONFIG_DIR, `config_${selfInfo.uin}.json`)
|
||||
return new ConfigUtil(configFilePath)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export function log(...msg: any[]) {
|
||||
const month = date.getMonth() + 1;
|
||||
const day = date.getDate();
|
||||
const currentDate = `${year}-${month}-${day}`;
|
||||
const userInfo = selfInfo.user_id ? `${selfInfo.nickname}(${selfInfo.user_id})` : ""
|
||||
const userInfo = selfInfo.uin ? `${selfInfo.nick}(${selfInfo.uin})` : ""
|
||||
let logMsg = "";
|
||||
for (let msgItem of msg){
|
||||
// 判断是否是对象
|
||||
@@ -34,6 +34,8 @@ export function log(...msg: any[]) {
|
||||
logMsg += msgItem + " ";
|
||||
}
|
||||
logMsg = `${currentDateTime} ${userInfo}: ${logMsg}\n`
|
||||
// sendLog(...msg);
|
||||
// console.log(msg)
|
||||
fs.appendFile(path.join(CONFIG_DIR , `llonebot-${currentDate}.log`), logMsg, (err: any) => {
|
||||
|
||||
})
|
||||
|
@@ -1,50 +1,18 @@
|
||||
import {ipcMain, webContents} from 'electron';
|
||||
import {OB11PostSendMsg} from "../onebot11/types"
|
||||
import {CHANNEL_RECALL_MSG, CHANNEL_SEND_MSG,CHANNEL_SEND_BACK_MSG} from "../common/channels";
|
||||
import {v4 as uuid4} from "uuid";
|
||||
import {log} from "../common/utils";
|
||||
import {webContents} from 'electron';
|
||||
import { CHANNEL_LOG } from '../common/channels';
|
||||
|
||||
|
||||
import {OB11Return} from "../onebot11/types";
|
||||
|
||||
function sendIPCMsg(channel: string, data: any) {
|
||||
function sendIPCMsg(channel: string, ...data: any) {
|
||||
let contents = webContents.getAllWebContents();
|
||||
for (const content of contents) {
|
||||
try {
|
||||
content.send(channel, data)
|
||||
content.send(channel, ...data)
|
||||
} catch (e) {
|
||||
console.log("llonebot send ipc msg to render error:", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface SendIPCMsgSession<T> {
|
||||
id: string
|
||||
data: T
|
||||
export function sendLog(...args){
|
||||
sendIPCMsg(CHANNEL_LOG, ...args)
|
||||
}
|
||||
|
||||
export function sendIPCSendQQMsg(postData: OB11PostSendMsg, handleSendResult: (data: OB11Return<any>) => void) {
|
||||
const onceSessionId = uuid4();
|
||||
const handler = (event: any, session: SendIPCMsgSession<OB11Return<any>>) => {
|
||||
// log("llonebot send msg ipcMain.once:" + JSON.stringify(sendResult));
|
||||
if (session?.id !== onceSessionId) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
handleSendResult(session.data)
|
||||
ipcMain.off(CHANNEL_SEND_BACK_MSG, handler)
|
||||
return
|
||||
} catch (e) {
|
||||
log("llonebot send msg sendIPCSendQQMsg handler error:" + JSON.stringify(e))
|
||||
}
|
||||
}
|
||||
ipcMain.on(CHANNEL_SEND_BACK_MSG, handler)
|
||||
sendIPCMsg(CHANNEL_SEND_MSG, {
|
||||
id: onceSessionId,
|
||||
data: postData,
|
||||
});
|
||||
}
|
||||
|
||||
export function sendIPCRecallQQMsg(message_id: string) {
|
||||
sendIPCMsg(CHANNEL_RECALL_MSG, { message_id: message_id });
|
||||
}
|
114
src/main/main.ts
114
src/main/main.ts
@@ -1,29 +1,23 @@
|
||||
// 运行在 Electron 主进程 下的插件入口
|
||||
|
||||
import * as path from "path";
|
||||
import {BrowserWindow, ipcMain} from 'electron';
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
import * as util from 'util';
|
||||
|
||||
import {Config, Group, RawMessage, SelfInfo, User} from "../common/types";
|
||||
import { Config } from "../common/types";
|
||||
import {
|
||||
CHANNEL_DOWNLOAD_FILE,
|
||||
CHANNEL_GET_CONFIG,
|
||||
CHANNEL_SET_SELF_INFO,
|
||||
CHANNEL_LOG,
|
||||
CHANNEL_POST_ONEBOT_DATA,
|
||||
CHANNEL_SET_CONFIG,
|
||||
CHANNEL_START_HTTP_SERVER,
|
||||
CHANNEL_UPDATE_FRIENDS,
|
||||
CHANNEL_UPDATE_GROUPS, CHANNEL_DELETE_FILE, CHANNEL_GET_RUNNING_STATUS, CHANNEL_FILE2BASE64, CHANNEL_GET_HISTORY_MSG
|
||||
} from "../common/channels";
|
||||
import {ConfigUtil} from "../common/config";
|
||||
import {postMsg, startExpress} from "../server/httpserver";
|
||||
import {checkFileReceived, CONFIG_DIR, file2base64, getConfigUtil, isGIF, log} from "../common/utils";
|
||||
import {friends, groups, msgHistory, selfInfo} from "../common/data";
|
||||
import {} from "../global";
|
||||
import {hookNTQQApiReceive, ReceiveCmd, registerReceiveHook} from "../ntqqapi/hook";
|
||||
import {OB11Constructor} from "../onebot11/constructor";
|
||||
import {NTQQApi} from "../ntqqapi/ntcall";
|
||||
import { ConfigUtil } from "../common/config";
|
||||
import { postMsg, startExpress } from "../onebot11/server";
|
||||
import { CONFIG_DIR, getConfigUtil, log } from "../common/utils";
|
||||
import { friends, groups, msgHistory, selfInfo } from "../common/data";
|
||||
import { hookNTQQApiReceive, ReceiveCmd, registerReceiveHook } from "../ntqqapi/hook";
|
||||
import { OB11Constructor } from "../onebot11/constructor";
|
||||
import { NTQQApi } from "../ntqqapi/ntcall";
|
||||
import { Group, RawMessage, SelfInfo } from "../ntqqapi/types";
|
||||
|
||||
const fs = require('fs');
|
||||
|
||||
@@ -38,7 +32,7 @@ function onLoad() {
|
||||
|
||||
|
||||
if (!fs.existsSync(CONFIG_DIR)) {
|
||||
fs.mkdirSync(CONFIG_DIR, {recursive: true});
|
||||
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
||||
}
|
||||
ipcMain.handle(CHANNEL_GET_CONFIG, (event: any, arg: any) => {
|
||||
return getConfigUtil().getConfig()
|
||||
@@ -52,18 +46,18 @@ function onLoad() {
|
||||
})
|
||||
|
||||
|
||||
function postRawMsg(msgList:RawMessage[]) {
|
||||
const {debug, reportSelfMessage} = getConfigUtil().getConfig();
|
||||
function postRawMsg(msgList: RawMessage[]) {
|
||||
const { debug, reportSelfMessage } = getConfigUtil().getConfig();
|
||||
for (const message of msgList) {
|
||||
OB11Constructor.message(message).then((msg) => {
|
||||
if (debug) {
|
||||
msg.raw = message;
|
||||
}
|
||||
if (msg.user_id == selfInfo.user_id && !reportSelfMessage) {
|
||||
if (msg.user_id == selfInfo.uin && !reportSelfMessage) {
|
||||
return
|
||||
}
|
||||
postMsg(msg);
|
||||
}).catch(e=>log("constructMessage error: ", e.toString()));
|
||||
}).catch(e => log("constructMessage error: ", e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +70,7 @@ function onLoad() {
|
||||
})
|
||||
|
||||
registerReceiveHook<{ msgRecord: RawMessage }>(ReceiveCmd.SELF_SEND_MSG, (payload) => {
|
||||
const {reportSelfMessage} = getConfigUtil().getConfig()
|
||||
const { reportSelfMessage } = getConfigUtil().getConfig()
|
||||
if (!reportSelfMessage) {
|
||||
return
|
||||
}
|
||||
@@ -87,46 +81,56 @@ function onLoad() {
|
||||
log("report self message error: ", e.toString())
|
||||
}
|
||||
})
|
||||
|
||||
async function getSelfInfo(){
|
||||
if (!selfInfo.user_id){
|
||||
setTimeout(()=>{
|
||||
getSelfInfo().then()
|
||||
})
|
||||
|
||||
async function getSelfInfo() {
|
||||
try{
|
||||
const _ = await NTQQApi.getSelfInfo()
|
||||
Object.assign(selfInfo, _)
|
||||
selfInfo.nick = selfInfo.uin
|
||||
log("get self simple info", _)
|
||||
}catch(e){
|
||||
log("retry get self info")
|
||||
|
||||
}
|
||||
const _ = await NTQQApi.getSelfInfo()
|
||||
if (_.uin){
|
||||
log("get self info success", _)
|
||||
selfInfo.user_id = _.uin
|
||||
let nickName = _.uin
|
||||
try{
|
||||
const userInfo = (await NTQQApi.getUserInfo(_.uid))
|
||||
if (userInfo){
|
||||
nickName = userInfo.nickName
|
||||
if (selfInfo.uin) {
|
||||
try {
|
||||
const userInfo = (await NTQQApi.getUserInfo(selfInfo.uid))
|
||||
if (userInfo) {
|
||||
selfInfo.nick = userInfo.nick
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
catch (e) {
|
||||
log("get self nickname failed", e.toString())
|
||||
}
|
||||
selfInfo.nickname = nickName
|
||||
try{
|
||||
// let _friends = await NTQQApi.getFriends(true)
|
||||
// log("friends api:", _friends)
|
||||
// for (let f of _friends){
|
||||
// friends.push(f)
|
||||
// }
|
||||
let _groups = await NTQQApi.getGroups(true)
|
||||
log("groups api:", _groups)
|
||||
for (let g of _groups){
|
||||
g.members = (await NTQQApi.getGroupMembers(g.uid))
|
||||
groups.push(g)
|
||||
}
|
||||
// try {
|
||||
// friends.push(...(await NTQQApi.getFriends(true)))
|
||||
// log("get friends", friends)
|
||||
// let _groups: Group[] = []
|
||||
// for(let i=0; i++; i<3){
|
||||
// try{
|
||||
// _groups = await NTQQApi.getGroups(true)
|
||||
// log("get groups sucess", _groups)
|
||||
// break
|
||||
// } catch(e) {
|
||||
// log("get groups failed", e)
|
||||
// }
|
||||
// }
|
||||
// for (let g of _groups) {
|
||||
// g.members = (await NTQQApi.getGroupMembers(g.groupCode))
|
||||
// log("group members", g.members)
|
||||
// groups.push(g)
|
||||
// }
|
||||
|
||||
}catch(e){
|
||||
log("!!!初始化失败", e.stack.toString())
|
||||
}
|
||||
// } catch (e) {
|
||||
// log("!!!初始化失败", e.stack.toString())
|
||||
// }
|
||||
startExpress(getConfigUtil().getConfig().port)
|
||||
}
|
||||
else{
|
||||
setTimeout(() => {
|
||||
getSelfInfo().then()
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
getSelfInfo().then()
|
||||
}
|
||||
@@ -136,7 +140,7 @@ function onLoad() {
|
||||
function onBrowserWindowCreated(window: BrowserWindow) {
|
||||
try {
|
||||
hookNTQQApiReceive(window);
|
||||
} catch (e){
|
||||
} catch (e) {
|
||||
log("llonebot hook error: ", e.toString())
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import {AtType} from "../common/types";
|
||||
import {ElementType, SendPicElement, SendPttElement, SendReplyElement, SendTextElement} from "./types";
|
||||
import {ElementType, SendPicElement, SendPttElement, SendReplyElement, SendTextElement, AtType} from "./types";
|
||||
import {NTQQApi} from "./ntcall";
|
||||
|
||||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
import {BrowserWindow} from 'electron';
|
||||
import {getConfigUtil, log} from "../common/utils";
|
||||
import {NTQQApiClass, sendMessagePool} from "./ntcall";
|
||||
import { Group } from "./types";
|
||||
import {NTQQApi, NTQQApiClass, sendMessagePool} from "./ntcall";
|
||||
import { Group, User } from "./types";
|
||||
import { RawMessage } from "./types";
|
||||
import {groups, msgHistory} from "../common/data";
|
||||
import {friends, groups, msgHistory} from "../common/data";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export let hookApiCallbacks: Record<string, (apiReturn: any)=>void>={}
|
||||
|
||||
@@ -13,7 +14,8 @@ export enum ReceiveCmd {
|
||||
SELF_SEND_MSG = "nodeIKernelMsgListener/onAddSendMsg",
|
||||
USER_INFO = "nodeIKernelProfileListener/onProfileDetailInfoChanged",
|
||||
GROUPS = "nodeIKernelGroupListener/onGroupListUpdate",
|
||||
GROUPS_UNIX = "onGroupListUpdate"
|
||||
GROUPS_UNIX = "onGroupListUpdate",
|
||||
FRIENDS = "onBuddyListChange"
|
||||
}
|
||||
|
||||
interface NTQQApiReturnData<PayloadType=unknown> extends Array<any> {
|
||||
@@ -32,14 +34,14 @@ interface NTQQApiReturnData<PayloadType=unknown> extends Array<any> {
|
||||
|
||||
let receiveHooks: Array<{
|
||||
method: ReceiveCmd,
|
||||
hookFunc: (payload: any) => void
|
||||
hookFunc: (payload: any) => void,
|
||||
id: string
|
||||
}> = []
|
||||
|
||||
export function hookNTQQApiReceive(window: BrowserWindow) {
|
||||
const originalSend = window.webContents.send;
|
||||
const patchSend = (channel: string, ...args: NTQQApiReturnData) => {
|
||||
// 判断是否是列表
|
||||
log(`received ntqq api message: ${channel}`, JSON.stringify(args))
|
||||
// log(`received ntqq api message: ${channel}`, JSON.stringify(args))
|
||||
if (args?.[1] instanceof Array) {
|
||||
for (let receiveData of args?.[1]) {
|
||||
const ntQQApiMethodName = receiveData.cmdName;
|
||||
@@ -73,32 +75,53 @@ export function hookNTQQApiReceive(window: BrowserWindow) {
|
||||
window.webContents.send = patchSend;
|
||||
}
|
||||
|
||||
export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (payload: PayloadType) => void) {
|
||||
export function registerReceiveHook<PayloadType>(method: ReceiveCmd, hookFunc: (payload: PayloadType) => void): string {
|
||||
const id = uuidv4()
|
||||
receiveHooks.push({
|
||||
method,
|
||||
hookFunc
|
||||
hookFunc,
|
||||
id
|
||||
})
|
||||
return id;
|
||||
}
|
||||
|
||||
function updateGroups(_groups: Group[]){
|
||||
export function removeReceiveHook(id: string){
|
||||
const index = receiveHooks.findIndex(h=>h.id === id)
|
||||
receiveHooks.splice(index, 1);
|
||||
}
|
||||
|
||||
async function updateGroups(_groups: Group[]){
|
||||
for(let group of _groups){
|
||||
let existGroup = groups.find(g=>g.groupCode == group.groupCode)
|
||||
if (!existGroup){
|
||||
groups.push(group)
|
||||
log("update group")
|
||||
let _membeers = await NTQQApi.getGroupMembers(group.groupCode)
|
||||
if (_membeers){
|
||||
group.members = _membeers
|
||||
}
|
||||
log("update group members", group.members)
|
||||
}
|
||||
else{
|
||||
Object.assign(existGroup, group);
|
||||
group.members = [...existGroup.members]
|
||||
}
|
||||
}
|
||||
groups.length = 0;
|
||||
groups.push(..._groups)
|
||||
}
|
||||
|
||||
registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS, (payload)=>updateGroups(payload.groupList))
|
||||
registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS_UNIX, (payload)=>updateGroups(payload.groupList))
|
||||
|
||||
registerReceiveHook<any>(ReceiveCmd.USER_INFO, (payload)=>{
|
||||
log("user info", payload);
|
||||
registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS, (payload)=>updateGroups(payload.groupList).then())
|
||||
registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS_UNIX, (payload)=>updateGroups(payload.groupList).then())
|
||||
registerReceiveHook<{data:{categoryId: number, categroyName: string, categroyMbCount: number, buddyList: User[]}[]}>(ReceiveCmd.FRIENDS, payload=>{
|
||||
friends.length = 0
|
||||
for (const fData of payload.data) {
|
||||
friends.push(...fData.buddyList)
|
||||
}
|
||||
})
|
||||
|
||||
// registerReceiveHook<any>(ReceiveCmd.USER_INFO, (payload)=>{
|
||||
// log("user info", payload);
|
||||
// })
|
||||
|
||||
registerReceiveHook<{ msgList: Array<RawMessage> }>(ReceiveCmd.UPDATE_MSG, (payload) => {
|
||||
for (const message of payload.msgList) {
|
||||
msgHistory[message.msgId] = message;
|
||||
|
@@ -1,13 +1,12 @@
|
||||
import {ipcMain} from "electron";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import {hookApiCallbacks} from "./hook";
|
||||
import {log} from "../common/utils";
|
||||
import { ChatType } from "./types";
|
||||
import { ipcMain } from "electron";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { ReceiveCmd, hookApiCallbacks, registerReceiveHook, removeReceiveHook } from "./hook";
|
||||
import { log } from "../common/utils";
|
||||
import { ChatType, Friend, SelfInfo, User } from "./types";
|
||||
import { Group } from "./types";
|
||||
import { GroupMember } from "./types";
|
||||
import { RawMessage } from "./types";
|
||||
import { User } from "./types";
|
||||
import {SendMessageElement} from "./types";
|
||||
import { SendMessageElement } from "./types";
|
||||
|
||||
interface IPCReceiveEvent {
|
||||
eventName: string
|
||||
@@ -31,7 +30,7 @@ export enum NTQQApiMethod {
|
||||
LIKE_FRIEND = "nodeIKernelProfileLikeService/setBuddyProfileLike",
|
||||
UPDATE_MSG = "nodeIKernelMsgListener/onMsgInfoListUpdate",
|
||||
SELF_INFO = "fetchAuthData",
|
||||
FRIENDS = "nodeIKernelProfileService/getBuddyProfileList",
|
||||
FRIENDS = "nodeIKernelBuddyService/getBuddyList",
|
||||
GROUPS = "nodeIKernelGroupService/getGroupList",
|
||||
GROUP_MEMBER_SCENE = "nodeIKernelGroupService/createMemberListScene",
|
||||
GROUP_MEMBERS = "nodeIKernelGroupService/getNextMemberList",
|
||||
@@ -58,26 +57,65 @@ export interface Peer {
|
||||
guildId?: ""
|
||||
}
|
||||
|
||||
enum CallBackType {
|
||||
UUID,
|
||||
METHOD
|
||||
}
|
||||
|
||||
function callNTQQApi<ReturnType>(channel: NTQQApiChannel, className: NTQQApiClass, methodName: NTQQApiMethod, args: unknown[] = []) {
|
||||
|
||||
function callNTQQApi<ReturnType>(channel: NTQQApiChannel, className: NTQQApiClass, methodName: NTQQApiMethod, args: unknown[] = [], cbCmd: ReceiveCmd | null = null, timeout = 5) {
|
||||
const uuid = uuidv4();
|
||||
// log("callNTQQApi", channel, className, methodName, args, uuid)
|
||||
return new Promise((resolve: (data: ReturnType) => void, reject) => {
|
||||
// log("callNTQQApiPromise", channel, className, methodName, args, uuid)
|
||||
hookApiCallbacks[uuid] = resolve;
|
||||
const _timeout = timeout * 1000
|
||||
let success = false
|
||||
if (!cbCmd) {
|
||||
// QQ后端会返回结果,并且可以插根据uuid识别
|
||||
hookApiCallbacks[uuid] = (r: ReturnType) => {
|
||||
success = true
|
||||
resolve(r)
|
||||
};
|
||||
}
|
||||
else {
|
||||
// 这里的callback比较特殊,QQ后端先返回是否调用成功,再返回一条结果数据
|
||||
hookApiCallbacks[uuid] = (result: GeneralCallResult) => {
|
||||
log(`${methodName} callback`, result)
|
||||
if (result.result == 0) {
|
||||
const hookId = registerReceiveHook<ReturnType>(cbCmd, (payload) => {
|
||||
log(methodName, "second callback", cbCmd, payload);
|
||||
removeReceiveHook(hookId);
|
||||
success = true
|
||||
resolve(payload);
|
||||
})
|
||||
}
|
||||
else {
|
||||
success = true
|
||||
reject(`ntqq api call failed, ${result.errMsg}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
// log("ntqq api timeout", success, channel, className, methodName)
|
||||
if (!success) {
|
||||
log(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
|
||||
reject(`ntqq api timeout ${channel}, ${className}, ${methodName}`)
|
||||
}
|
||||
}, _timeout)
|
||||
|
||||
ipcMain.emit(
|
||||
channel,
|
||||
{},
|
||||
{type: 'request', callbackId: uuid, eventName: className + "-" + channel[channel.length - 1]},
|
||||
{ type: 'request', callbackId: uuid, eventName: className + "-" + channel[channel.length - 1] },
|
||||
[methodName, ...args],
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage)=>void) | null> = {}// peerUid: callbackFunnc
|
||||
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {}// peerUid: callbackFunnc
|
||||
|
||||
interface GeneralCallResult{
|
||||
result:0,
|
||||
interface GeneralCallResult {
|
||||
result: number, // 0: success
|
||||
errMsg: string
|
||||
}
|
||||
|
||||
@@ -97,41 +135,63 @@ export class NTQQApi {
|
||||
}
|
||||
|
||||
static getSelfInfo() {
|
||||
return callNTQQApi<User>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.GLOBAL_DATA, NTQQApiMethod.SELF_INFO, [])
|
||||
return callNTQQApi<SelfInfo>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.GLOBAL_DATA, NTQQApiMethod.SELF_INFO, [], null, 2)
|
||||
|
||||
}
|
||||
|
||||
static getFriends(forced = false) {
|
||||
return callNTQQApi<GeneralCallResult>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.FRIENDS, [{force_update: forced}, undefined])
|
||||
}
|
||||
|
||||
static getGroups(forced = false) {
|
||||
return callNTQQApi<GeneralCallResult>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUPS, [{force_update: forced}, undefined])
|
||||
}
|
||||
|
||||
static async getGroupMembers(groupQQ: string, num = 5000) {
|
||||
const sceneId = callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBER_SCENE, [{
|
||||
groupCode: groupQQ,
|
||||
scene: "groupMemberList_MainWindow"
|
||||
}]
|
||||
)
|
||||
return callNTQQApi<GroupMember[]>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBERS,
|
||||
[{
|
||||
sceneId: sceneId,
|
||||
num: num
|
||||
},
|
||||
null
|
||||
])
|
||||
}
|
||||
|
||||
static async getUserInfo(uid: string) {
|
||||
const result = await callNTQQApi<GeneralCallResult>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.USER_INFO,
|
||||
[{force: true, uids: [uid]}, undefined])
|
||||
log("get user info result", result);
|
||||
return result[0].payload.profiles.get(uid);
|
||||
|
||||
const result = await callNTQQApi<{ info: User }>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.USER_INFO,
|
||||
[{ force: true, uids: [uid] }, undefined], ReceiveCmd.USER_INFO)
|
||||
return result.info
|
||||
|
||||
}
|
||||
|
||||
// static async getFriends(forced = false) {
|
||||
// const data = await callNTQQApi<{ data: { categoryId: number, categroyName: string, categroyMbCount: number, buddyList: Friend[] }[] }>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.FRIENDS, [{ force_update: forced }, undefined], ReceiveCmd.FRIENDS)
|
||||
// let _friends: Friend[] = [];
|
||||
// for (const fData of data.data) {
|
||||
// _friends.push(...fData.buddyList)
|
||||
// }
|
||||
// return _friends
|
||||
// }
|
||||
|
||||
// static async getGroups(forced = false) {
|
||||
// let cbCmd = ReceiveCmd.GROUPS
|
||||
// if (process.platform != "win32") {
|
||||
// cbCmd = ReceiveCmd.GROUPS_UNIX
|
||||
// }
|
||||
// const result = await callNTQQApi<{ updateType: number, groupList: Group[] }>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUPS, [{ force_update: forced }, undefined], cbCmd)
|
||||
// return result.groupList
|
||||
// }
|
||||
|
||||
static async getGroupMembers(groupQQ: string, num = 3000) {
|
||||
const sceneId = await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBER_SCENE, [{
|
||||
groupCode: groupQQ,
|
||||
scene: "groupMemberList_MainWindow"
|
||||
}])
|
||||
// log("get group member sceneId", sceneId);
|
||||
try {
|
||||
const result = await callNTQQApi<{result:{infos: any}}>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBERS,
|
||||
[{
|
||||
sceneId: sceneId,
|
||||
num: num
|
||||
},
|
||||
null
|
||||
])
|
||||
// log("members info", typeof result.result.infos, Object.keys(result.result.infos))
|
||||
let values = result.result.infos.values()
|
||||
|
||||
values = Array.from(values) as GroupMember[]
|
||||
// log("members info", values);
|
||||
return values
|
||||
} catch (e) {
|
||||
log(`get group ${groupQQ} members failed`, e)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static getFileType(filePath: string) {
|
||||
return callNTQQApi<{
|
||||
ext: string
|
||||
@@ -184,40 +244,40 @@ export class NTQQApi {
|
||||
}
|
||||
}
|
||||
|
||||
static recallMsg(peer: Peer, msgIds: string[]){
|
||||
return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.RECALL_MSG, [{peer, msgIds}, null])
|
||||
static recallMsg(peer: Peer, msgIds: string[]) {
|
||||
return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.RECALL_MSG, [{ peer, msgIds }, null])
|
||||
}
|
||||
|
||||
static sendMsg(peer: Peer, msgElements: SendMessageElement[]){
|
||||
static sendMsg(peer: Peer, msgElements: SendMessageElement[]) {
|
||||
const sendTimeout = 10 * 1000
|
||||
|
||||
return new Promise<RawMessage>((resolve, reject)=>{
|
||||
return new Promise<RawMessage>((resolve, reject) => {
|
||||
const peerUid = peer.peerUid;
|
||||
let usingTime = 0;
|
||||
let success = false;
|
||||
|
||||
const checkSuccess = ()=>{
|
||||
if (!success){
|
||||
const checkSuccess = () => {
|
||||
if (!success) {
|
||||
sendMessagePool[peerUid] = null;
|
||||
reject("发送超时")
|
||||
}
|
||||
}
|
||||
setTimeout(checkSuccess, sendTimeout);
|
||||
|
||||
const checkLastSend = ()=>{
|
||||
const checkLastSend = () => {
|
||||
let lastSending = sendMessagePool[peerUid]
|
||||
if (sendTimeout < usingTime){
|
||||
if (sendTimeout < usingTime) {
|
||||
sendMessagePool[peerUid] = null;
|
||||
reject("发送超时")
|
||||
}
|
||||
if (!!lastSending){
|
||||
if (!!lastSending) {
|
||||
// log("有正在发送的消息,等待中...")
|
||||
usingTime += 100;
|
||||
setTimeout(checkLastSend, 100);
|
||||
}
|
||||
else{
|
||||
else {
|
||||
log("可以进行发送消息,设置发送成功回调", sendMessagePool)
|
||||
sendMessagePool[peerUid] = (rawMessage: RawMessage)=>{
|
||||
sendMessagePool[peerUid] = (rawMessage: RawMessage) => {
|
||||
success = true;
|
||||
sendMessagePool[peerUid] = null;
|
||||
resolve(rawMessage);
|
||||
|
@@ -1,15 +1,18 @@
|
||||
|
||||
export interface User {
|
||||
uid: string; // 加密的字符串
|
||||
uin: string; // QQ号
|
||||
nick: string;
|
||||
avatarUrl?: string;
|
||||
longNick: string; // 签名
|
||||
raw: {
|
||||
remark: string;
|
||||
};
|
||||
longNick?: string; // 签名
|
||||
remark?: string
|
||||
}
|
||||
|
||||
export interface SelfInfo extends User{
|
||||
|
||||
}
|
||||
|
||||
export interface Friend extends User{}
|
||||
|
||||
export interface Group{
|
||||
groupCode: string,
|
||||
maxMember: number,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import {OB11MessageDataType, OB11GroupMemberRole, OB11Message, OB11MessageData, OB11Group, OB11GroupMember, Friend} from "./types";
|
||||
import { AtType, ChatType, Group, GroupMember, RawMessage, User } from '../ntqqapi/types';
|
||||
import {getFriend, getGroupMember, getHistoryMsgBySeq, msgHistory, selfInfo} from "../common/data";
|
||||
import {file2base64, getConfigUtil} from "../common/utils";
|
||||
import {OB11MessageDataType, OB11GroupMemberRole, OB11Message, OB11MessageData, OB11Group, OB11GroupMember, OB11User} from "./types";
|
||||
import { AtType, ChatType, Group, GroupMember, RawMessage, SelfInfo, User } from '../ntqqapi/types';
|
||||
import { getFriend, getGroupMember, getHistoryMsgBySeq, selfInfo } from '../common/data';
|
||||
import {file2base64, getConfigUtil, log} from "../common/utils";
|
||||
|
||||
|
||||
export class OB11Constructor {
|
||||
@@ -9,7 +9,7 @@ export class OB11Constructor {
|
||||
const {enableBase64} = getConfigUtil().getConfig()
|
||||
const message_type = msg.chatType == ChatType.group ? "group" : "private";
|
||||
const resMsg: OB11Message = {
|
||||
self_id: selfInfo.user_id,
|
||||
self_id: selfInfo.uin,
|
||||
user_id: msg.senderUin,
|
||||
time: parseInt(msg.msgTime) || 0,
|
||||
message_id: msg.msgId,
|
||||
@@ -36,7 +36,7 @@ export class OB11Constructor {
|
||||
resMsg.sub_type = "friend"
|
||||
const friend = await getFriend(msg.senderUin);
|
||||
if (friend) {
|
||||
resMsg.sender.nickname = friend.nickName;
|
||||
resMsg.sender.nickname = friend.nick;
|
||||
}
|
||||
} else if (msg.chatType == ChatType.temp) {
|
||||
resMsg.sub_type = "group"
|
||||
@@ -119,16 +119,23 @@ export class OB11Constructor {
|
||||
return resMsg;
|
||||
}
|
||||
|
||||
static friend(friend: User): Friend{
|
||||
static friend(friend: User): OB11User{
|
||||
return {
|
||||
user_id: friend.uin,
|
||||
nickname: friend.nickName,
|
||||
remark: friend.raw.remark
|
||||
nickname: friend.nick,
|
||||
remark: friend.remark
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static friends(friends: User[]): Friend[]{
|
||||
static selfInfo(selfInfo: SelfInfo): OB11User{
|
||||
return {
|
||||
user_id: selfInfo.uin,
|
||||
nickname: selfInfo.nick
|
||||
}
|
||||
}
|
||||
|
||||
static friends(friends: User[]): OB11User[]{
|
||||
return friends.map(OB11Constructor.friend)
|
||||
}
|
||||
|
||||
@@ -150,6 +157,7 @@ export class OB11Constructor {
|
||||
}
|
||||
|
||||
static groupMembers(group: Group): OB11GroupMember[]{
|
||||
log("construct ob11 group members", group)
|
||||
return group.members.map(m=>OB11Constructor.groupMember(group.groupCode, m))
|
||||
}
|
||||
|
||||
|
331
src/onebot11/server.ts
Normal file
331
src/onebot11/server.ts
Normal file
@@ -0,0 +1,331 @@
|
||||
import { getConfigUtil, log } from "../common/utils";
|
||||
|
||||
const express = require("express");
|
||||
import { Request } from 'express';
|
||||
import { Response } from 'express';
|
||||
|
||||
const JSONbig = require('json-bigint')({ storeAsString: true });
|
||||
import { AtType, ChatType, Group, SelfInfo } from "../ntqqapi/types";
|
||||
import { friends, getGroup, getGroupMember, getStrangerByUin, groups, msgHistory, selfInfo } from "../common/data";
|
||||
import { OB11ApiName, OB11Message, OB11Return, OB11MessageData, OB11Group, OB11GroupMember, OB11PostSendMsg, OB11MessageDataType, OB11User } from './types';
|
||||
import { OB11Constructor } from "./constructor";
|
||||
import { NTQQApi } from "../ntqqapi/ntcall";
|
||||
import { Peer } from "../ntqqapi/ntcall";
|
||||
import { SendMessageElement } from "../ntqqapi/types";
|
||||
import { SendMsgElementConstructor } from "../ntqqapi/constructor";
|
||||
import { uri2local } from "./utils";
|
||||
import { v4 as uuid4 } from 'uuid';
|
||||
|
||||
|
||||
// @SiberianHusky 2021-08-15
|
||||
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
||||
function checkUri(uri: string): boolean {
|
||||
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/;
|
||||
return pattern.test(uri);
|
||||
}
|
||||
|
||||
for (let msg of sendMsgList) {
|
||||
if (msg["type"] && msg["data"]) {
|
||||
let type = msg["type"];
|
||||
let data = msg["data"];
|
||||
if (type === "text" && !data["text"]) {
|
||||
return 400;
|
||||
} else if (["image", "voice", "record"].includes(type)) {
|
||||
if (!data["file"]) {
|
||||
return 400;
|
||||
} else {
|
||||
if (checkUri(data["file"])) {
|
||||
return 200;
|
||||
} else {
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (type === "at" && !data["qq"]) {
|
||||
return 400;
|
||||
} else if (type === "reply" && !data["id"]) {
|
||||
return 400;
|
||||
}
|
||||
} else {
|
||||
return 400
|
||||
}
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
|
||||
// ==end==
|
||||
|
||||
|
||||
class OB11Response {
|
||||
static res<T>(data: T, status: number = 0, message: string = ""): OB11Return<T> {
|
||||
return {
|
||||
status: status,
|
||||
retcode: status,
|
||||
data: data,
|
||||
message: message
|
||||
}
|
||||
}
|
||||
static ok<T>(data: T) {
|
||||
return OB11Response.res<T>(data)
|
||||
}
|
||||
static error(err: string) {
|
||||
return OB11Response.res(null, -1, err)
|
||||
}
|
||||
}
|
||||
|
||||
const expressAPP = express();
|
||||
expressAPP.use(express.urlencoded({ extended: true, limit: "500mb" }));
|
||||
|
||||
expressAPP.use((req, res, next) => {
|
||||
let data = '';
|
||||
req.on('data', chunk => {
|
||||
data += chunk.toString();
|
||||
});
|
||||
req.on('end', () => {
|
||||
if (data) {
|
||||
try {
|
||||
// log("receive raw", data)
|
||||
req.body = JSONbig.parse(data);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
});
|
||||
// expressAPP.use(express.json({
|
||||
// limit: '500mb',
|
||||
// verify: (req: any, res: any, buf: any, encoding: any) => {
|
||||
// req.rawBody = buf;
|
||||
// }
|
||||
// }));
|
||||
|
||||
export function startExpress(port: number) {
|
||||
|
||||
expressAPP.get('/', (req: Request, res: Response) => {
|
||||
res.send('llonebot已启动');
|
||||
})
|
||||
|
||||
expressAPP.listen(port, "0.0.0.0", () => {
|
||||
console.log(`llonebot started 0.0.0.0:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function postMsg(msg: OB11Message) {
|
||||
const { reportSelfMessage } = getConfigUtil().getConfig()
|
||||
if (!reportSelfMessage) {
|
||||
if (msg.user_id == selfInfo.uin) {
|
||||
return
|
||||
}
|
||||
}
|
||||
for (const host of getConfigUtil().getConfig().hosts) {
|
||||
fetch(host, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-self-id": selfInfo.uin
|
||||
},
|
||||
body: JSON.stringify(msg)
|
||||
}).then((res: any) => {
|
||||
log(`新消息事件上报成功: ${host} ` + JSON.stringify(msg));
|
||||
}, (err: any) => {
|
||||
log(`新消息事件上报失败: ${host} ` + err + JSON.stringify(msg));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let routers: Record<string, (payload: any) => Promise<OB11Return<any>>> = {};
|
||||
|
||||
function registerRouter<PayloadType, ReturnDataType>(action: OB11ApiName, handle: (payload: PayloadType) => Promise<OB11Return<ReturnDataType | null>>) {
|
||||
let url = action.toString()
|
||||
if (!action.startsWith("/")) {
|
||||
url = "/" + action
|
||||
}
|
||||
async function _handle(res: Response, payload: PayloadType) {
|
||||
log("receive post data", url, payload)
|
||||
try {
|
||||
const result = await handle(payload)
|
||||
res.send(result)
|
||||
}
|
||||
catch (e) {
|
||||
log(e.stack);
|
||||
res.send(OB11Response.error(e.stack.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
expressAPP.post(url, (req: Request, res: Response) => {
|
||||
_handle(res, req.body).then()
|
||||
});
|
||||
expressAPP.get(url, (req: Request, res: Response) => {
|
||||
_handle(res, req.query as any).then()
|
||||
});
|
||||
routers[url] = handle
|
||||
}
|
||||
|
||||
registerRouter<{ message_id: string }, OB11Message>("get_msg", async (payload) => {
|
||||
log("history msg ids", Object.keys(msgHistory));
|
||||
const msg = msgHistory[payload.message_id.toString()]
|
||||
if (msg) {
|
||||
const msgData = await OB11Constructor.message(msg);
|
||||
return OB11Response.ok(msgData)
|
||||
} else {
|
||||
return OB11Response.error("消息不存在")
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{}, OB11User>("get_login_info", async (payload) => {
|
||||
return OB11Response.ok(OB11Constructor.selfInfo(selfInfo));
|
||||
})
|
||||
|
||||
registerRouter<{}, OB11User[]>("get_friend_list", async (payload) => {
|
||||
return OB11Response.ok(OB11Constructor.friends(friends));
|
||||
})
|
||||
|
||||
registerRouter<{}, OB11Group[]>("get_group_list", async (payload) => {
|
||||
return OB11Response.ok(OB11Constructor.groups(groups));
|
||||
})
|
||||
|
||||
|
||||
registerRouter<{ group_id: number }, OB11Group[]>("get_group_info", async (payload) => {
|
||||
const group = await getGroup(payload.group_id.toString())
|
||||
if (group) {
|
||||
return OB11Response.ok(OB11Constructor.groups(groups));
|
||||
}
|
||||
else {
|
||||
return OB11Response.error(`群${payload.group_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{ group_id: number }, OB11GroupMember[]>("get_group_member_list", async (payload) => {
|
||||
|
||||
const group = await getGroup(payload.group_id.toString());
|
||||
if (group) {
|
||||
if (!group.members?.length){
|
||||
group.members = await NTQQApi.getGroupMembers(payload.group_id.toString())
|
||||
}
|
||||
return OB11Response.ok(OB11Constructor.groupMembers(group));
|
||||
}
|
||||
else {
|
||||
return OB11Response.error(`群${payload.group_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{ group_id: number, user_id: number }, OB11GroupMember>("get_group_member_info", async (payload) => {
|
||||
const member = await getGroupMember(payload.group_id.toString(), payload.user_id.toString())
|
||||
if (member) {
|
||||
return OB11Response.ok(OB11Constructor.groupMember(payload.group_id.toString(), member))
|
||||
}
|
||||
else {
|
||||
return OB11Response.error(`群成员${payload.user_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
const handleSendMsg = async (payload) => {
|
||||
const peer: Peer = {
|
||||
chatType: ChatType.friend,
|
||||
peerUid: ""
|
||||
}
|
||||
let group: Group | undefined = undefined;
|
||||
if (payload?.group_id) {
|
||||
group = await getGroup(payload.group_id.toString())
|
||||
if (!group) {
|
||||
return OB11Response.error(`群${payload.group_id}不存在`)
|
||||
}
|
||||
peer.chatType = ChatType.group
|
||||
// peer.name = group.name
|
||||
peer.peerUid = group.groupCode
|
||||
}
|
||||
else if (payload?.user_id) {
|
||||
const friend = friends.find(f => f.uin == payload.user_id.toString())
|
||||
if (friend) {
|
||||
// peer.name = friend.nickName
|
||||
peer.peerUid = friend.uid
|
||||
}
|
||||
else {
|
||||
peer.chatType = ChatType.temp
|
||||
const tempUser = getStrangerByUin(payload.user_id.toString())
|
||||
if (!tempUser) {
|
||||
return OB11Response.error(`找不到私聊对象${payload.user_id}`)
|
||||
}
|
||||
// peer.name = tempUser.nickName
|
||||
peer.peerUid = tempUser.uid
|
||||
}
|
||||
}
|
||||
if (typeof payload.message === "string") {
|
||||
payload.message = [{
|
||||
type: OB11MessageDataType.text,
|
||||
data: {
|
||||
text: payload.message
|
||||
}
|
||||
}] as OB11MessageData[]
|
||||
}
|
||||
else if (!Array.isArray(payload.message)) {
|
||||
payload.message = [payload.message]
|
||||
}
|
||||
const sendElements: SendMessageElement[] = []
|
||||
for (let sendMsg of payload.message) {
|
||||
switch (sendMsg.type) {
|
||||
case OB11MessageDataType.text: {
|
||||
const text = sendMsg.data?.text;
|
||||
if (text) {
|
||||
sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text))
|
||||
}
|
||||
} break;
|
||||
case OB11MessageDataType.at: {
|
||||
let atQQ = sendMsg.data?.qq;
|
||||
if (atQQ) {
|
||||
atQQ = atQQ.toString()
|
||||
if (atQQ === "all") {
|
||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员"))
|
||||
}
|
||||
else {
|
||||
const atMember = group?.members.find(m => m.uin == atQQ)
|
||||
if (atMember) {
|
||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick))
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case OB11MessageDataType.reply: {
|
||||
let replyMsgId = sendMsg.data.id;
|
||||
if (replyMsgId) {
|
||||
replyMsgId = replyMsgId.toString()
|
||||
const replyMsg = msgHistory[replyMsgId]
|
||||
if (replyMsg) {
|
||||
sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsgId, replyMsg.senderUin, replyMsg.senderUin))
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case OB11MessageDataType.image: {
|
||||
const file = sendMsg.data?.file
|
||||
if (file) {
|
||||
const picPath = await (await uri2local(uuid4(), file)).path
|
||||
if (picPath) {
|
||||
sendElements.push(await SendMsgElementConstructor.pic(picPath))
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case OB11MessageDataType.voice: {
|
||||
const file = sendMsg.data?.file
|
||||
if (file) {
|
||||
const voicePath = await (await uri2local(uuid4(), file)).path
|
||||
if (voicePath) {
|
||||
sendElements.push(await SendMsgElementConstructor.ptt(voicePath))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log("send msg:", peer, sendElements)
|
||||
try {
|
||||
const returnMsg = await NTQQApi.sendMsg(peer, sendElements)
|
||||
return OB11Response.ok({ message_id: returnMsg.msgId })
|
||||
} catch (e) {
|
||||
return OB11Response.error(e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
registerRouter<OB11PostSendMsg, { message_id: string }>("send_msg", handleSendMsg)
|
||||
registerRouter<OB11PostSendMsg, { message_id: string }>("send_private_msg", handleSendMsg)
|
||||
registerRouter<OB11PostSendMsg, { message_id: string }>("send_group_msg", handleSendMsg)
|
@@ -1,9 +1,9 @@
|
||||
import {SelfInfo} from "../common/types";
|
||||
import { AtType } from "../ntqqapi/types";
|
||||
import { RawMessage } from "../ntqqapi/types";
|
||||
import { User } from "../ntqqapi/types";
|
||||
|
||||
export interface Friend extends SelfInfo{
|
||||
export interface OB11User{
|
||||
user_id: string;
|
||||
nickname: string;
|
||||
remark?: string
|
||||
}
|
||||
|
||||
|
@@ -1,63 +1,18 @@
|
||||
// Electron 主进程 与 渲染进程 交互的桥梁
|
||||
|
||||
import {Config, SelfInfo} from "./common/types";
|
||||
import { Group } from "./ntqqapi/types";
|
||||
import { RawMessage } from "./ntqqapi/types";
|
||||
import { User } from "./ntqqapi/types";
|
||||
import {Config} from "./common/types";
|
||||
import {
|
||||
CHANNEL_DOWNLOAD_FILE,
|
||||
CHANNEL_GET_CONFIG,
|
||||
CHANNEL_SET_SELF_INFO,
|
||||
CHANNEL_LOG,
|
||||
CHANNEL_POST_ONEBOT_DATA,
|
||||
CHANNEL_RECALL_MSG,
|
||||
CHANNEL_SEND_MSG,
|
||||
CHANNEL_SET_CONFIG,
|
||||
CHANNEL_START_HTTP_SERVER,
|
||||
CHANNEL_UPDATE_FRIENDS,
|
||||
CHANNEL_UPDATE_GROUPS,
|
||||
CHANNEL_DELETE_FILE,
|
||||
CHANNEL_GET_RUNNING_STATUS,
|
||||
CHANNEL_FILE2BASE64,
|
||||
CHANNEL_GET_HISTORY_MSG,
|
||||
CHANNEL_SEND_BACK_MSG,
|
||||
} from "./common/channels";
|
||||
|
||||
|
||||
import {OB11Return, OB11SendMsgReturn} from "./onebot11/types";
|
||||
import { SendIPCMsgSession } from "./main/ipcsend";
|
||||
|
||||
|
||||
const {contextBridge} = require("electron");
|
||||
const {ipcRenderer} = require('electron');
|
||||
|
||||
// 在window对象下导出只读对象
|
||||
contextBridge.exposeInMainWorld("llonebot", {
|
||||
|
||||
postData: (data: any) => {
|
||||
ipcRenderer.send(CHANNEL_POST_ONEBOT_DATA, data);
|
||||
},
|
||||
updateGroups: (groups: Group[]) => {
|
||||
ipcRenderer.send(CHANNEL_UPDATE_GROUPS, groups);
|
||||
},
|
||||
updateFriends: (friends: User[]) => {
|
||||
ipcRenderer.send(CHANNEL_UPDATE_FRIENDS, friends);
|
||||
},
|
||||
sendSendMsgResult: (sessionId: string, msgResult: OB11SendMsgReturn)=>{
|
||||
ipcRenderer.send(CHANNEL_SEND_BACK_MSG, {
|
||||
id: sessionId,
|
||||
data: msgResult,
|
||||
});
|
||||
},
|
||||
|
||||
listenRecallMessage: (handle: (jsonData: {message_id: string}) => void) => {
|
||||
ipcRenderer.on(CHANNEL_RECALL_MSG, (event: any, args: {message_id: string}) => {
|
||||
handle(args)
|
||||
})
|
||||
},
|
||||
startExpress: () => {
|
||||
ipcRenderer.send(CHANNEL_START_HTTP_SERVER);
|
||||
},
|
||||
log: (data: any) => {
|
||||
ipcRenderer.send(CHANNEL_LOG, data);
|
||||
},
|
||||
@@ -67,20 +22,4 @@ contextBridge.exposeInMainWorld("llonebot", {
|
||||
getConfig: async () => {
|
||||
return ipcRenderer.invoke(CHANNEL_GET_CONFIG);
|
||||
},
|
||||
setSelfInfo(selfInfo: SelfInfo){
|
||||
ipcRenderer.invoke(CHANNEL_SET_SELF_INFO, selfInfo)
|
||||
},
|
||||
downloadFile: (arg: {uri: string, localFilePath: string}) => {
|
||||
return ipcRenderer.invoke(CHANNEL_DOWNLOAD_FILE, arg);
|
||||
},
|
||||
deleteFile: async (localFilePath: string[]) => {
|
||||
ipcRenderer.send(CHANNEL_DELETE_FILE, localFilePath);
|
||||
},
|
||||
getRunningStatus: () => {
|
||||
return ipcRenderer.invoke(CHANNEL_GET_RUNNING_STATUS);
|
||||
},
|
||||
getHistoryMsg: async (msgId: string):Promise<RawMessage> => {
|
||||
return await ipcRenderer.invoke(CHANNEL_GET_HISTORY_MSG, msgId)
|
||||
}
|
||||
// startExpress,
|
||||
});
|
@@ -1,3 +1,5 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
import { CHANNEL_LOG } from './common/channels';
|
||||
/// <reference path="./global.d.ts" />
|
||||
|
||||
|
||||
|
@@ -1,474 +0,0 @@
|
||||
import {getConfigUtil, log} from "../common/utils";
|
||||
|
||||
const express = require("express");
|
||||
import {Request, text} from 'express';
|
||||
import {Response} from 'express';
|
||||
|
||||
const JSONbig = require('json-bigint')({storeAsString: true});
|
||||
import {sendIPCRecallQQMsg, sendIPCSendQQMsg} from "../main/ipcsend";
|
||||
import {AtType, ChatType, Group, SelfInfo} from "../common/types";
|
||||
import {friends, getGroup, getGroupMember, getStrangerByUin, groups, msgHistory, selfInfo} from "../common/data";
|
||||
import { OB11ApiName, OB11Message, OB11Return, OB11MessageData, OB11Group, OB11GroupMember, OB11PostSendMsg, OB11MessageDataType, Friend } from '../onebot11/types';
|
||||
import {OB11Constructor} from "../onebot11/constructor";
|
||||
import { NTQQApi } from "../ntqqapi/ntcall";
|
||||
import { Peer } from "../ntqqapi/ntcall";
|
||||
import { ElementType, SendMessageElement } from "../ntqqapi/types";
|
||||
import { SendMsgElementConstructor } from "../ntqqapi/constructor";
|
||||
import { uri2local } from "../onebot11/utils";
|
||||
import { v4 as uuid4 } from 'uuid';
|
||||
|
||||
|
||||
// @SiberianHusky 2021-08-15
|
||||
function checkSendMessage(sendMsgList: OB11MessageData[]) {
|
||||
function checkUri(uri: string): boolean {
|
||||
const pattern = /^(file:\/\/|http:\/\/|https:\/\/|base64:\/\/)/;
|
||||
return pattern.test(uri);
|
||||
}
|
||||
|
||||
for (let msg of sendMsgList) {
|
||||
if (msg["type"] && msg["data"]) {
|
||||
let type = msg["type"];
|
||||
let data = msg["data"];
|
||||
if (type === "text" && !data["text"]) {
|
||||
return 400;
|
||||
} else if (["image", "voice", "record"].includes(type)) {
|
||||
if (!data["file"]) {
|
||||
return 400;
|
||||
} else {
|
||||
if (checkUri(data["file"])) {
|
||||
return 200;
|
||||
} else {
|
||||
return 400;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (type === "at" && !data["qq"]) {
|
||||
return 400;
|
||||
} else if (type === "reply" && !data["id"]) {
|
||||
return 400;
|
||||
}
|
||||
} else {
|
||||
return 400
|
||||
}
|
||||
}
|
||||
return 200;
|
||||
}
|
||||
|
||||
// ==end==
|
||||
|
||||
function constructReturnData<T>(data: T, status: number=0, message: string = ""): OB11Return<T> {
|
||||
return {
|
||||
status: status,
|
||||
retcode: status,
|
||||
data: data,
|
||||
message: message
|
||||
}
|
||||
}
|
||||
|
||||
function constructErrorReturn(err: string){
|
||||
return constructReturnData(null, -1, err);
|
||||
}
|
||||
|
||||
|
||||
function handlePost(jsonData: any, handleSendResult: (data: OB11Return<any>) => void) {
|
||||
log("API receive post:" + JSON.stringify(jsonData))
|
||||
if (!jsonData.params) {
|
||||
jsonData.params = JSON.parse(JSON.stringify(jsonData));
|
||||
delete jsonData.params.params;
|
||||
}
|
||||
let resData = {
|
||||
status: 0,
|
||||
retcode: 0,
|
||||
data: {},
|
||||
message: ''
|
||||
}
|
||||
|
||||
if (jsonData.action == "send_private_msg" || jsonData.action == "send_group_msg") {
|
||||
if (jsonData.action == "send_private_msg") {
|
||||
jsonData.message_type = "private"
|
||||
} else {
|
||||
jsonData.message_type = "group"
|
||||
}
|
||||
// @SiberianHuskY 2021-10-20 22:00:00
|
||||
resData.status = checkSendMessage(jsonData.message);
|
||||
if (resData.status == 200) {
|
||||
resData.message = "发送成功";
|
||||
resData.data = jsonData.message;
|
||||
sendIPCSendQQMsg(jsonData, handleSendResult);
|
||||
return;
|
||||
} else {
|
||||
resData.message = "发送失败, 请检查消息格式";
|
||||
resData.data = jsonData.message;
|
||||
}
|
||||
// == end ==
|
||||
} else if (jsonData.action == "get_group_list") {
|
||||
resData["data"] = groups.map(group => {
|
||||
return {
|
||||
group_id: group.uid,
|
||||
group_name: group.name,
|
||||
member_count: group.members?.length,
|
||||
group_members: group.members?.map(member => {
|
||||
return {
|
||||
user_id: member.uin,
|
||||
user_name: member.cardName || member.nick,
|
||||
user_display_name: member.cardName || member.nick
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
} else if (jsonData.action == "get_group_info") {
|
||||
let group = groups.find(group => group.uid == jsonData.params.group_id)
|
||||
if (group) {
|
||||
resData["data"] = {
|
||||
group_id: group.uid,
|
||||
group_name: group.name,
|
||||
member_count: group.members?.length,
|
||||
}
|
||||
}
|
||||
} else if (jsonData.action == "get_group_member_info") {
|
||||
let member = groups.find(group => group.uid == jsonData.params.group_id)?.members?.find(member => member.uin == jsonData.params.user_id)
|
||||
resData["data"] = {
|
||||
user_id: member?.uin,
|
||||
user_name: member?.nick,
|
||||
user_display_name: member?.cardName || member?.nick,
|
||||
nickname: member?.nick,
|
||||
card: member?.cardName,
|
||||
role: member && OB11Constructor.groupMemberRole(member.role),
|
||||
}
|
||||
} else if (jsonData.action == "get_group_member_list") {
|
||||
let group = groups.find(group => group.uid == jsonData.params.group_id)
|
||||
if (group) {
|
||||
resData["data"] = group?.members?.map(member => {
|
||||
return {
|
||||
user_id: member.uin,
|
||||
user_name: member.nick,
|
||||
user_display_name: member.cardName || member.nick,
|
||||
nickname: member.nick,
|
||||
card: member.cardName,
|
||||
role: OB11Constructor.groupMemberRole(member.role),
|
||||
}
|
||||
|
||||
}) || []
|
||||
} else {
|
||||
resData["data"] = []
|
||||
}
|
||||
} else if (jsonData.action == "get_friend_list") {
|
||||
resData["data"] = friends.map(friend => {
|
||||
return {
|
||||
user_id: friend.uin,
|
||||
user_name: friend.nickName,
|
||||
}
|
||||
})
|
||||
} else if (jsonData.action == "delete_msg") {
|
||||
sendIPCRecallQQMsg(jsonData.message_id)
|
||||
}
|
||||
return resData
|
||||
}
|
||||
|
||||
|
||||
const expressAPP = express();
|
||||
expressAPP.use(express.urlencoded({extended: true, limit: "500mb"}));
|
||||
|
||||
expressAPP.use((req, res, next) => {
|
||||
let data = '';
|
||||
req.on('data', chunk => {
|
||||
data += chunk.toString();
|
||||
});
|
||||
req.on('end', () => {
|
||||
if (data) {
|
||||
try {
|
||||
// log("receive raw", data)
|
||||
req.body = JSONbig.parse(data);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
}
|
||||
next();
|
||||
});
|
||||
});
|
||||
// expressAPP.use(express.json({
|
||||
// limit: '500mb',
|
||||
// verify: (req: any, res: any, buf: any, encoding: any) => {
|
||||
// req.rawBody = buf;
|
||||
// }
|
||||
// }));
|
||||
|
||||
export function startExpress(port: number) {
|
||||
|
||||
|
||||
// function parseToOnebot12(action: OB11ApiName) {
|
||||
// expressAPP.post('/' + action, (req: Request, res: Response) => {
|
||||
// let jsonData: PostDataSendMsg = req.body;
|
||||
// jsonData.action = action
|
||||
// let resData = handlePost(jsonData, (data: OB11Return<any>) => {
|
||||
// res.send(data)
|
||||
// })
|
||||
// if (resData) {
|
||||
// res.send(resData)
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
const actionList: OB11ApiName[] = ["get_login_info", "send_private_msg", "send_group_msg",
|
||||
"get_group_list", "get_friend_list", "delete_msg", "get_group_member_list", "get_group_member_info"]
|
||||
|
||||
// for (const action of actionList) {
|
||||
// parseToOnebot12(action as OB11ApiName)
|
||||
// }
|
||||
|
||||
expressAPP.get('/', (req: Request, res: Response) => {
|
||||
res.send('llonebot已启动');
|
||||
})
|
||||
|
||||
|
||||
// 处理POST请求的路由
|
||||
// expressAPP.post('/', (req: Request, res: Response) => {
|
||||
// let jsonData: PostDataSendMsg = req.body;
|
||||
// let resData = handlePost(jsonData, (data: OB11Return<any>) => {
|
||||
// res.send(data)
|
||||
// })
|
||||
// if (resData) {
|
||||
// res.send(resData)
|
||||
// }
|
||||
// });
|
||||
// expressAPP.post('/send_msg', (req: Request, res: Response) => {
|
||||
// let jsonData: PostDataSendMsg = req.body;
|
||||
// if (jsonData.message_type == "private") {
|
||||
// jsonData.action = "send_private_msg"
|
||||
// } else if (jsonData.message_type == "group") {
|
||||
// jsonData.action = "send_group_msg"
|
||||
// } else {
|
||||
// if (jsonData.params?.group_id) {
|
||||
// jsonData.action = "send_group_msg"
|
||||
// } else {
|
||||
// jsonData.action = "send_private_msg"
|
||||
// }
|
||||
// }
|
||||
// let resData = handlePost(jsonData, (data: OB11Return<any>) => {
|
||||
// res.send(data)
|
||||
// })
|
||||
// if (resData) {
|
||||
// res.send(resData)
|
||||
// }
|
||||
// })
|
||||
|
||||
expressAPP.listen(port, "0.0.0.0", () => {
|
||||
console.log(`llonebot started 0.0.0.0:${port}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function postMsg(msg: OB11Message) {
|
||||
const {reportSelfMessage} = getConfigUtil().getConfig()
|
||||
if (!reportSelfMessage) {
|
||||
if (msg.user_id == selfInfo.user_id) {
|
||||
return
|
||||
}
|
||||
}
|
||||
for (const host of getConfigUtil().getConfig().hosts) {
|
||||
fetch(host, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"x-self-id": selfInfo.user_id
|
||||
},
|
||||
body: JSON.stringify(msg)
|
||||
}).then((res: any) => {
|
||||
log(`新消息事件上报成功: ${host} ` + JSON.stringify(msg));
|
||||
}, (err: any) => {
|
||||
log(`新消息事件上报失败: ${host} ` + err + JSON.stringify(msg));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let routers: Record<string, (payload: any)=>Promise<OB11Return<any>>> = {};
|
||||
|
||||
function registerRouter<PayloadType, ReturnDataType>(action: OB11ApiName, handle: (payload: PayloadType) => Promise<OB11Return<ReturnDataType | null>>) {
|
||||
let url = action.toString()
|
||||
if (!action.startsWith("/")){
|
||||
url = "/" + action
|
||||
}
|
||||
async function _handle(res: Response, payload: PayloadType) {
|
||||
log("receive post data", url, payload)
|
||||
try{
|
||||
const result = await handle(payload)
|
||||
res.send(result)
|
||||
}
|
||||
catch(e){
|
||||
log(e.stack);
|
||||
res.send(constructErrorReturn(e.stack.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
expressAPP.post(url, (req: Request, res: Response) => {
|
||||
_handle(res, req.body).then()
|
||||
});
|
||||
expressAPP.get(url, (req: Request, res: Response) => {
|
||||
_handle(res, req.query as any).then()
|
||||
});
|
||||
routers[url] = handle
|
||||
}
|
||||
|
||||
registerRouter<{ message_id: string }, OB11Message>("get_msg", async (payload) => {
|
||||
log("history msg ids", Object.keys(msgHistory));
|
||||
const msg = msgHistory[payload.message_id.toString()]
|
||||
if (msg) {
|
||||
const msgData = await OB11Constructor.message(msg);
|
||||
return constructReturnData(msgData)
|
||||
} else {
|
||||
return constructErrorReturn("消息不存在")
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{}, SelfInfo>("get_login_info", async (payload)=>{
|
||||
return constructReturnData(selfInfo);
|
||||
})
|
||||
|
||||
registerRouter<{}, Friend[]>("get_friend_list", async (payload)=>{
|
||||
return constructReturnData(OB11Constructor.friends(friends));
|
||||
})
|
||||
|
||||
registerRouter<{}, OB11Group[]>("get_group_list", async (payload)=>{
|
||||
return constructReturnData(OB11Constructor.groups(groups));
|
||||
})
|
||||
|
||||
|
||||
registerRouter<{group_id: number}, OB11Group[]>("get_group_info", async (payload)=>{
|
||||
const group = await getGroup(payload.group_id.toString())
|
||||
if (group){
|
||||
return constructReturnData(OB11Constructor.groups(groups));
|
||||
}
|
||||
else{
|
||||
return constructErrorReturn(`群${payload.group_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{group_id: number}, OB11GroupMember[]>("get_group_member_list", async (payload)=>{
|
||||
|
||||
const group = await getGroup(payload.group_id.toString());
|
||||
if (group){
|
||||
return constructReturnData(OB11Constructor.groupMembers(group));
|
||||
}
|
||||
else{
|
||||
return constructErrorReturn(`群${payload.group_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
registerRouter<{group_id: number, user_id: number}, OB11GroupMember>("get_group_member_info", async (payload)=>{
|
||||
const member = await getGroupMember(payload.group_id.toString(), payload.user_id.toString())
|
||||
if (member){
|
||||
return constructReturnData(OB11Constructor.groupMember(payload.group_id.toString(), member))
|
||||
}
|
||||
else{
|
||||
return constructErrorReturn(`群成员${payload.user_id}不存在`)
|
||||
}
|
||||
})
|
||||
|
||||
const handleSendMsg = async (payload)=>{
|
||||
const peer: Peer = {
|
||||
chatType: ChatType.friend,
|
||||
peerUid: ""
|
||||
}
|
||||
let group: Group | undefined = undefined;
|
||||
if(payload?.group_id){
|
||||
group = groups.find(g=>g.uid == payload.group_id?.toString())
|
||||
if (!group){
|
||||
return constructErrorReturn(`群${payload.group_id}不存在`)
|
||||
}
|
||||
peer.chatType = ChatType.group
|
||||
// peer.name = group.name
|
||||
peer.peerUid = group.uid
|
||||
}
|
||||
else if (payload?.user_id){
|
||||
const friend = friends.find(f=>f.uin == payload.user_id.toString())
|
||||
if (friend){
|
||||
// peer.name = friend.nickName
|
||||
peer.peerUid = friend.uid
|
||||
}
|
||||
else{
|
||||
peer.chatType = ChatType.temp
|
||||
const tempUser = getStrangerByUin(payload.user_id.toString())
|
||||
if (!tempUser){
|
||||
return constructErrorReturn(`找不到私聊对象${payload.user_id}`)
|
||||
}
|
||||
// peer.name = tempUser.nickName
|
||||
peer.peerUid = tempUser.uid
|
||||
}
|
||||
}
|
||||
if (typeof payload.message === "string"){
|
||||
payload.message = [{
|
||||
type: OB11MessageDataType.text,
|
||||
data: {
|
||||
text: payload.message
|
||||
}
|
||||
}] as OB11MessageData[]
|
||||
}
|
||||
else if (!Array.isArray(payload.message)){
|
||||
payload.message = [payload.message]
|
||||
}
|
||||
const sendElements: SendMessageElement[] = []
|
||||
for (let sendMsg of payload.message){
|
||||
switch(sendMsg.type){
|
||||
case OB11MessageDataType.text: {
|
||||
const text = sendMsg.data?.text;
|
||||
if (text){
|
||||
sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text))
|
||||
}
|
||||
}break;
|
||||
case OB11MessageDataType.at: {
|
||||
let atQQ = sendMsg.data?.qq;
|
||||
if (atQQ){
|
||||
atQQ = atQQ.toString()
|
||||
if (atQQ === "all"){
|
||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员"))
|
||||
}
|
||||
else{
|
||||
const atMember = group?.members.find(m=>m.uin == atQQ)
|
||||
if (atMember){
|
||||
sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick))
|
||||
}
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case OB11MessageDataType.reply: {
|
||||
let replyMsgId = sendMsg.data.id;
|
||||
if (replyMsgId){
|
||||
replyMsgId = replyMsgId.toString()
|
||||
const replyMsg = msgHistory[replyMsgId]
|
||||
if (replyMsg){
|
||||
sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsgId, replyMsg.senderUin, replyMsg.senderUin))
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case OB11MessageDataType.image: {
|
||||
const file = sendMsg.data?.file
|
||||
if (file){
|
||||
const picPath = await (await uri2local(uuid4(), file)).path
|
||||
if (picPath){
|
||||
sendElements.push(await SendMsgElementConstructor.pic(picPath))
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case OB11MessageDataType.voice: {
|
||||
const file = sendMsg.data?.file
|
||||
if (file){
|
||||
const voicePath = await (await uri2local(uuid4(), file)).path
|
||||
if (voicePath){
|
||||
sendElements.push(await SendMsgElementConstructor.ptt(voicePath))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
log("send msg:", peer, sendElements)
|
||||
try{
|
||||
const returnMsg = await NTQQApi.sendMsg(peer, sendElements)
|
||||
return constructReturnData({message_id: returnMsg.msgId})
|
||||
}catch(e){
|
||||
return constructErrorReturn(e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
registerRouter<OB11PostSendMsg, {message_id: string}>("send_msg", handleSendMsg)
|
||||
registerRouter<OB11PostSendMsg, {message_id: string}>("send_private_msg", handleSendMsg)
|
||||
registerRouter<OB11PostSendMsg, {message_id: string}>("send_group_msg", handleSendMsg)
|
Reference in New Issue
Block a user