mirror of
https://github.com/crystelf/crystelf-admin.git
synced 2025-12-05 13:41:57 +00:00
feat:部分onebot11登录实现
This commit is contained in:
parent
5add485556
commit
edad447c6e
11
apps/login.js
Normal file
11
apps/login.js
Normal file
@ -0,0 +1,11 @@
|
||||
export default class LoginService extends plugin {
|
||||
constructor() {
|
||||
super({
|
||||
name: 'Onebot登录相关服务',
|
||||
dsc: '方便操作',
|
||||
rule: [],
|
||||
});
|
||||
}
|
||||
|
||||
async test(e) {}
|
||||
}
|
||||
@ -7,5 +7,12 @@
|
||||
"wsSecret": "",
|
||||
"wsReConnectInterval": "5000",
|
||||
"token": ""
|
||||
},
|
||||
"napcat": {
|
||||
"basePath": "",
|
||||
"userPath": ""
|
||||
},
|
||||
"lgr": {
|
||||
"basePath": ""
|
||||
}
|
||||
}
|
||||
|
||||
26
config/napcat.json
Normal file
26
config/napcat.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"network": {
|
||||
"httpServers": [],
|
||||
"httpSseServers": [],
|
||||
"httpClients": [],
|
||||
"websocketServers": [
|
||||
],
|
||||
"websocketClients": [
|
||||
{
|
||||
"enable": true,
|
||||
"name": "trss",
|
||||
"url": "ws://localhost:2536/OneBotv11",
|
||||
"reportSelfMessage": false,
|
||||
"messagePostFormat": "array",
|
||||
"token": "",
|
||||
"debug": false,
|
||||
"heartInterval": 30000,
|
||||
"reconnectInterval": 10000
|
||||
}
|
||||
],
|
||||
"plugins": []
|
||||
},
|
||||
"musicSignUrl": "",
|
||||
"enableLocalFile2Url": false,
|
||||
"parseMultMsg": false
|
||||
}
|
||||
101
lib/login/lgr.js
Normal file
101
lib/login/lgr.js
Normal file
@ -0,0 +1,101 @@
|
||||
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 LgrService {
|
||||
constructor() {
|
||||
const config = configControl.get('config')?.lgr || {};
|
||||
this.basePath = config.basePath;
|
||||
if (!this.basePath) {
|
||||
logger.error('[crystelf-admin] 未检测到lgr配置..');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lgr登录方法
|
||||
* @param qq qq号
|
||||
* @param nickname 昵称
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
async login(qq, nickname) {
|
||||
if (!this.basePath) {
|
||||
logger.error('[crystelf-admin] 未配置 lgr.basePath');
|
||||
}
|
||||
const parentDir = path.dirname(this.basePath);
|
||||
const targetDir = path.join(parentDir, String(qq));
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
try {
|
||||
await execAsync(`cp -r "${this.basePath}" "${targetDir}"`);
|
||||
logger.info(`[crystelf-admin] 已复制 ${this.basePath} 到 ${targetDir}..`);
|
||||
} catch (err) {
|
||||
logger.error(`[crystelf-admin] 复制文件夹失败: ${err.message}..`);
|
||||
}
|
||||
}
|
||||
const exeFile = path.join(targetDir, 'lgr');
|
||||
try {
|
||||
await execAsync(`chmod 777 "${exeFile}"`);
|
||||
} catch (err) {
|
||||
logger.error(`[crystelf-admin] chmod 失败: ${err.message}..`);
|
||||
}
|
||||
try {
|
||||
await execAsync(`tmux has-session -t ${nickname}`);
|
||||
await execAsync(`tmux kill-session -t ${nickname}`);
|
||||
await execAsync(`tmux new -s ${nickname} -d "cd '${targetDir}' && ./lgr"`);
|
||||
} catch {
|
||||
await execAsync(`tmux new -s ${nickname} -d "cd '${targetDir}' && ./lgr"`);
|
||||
}
|
||||
|
||||
return await this.waitForQrUpdate(targetDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待qr图片更新
|
||||
* @param targetDir 目标文件夹
|
||||
* @param timeout
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
async waitForQrUpdate(targetDir, timeout = 10000) {
|
||||
const qrPath = path.join(targetDir, 'qr-0.png');
|
||||
if (!fs.existsSync(qrPath)) {
|
||||
return 'none';
|
||||
}
|
||||
|
||||
let lastMtime = fs.statSync(qrPath).mtimeMs;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(() => {
|
||||
watcher.close();
|
||||
resolve('none');
|
||||
}, timeout);
|
||||
|
||||
const watcher = fs.watch(qrPath, (eventType) => {
|
||||
if (eventType === 'change') {
|
||||
const stat = fs.statSync(qrPath);
|
||||
if (stat.mtimeMs !== lastMtime) {
|
||||
lastMtime = stat.mtimeMs;
|
||||
clearTimeout(timer);
|
||||
watcher.close();
|
||||
resolve(qrPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开lgr连接
|
||||
* @param {string} nickname
|
||||
*/
|
||||
async disconnect(nickname) {
|
||||
try {
|
||||
await execAsync(`tmux kill-session -t ${nickname}`);
|
||||
return `已关闭会话: ${nickname}`;
|
||||
} catch (err) {
|
||||
return `关闭会话失败: ${err.message}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
lib/login/napcat.js
Normal file
107
lib/login/napcat.js
Normal file
@ -0,0 +1,107 @@
|
||||
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}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user