mirror of
https://github.com/crystelf/crystelf-admin.git
synced 2025-12-05 13:41:57 +00:00
108 lines
3.2 KiB
JavaScript
108 lines
3.2 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import { exec } from 'child_process';
|
|
import util from 'util';
|
|
import configControl from '../config/configControl.js';
|
|
|
|
const execAsync = util.promisify(exec);
|
|
|
|
export default class NapcatService {
|
|
constructor() {
|
|
const config = configControl.get('config')?.napcat || {};
|
|
this.basePath = config.basePath;
|
|
this.userPath = config.userPath;
|
|
if (!this.basePath || !this.userPath) {
|
|
logger.error('[crystelf-admin] 未检测到napcat配置..');
|
|
}
|
|
this.qrPath = path.join(this.basePath, 'cache', 'qrcode.png');
|
|
this.configPath = path.join(this.basePath, 'config');
|
|
}
|
|
|
|
/**
|
|
* nc登录方法
|
|
* @param qq qq号
|
|
* @param nickname 昵称
|
|
* @returns {Promise<unknown>}
|
|
*/
|
|
async login(qq, nickname) {
|
|
const shFile = path.join(this.userPath, `${qq}.sh`);
|
|
if (!fs.existsSync(this.userPath)) {
|
|
fs.mkdirSync(this.userPath, { recursive: true });
|
|
}
|
|
const userConfigFile = path.join(this.configPath, `onebot11_${qq}.json`);
|
|
if (!fs.existsSync(userConfigFile)) {
|
|
try {
|
|
const defaultConfigFile = path.join(configControl.get('config')?.path || '', 'napcat.json');
|
|
if (!fs.existsSync(defaultConfigFile)) {
|
|
logger.error(`[crystelf-admin] 默认配置文件不存在: ${defaultConfigFile}`);
|
|
}
|
|
fs.copyFileSync(defaultConfigFile, userConfigFile);
|
|
logger.info(`[crystelf-admin] 已复制默认配置到 ${userConfigFile}`);
|
|
} catch (err) {
|
|
logger.error(`[crystelf-admin] 复制默认配置失败: ${err.message}`);
|
|
}
|
|
}
|
|
if (!fs.existsSync(shFile)) {
|
|
const scriptContent = `#!/bin/bash\ncd "${this.basePath}"\n./napcat --qq ${qq}\n`;
|
|
fs.writeFileSync(shFile, scriptContent, { mode: 0o755 });
|
|
}
|
|
try {
|
|
await execAsync(`tmux has-session -t ${nickname}`);
|
|
// 存在就先干掉
|
|
await execAsync(`tmux kill-session -t ${nickname}`);
|
|
await execAsync(`tmux new -s ${nickname} -d "bash '${shFile}'"`);
|
|
} catch {
|
|
// 不存在再新建
|
|
await execAsync(`tmux new -s ${nickname} -d "bash '${shFile}'"`);
|
|
}
|
|
|
|
return await this.waitForQrUpdate();
|
|
}
|
|
|
|
/**
|
|
* 等待qrcode图像更新
|
|
* @param timeout
|
|
* @returns {Promise<unknown>}
|
|
*/
|
|
async waitForQrUpdate(timeout = 10000) {
|
|
if (!fs.existsSync(this.qrPath)) {
|
|
return 'none';
|
|
}
|
|
|
|
let lastMtime = fs.statSync(this.qrPath).mtimeMs;
|
|
|
|
return new Promise((resolve) => {
|
|
const timer = setTimeout(() => {
|
|
watcher.close();
|
|
resolve('none');
|
|
}, timeout);
|
|
|
|
const watcher = fs.watch(this.qrPath, (eventType) => {
|
|
if (eventType === 'change') {
|
|
const stat = fs.statSync(this.qrPath);
|
|
if (stat.mtimeMs !== lastMtime) {
|
|
lastMtime = stat.mtimeMs;
|
|
clearTimeout(timer);
|
|
watcher.close();
|
|
resolve(this.qrPath);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 断开nc连接
|
|
* @param nickname 昵称
|
|
* @returns {Promise<string>}
|
|
*/
|
|
async disconnect(nickname) {
|
|
try {
|
|
await execAsync(`tmux kill-session -t ${nickname}`);
|
|
return `已关闭会话: ${nickname}`;
|
|
} catch (err) {
|
|
return `关闭会话失败: ${err.message}`;
|
|
}
|
|
}
|
|
}
|