Q2TG/src/client/OicqClient.ts

159 lines
5.2 KiB
TypeScript
Raw Normal View History

2022-09-01 15:35:27 +00:00
import {
Client,
DiscussMessageEvent,
Friend,
Group,
GroupMessageEvent,
LogLevel,
Platform,
PrivateMessageEvent,
} from 'oicq';
import Buffer from 'buffer';
2022-02-23 06:09:54 +00:00
import { execSync } from 'child_process';
import random from '../utils/random';
import fs from 'fs';
import fsP from 'fs/promises';
import { Config } from 'oicq/lib/client';
import dataPath from '../helpers/dataPath';
import os from 'os';
2022-02-23 06:09:54 +00:00
2022-02-26 10:15:40 +00:00
const LOG_LEVEL: LogLevel = 'warn';
type MessageHandler = (event: PrivateMessageEvent | GroupMessageEvent) => Promise<boolean | void>
2022-02-23 06:09:54 +00:00
interface CreateOicqParams {
id: number;
2022-02-23 06:09:54 +00:00
uin: number;
password: string;
platform: Platform;
// 当需要验证手机时调用此方法,应该返回收到的手机验证码
2022-02-23 06:09:54 +00:00
onVerifyDevice: (phone: string) => Promise<string>;
// 当滑块时调用此方法,返回 ticker也可以返回假值改用扫码登录
onVerifySlider: (url: string) => Promise<string>;
// 扫码后返回
onQrCode: (image: Buffer) => Promise<void>;
}
// OicqExtended??
export default class OicqClient extends Client {
private readonly onMessageHandlers: Array<MessageHandler> = [];
private constructor(uin: number, public readonly id: number, conf?: Config) {
2022-02-23 06:09:54 +00:00
super(uin, conf);
}
private static existedBots = {} as { [id: number]: OicqClient };
2022-02-23 06:09:54 +00:00
public static create(params: CreateOicqParams) {
if (this.existedBots[params.id]) {
return Promise.resolve(this.existedBots[params.id]);
}
2022-02-23 06:09:54 +00:00
return new Promise<OicqClient>(async (resolve, reject) => {
async function loginDeviceHandler({ phone }: { url: string, phone: string }) {
client.sendSmsCode();
const code = await params.onVerifyDevice(phone);
if (code === 'qrsubmit') {
client.login();
}
else {
client.submitSmsCode(code);
}
2022-02-23 06:09:54 +00:00
}
async function loginSliderHandler({ url }: { url: string }) {
const res = await params.onVerifySlider(url);
if (res) {
client.submitSlider(res);
}
else {
client.login();
}
}
async function loginQrCodeHandler({ image }: { image: Buffer }) {
await params.onQrCode(image);
client.qrcodeLogin();
2022-02-23 06:09:54 +00:00
}
function loginErrorHandler({ message }: { code: number; message: string }) {
reject(message);
}
function successLoginHandler() {
client.off('system.login.device', loginDeviceHandler)
.off('system.login.slider', loginSliderHandler)
.off('system.login.qrcode', loginQrCodeHandler)
.off('system.login.error', loginErrorHandler)
.off('system.online', successLoginHandler)
.on('message', client.onMessage);
2022-02-23 06:09:54 +00:00
resolve(client);
}
if (!fs.existsSync(dataPath(`${params.uin}/device-${params.uin}.json`))) {
await fsP.mkdir(dataPath(params.uin.toString()), { recursive: true });
2022-02-23 06:09:54 +00:00
const device = {
product: 'Q2TG',
device: 'ANGELKAWAII2',
board: 'rainbowcat',
2022-02-23 06:09:54 +00:00
brand: random.pick('GOOGLE', 'XIAOMI', 'HUAWEI', 'SAMSUNG', 'SONY'),
model: 'rainbowcat',
wifi_ssid: random.pick('OpenWrt', `Redmi-${random.hex(4).toUpperCase()}`,
`MiWifi-${random.hex(4).toUpperCase()}`, `TP-LINK-${random.hex(6).toUpperCase()}`),
2022-02-23 06:09:54 +00:00
bootloader: random.pick('U-Boot', 'GRUB', 'gummiboot'),
android_id: random.hex(16),
proc_version: `${os.type()} version ${os.release()}`,
2022-02-23 06:09:54 +00:00
mac_address: `8c:85:90:${random.hex(2)}:${random.hex(2)}:${random.hex(2)}`.toUpperCase(),
ip_address: `192.168.${random.int(1, 200)}.${random.int(10, 250)}`,
incremental: random.int(0, 4294967295),
imei: random.imei(),
};
await fsP.writeFile(dataPath(`${params.uin}/device-${params.uin}.json`), JSON.stringify(device, null, 0), 'utf-8');
2022-02-23 06:09:54 +00:00
}
const client = new this(params.uin, params.id, {
2022-02-23 06:09:54 +00:00
platform: params.platform,
data_dir: dataPath(),
log_level: LOG_LEVEL,
2022-09-16 14:32:09 +00:00
ffmpeg_path: process.env.FFMPEG_PATH,
ffprobe_path: process.env.FFPROBE_PATH,
2022-02-23 06:09:54 +00:00
})
.on('system.login.device', loginDeviceHandler)
.on('system.login.slider', loginSliderHandler)
.on('system.login.qrcode', loginQrCodeHandler)
.on('system.login.error', loginErrorHandler)
.on('system.online', successLoginHandler);
this.existedBots[params.id] = client;
2022-02-23 06:09:54 +00:00
client.login(params.password);
});
}
private onMessage = async (event: PrivateMessageEvent | GroupMessageEvent | DiscussMessageEvent) => {
if (event.message_type === 'discuss') return;
for (const handler of this.onMessageHandlers) {
const res = await handler(event);
if (res) return;
}
};
public addNewMessageEventHandler(handler: MessageHandler) {
this.onMessageHandlers.push(handler);
}
public removeNewMessageEventHandler(handler: MessageHandler) {
this.onMessageHandlers.includes(handler) &&
this.onMessageHandlers.splice(this.onMessageHandlers.indexOf(handler), 1);
}
2022-09-01 15:35:27 +00:00
public getChat(roomId: number): Group | Friend {
2022-02-23 06:09:54 +00:00
if (roomId > 0) {
return this.pickFriend(roomId);
}
else {
return this.pickGroup(-roomId);
}
}
}