refactor: nc shell login

This commit is contained in:
手瓜一十雪 2024-11-14 13:40:01 +08:00
parent 6a08b15095
commit 96003724ab

View File

@ -34,54 +34,46 @@ program.option('-q, --qq [number]', 'QQ号').parse(process.argv);
const cmdOptions = program.opts(); const cmdOptions = program.opts();
// NapCat Shell App ES 入口文件 // NapCat Shell App ES 入口文件
export async function NCoreInitShell() { async function handleUncaughtExceptions(logger: LogWrapper) {
console.log('NapCat Shell App Loading...');
process.on('uncaughtException', (err) => { process.on('uncaughtException', (err) => {
console.log('[NapCat] [Error] Unhandled Exception:', err.message); logger.logError('[NapCat] [Error] Unhandled Exception:', err.message);
}); });
process.on('unhandledRejection', (reason, promise) => { process.on('unhandledRejection', (reason, promise) => {
console.log('[NapCat] [Error] unhandledRejection:', reason); logger.logError('[NapCat] [Error] unhandledRejection:', reason);
}); });
const pathWrapper = new NapCatPathWrapper(); }
const logger = new LogWrapper(pathWrapper.logsPath);
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
const o3Service = wrapper.NodeIO3MiscService.get(); function getDataPaths(wrapper: WrapperNodeApi): [string, string] {
o3Service.addO3MiscListener(new NodeIO3MiscListener()); if (os.platform() === 'darwin') {
const userPath = os.homedir();
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
return [appDataPath, path.join(appDataPath, 'global')];
}
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
if (!dataPath) {
dataPath = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(dataPath, { recursive: true });
}
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
return [dataPath, dataPathGlobal];
}
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion); function getPlatformType(): PlatformType {
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
// from constructor
const engine = wrapper.NodeIQQNTWrapperEngine.get();
//const util = wrapper.NodeQQNTWrapperUtil.get();
const loginService = wrapper.NodeIKernelLoginService.get();
const session = wrapper.NodeIQQNTWrapperSession.create();
// from get dataPath
const [dataPath, dataPathGlobal] = (() => {
if (os.platform() === 'darwin') {
const userPath = os.homedir();
const appDataPath = path.resolve(userPath, './Library/Application Support/QQ');
return [appDataPath, path.join(appDataPath, 'global')];
}
let dataPath = wrapper.NodeQQNTWrapperUtil.getNTUserDataInfoConfig();
if (!dataPath) {
dataPath = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(dataPath, { recursive: true });
}
const dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
return [dataPath, dataPathGlobal];
})();
const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = { const platformMapping: Partial<Record<NodeJS.Platform, PlatformType>> = {
win32: PlatformType.KWINDOWS, win32: PlatformType.KWINDOWS,
darwin: PlatformType.KMAC, darwin: PlatformType.KMAC,
linux: PlatformType.KLINUX, linux: PlatformType.KLINUX,
}; };
const systemPlatform = platformMapping[os.platform()] ?? PlatformType.KWINDOWS; return platformMapping[os.platform()] ?? PlatformType.KWINDOWS;
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined'); }
// from initConfig
async function initializeEngine(
engine: any,
basicInfoWrapper: QQBasicInfoWrapper,
dataPathGlobal: string,
systemPlatform: PlatformType,
systemVersion: string
) {
engine.initWithDeskTopConfig( engine.initWithDeskTopConfig(
{ {
base_path_prefix: '', base_path_prefix: '',
@ -98,33 +90,41 @@ export async function NCoreInitShell() {
}, },
new NodeIGlobalAdapter(), new NodeIGlobalAdapter(),
); );
}
async function initializeLoginService(
loginService: NodeIKernelLoginService,
basicInfoWrapper: QQBasicInfoWrapper,
dataPathGlobal: string,
systemVersion: string,
hostname: string
) {
loginService.initConfig({ loginService.initConfig({
machineId: '', machineId: '',
appid: basicInfoWrapper.QQVersionAppid, appid: basicInfoWrapper.QQVersionAppid ?? '',
platVer: systemVersion, platVer: systemVersion,
commonPath: dataPathGlobal, commonPath: dataPathGlobal,
clientVer: basicInfoWrapper.getFullQQVesion(), clientVer: basicInfoWrapper.getFullQQVesion(),
hostName: hostname, hostName: hostname,
}); });
}
let quickLoginUin = cmdOptions.qq; // undefined | 'true' | string async function handleLogin(
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList; loginService: NodeIKernelLoginService,
if (quickLoginUin == 'true') { logger: LogWrapper,
if (historyLoginList.length > 0) { pathWrapper: NapCatPathWrapper,
quickLoginUin = historyLoginList[0].uin; quickLoginUin: string | undefined,
logger.log(`-q 指令指定使用最近的 QQ ${quickLoginUin} 进行快速登录`); historyLoginList: any[],
} else { basicInfoWrapper: QQBasicInfoWrapper,
quickLoginUin = ''; o3Service: any,
} dataTimestape: string
} ): Promise<SelfInfo> {
const dataTimestape = new Date().getTime().toString(); return new Promise<SelfInfo>((resolve) => {
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
const selfInfo = await new Promise<SelfInfo>((resolve) => {
const loginListener = new NodeIKernelLoginListener(); const loginListener = new NodeIKernelLoginListener();
let isLogined = false; let isLogined = false;
// from constructor
loginListener.onUserLoggedIn = (userid: string) => { loginListener.onUserLoggedIn = (userid: string) => {
logger.logError.bind(logger)(`当前账号(${userid})已登录,无法重复登录`); logger.logError(`当前账号(${userid})已登录,无法重复登录`);
}; };
loginListener.onQRCodeLoginSucceed = async (loginResult) => { loginListener.onQRCodeLoginSucceed = async (loginResult) => {
@ -132,13 +132,12 @@ export async function NCoreInitShell() {
resolve({ resolve({
uid: loginResult.uid, uid: loginResult.uid,
uin: loginResult.uin, uin: loginResult.uin,
nick: '', // 获取不到 nick: '',
online: true, online: true,
}); });
}; };
loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => { loginListener.onQRCodeGetPicture = ({ pngBase64QrcodeData, qrcodeUrl }) => {
//设置WebuiQrcode
WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl); WebUiDataRuntime.setQQLoginQrcodeURL(qrcodeUrl);
const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, ''); const realBase64 = pngBase64QrcodeData.replace(/^data:image\/\w+;base64,/, '');
@ -157,50 +156,46 @@ export async function NCoreInitShell() {
}); });
}); });
}; };
loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => { loginListener.onQRCodeSessionFailed = (errType: number, errCode: number, errMsg: string) => {
if (!isLogined) { if (!isLogined) {
logger.logError.bind(logger)('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg); logger.logError('[Core] [Login] Login Error,ErrCode: ', errCode, ' ErrMsg:', errMsg);
if (errType == 1 && errCode == 3) { if (errType == 1 && errCode == 3) {
// 二维码过期刷新 // 二维码过期刷新
} }
loginService.getQRCodePicture(); loginService.getQRCodePicture();
} }
}; };
loginListener.onLoginFailed = (args) => { loginListener.onLoginFailed = (args) => {
logger.logError.bind(logger)('[Core] [Login] Login Error , ErrInfo: ', args); logger.logError('[Core] [Login] Login Error , ErrInfo: ', args);
}; };
loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger)); loginService.addKernelLoginListener(proxiedListenerOf(loginListener, logger));
const isConnect = loginService.connect(); const isConnect = loginService.connect();
if (!isConnect) { if (!isConnect) {
logger.logError.bind(logger)('核心登录服务连接失败!'); logger.logError('核心登录服务连接失败!');
return; return;
} }
logger.log('核心登录服务连接成功!'); logger.log('核心登录服务连接成功!');
// 实现WebUi快速登录
loginService.getLoginList().then((res) => { loginService.getLoginList().then((res) => {
// 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList // 遍历 res.LocalLoginInfoList[x].isQuickLogin是否可以 res.LocalLoginInfoList[x].uin 转为string 加入string[] 最后遍历完成调用WebUiDataRuntime.setQQQuickLoginList
WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString())); WebUiDataRuntime.setQQQuickLoginList(res.LocalLoginInfoList.filter((item) => item.isQuickLogin).map((item) => item.uin.toString()));
}); });
if (basicInfoWrapper.QQVersionConfig?.curVersion) {
loginService.getLoginMiscData('hotUpdateSign').then((res) => {
if (res.result === 0) {
loginService.setLoginMiscData('hotUpdateSign', res.value);
}
});
session.getNodeMiscService().writeVersionToRegistry(basicInfoWrapper.QQVersionConfig?.curVersion);
}
WebUiDataRuntime.setQuickLoginCall(async (uin: string) => { WebUiDataRuntime.setQuickLoginCall(async (uin: string) => {
return await new Promise((resolve) => { return await new Promise((resolve) => {
if (uin) { if (uin) {
logger.log.bind(logger)('正在快速登录 ', uin); logger.log('正在快速登录 ', uin);
loginService.quickLoginWithUin(uin).then(res => { loginService.quickLoginWithUin(uin).then(res => {
if (res.loginErrorInfo.errMsg) { if (res.loginErrorInfo.errMsg) {
resolve({ result: false, message: res.loginErrorInfo.errMsg }); resolve({ result: false, message: res.loginErrorInfo.errMsg });
} }
resolve({ result: true, message: '' }); resolve({ result: true, message: '' });
}).catch((e) => { }).catch((e) => {
logger.logError.bind(logger)(e); logger.logError(e);
resolve({ result: false, message: '快速登录发生错误' }); resolve({ result: false, message: '快速登录发生错误' });
}); });
} else { } else {
@ -216,14 +211,14 @@ export async function NCoreInitShell() {
loginService.quickLoginWithUin(quickLoginUin) loginService.quickLoginWithUin(quickLoginUin)
.then(result => { .then(result => {
if (result.loginErrorInfo.errMsg) { if (result.loginErrorInfo.errMsg) {
logger.logError.bind(logger)('快速登录错误:', result.loginErrorInfo.errMsg); logger.logError('快速登录错误:', result.loginErrorInfo.errMsg);
if (!isLogined) loginService.getQRCodePicture(); if (!isLogined) loginService.getQRCodePicture();
} }
}) })
.catch(); .catch();
}, 1000); }, 1000);
} else { } else {
logger.logError.bind(logger)('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式'); logger.logError('快速登录失败,未找到该 QQ 历史登录记录,将使用二维码登录方式');
if (!isLogined) loginService.getQRCodePicture(); if (!isLogined) loginService.getQRCodePicture();
} }
} else { } else {
@ -237,31 +232,14 @@ export async function NCoreInitShell() {
loginService.getQRCodePicture(); loginService.getQRCodePicture();
} }
}); });
// BEFORE LOGGING IN }
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
// AFTER LOGGING IN
//99b15bdb4c984fc69d5aa1feb9aa16xx --> 99b15bdb-4c98-4fc6-9d5a-a1feb9aa16xx
//把guid从左向右转换为guid格式 loginService.getMachineGuid()
let guid = loginService.getMachineGuid(); async function initializeSession(
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20); session: NodeIQQNTWrapperSession,
//console.log('guid:', guid); sessionConfig: any,
//NodeIO3MiscService/reportAmgomWeather login a6 [ '1726748166943', '184', '329' ] logger: LogWrapper
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']); ) {
// if(session.getUnitedConfigService()){ return new Promise<void>((resolve, reject) => {
// session.getUnitedConfigService().fetchUnitedCommendConfig([]);
// }
// from initSession
const sessionConfig = await genSessionConfig(
guid,
basicInfoWrapper.QQVersionAppid,
basicInfoWrapper.getFullQQVesion(),
selfInfo.uin,
selfInfo.uid,
dataPath,
);
await new Promise<void>((resolve, reject) => {
const sessionListener = new NodeIKernelSessionListener(); const sessionListener = new NodeIKernelSessionListener();
sessionListener.onSessionInitComplete = (r: unknown) => { sessionListener.onSessionInitComplete = (r: unknown) => {
if (r === 0) { if (r === 0) {
@ -278,7 +256,7 @@ export async function NCoreInitShell() {
); );
try { try {
session.startNT(0); session.startNT(0);
} catch (_) { /* Empty */ } catch (_) {
try { try {
session.startNT(); session.startNT();
} catch (e: unknown) { } catch (e: unknown) {
@ -286,7 +264,60 @@ export async function NCoreInitShell() {
} }
} }
}); });
// Initialization end! }
export async function NCoreInitShell() {
console.log('NapCat Shell App Loading...');
const pathWrapper = new NapCatPathWrapper();
const logger = new LogWrapper(pathWrapper.logsPath);
handleUncaughtExceptions(logger);
const basicInfoWrapper = new QQBasicInfoWrapper({ logger });
const wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
const o3Service = wrapper.NodeIO3MiscService.get();
o3Service.addO3MiscListener(new NodeIO3MiscListener());
logger.log(`[NapCat] [Core] NapCat.Core Version: ` + napCatVersion);
InitWebUi(logger, pathWrapper).then().catch(logger.logError.bind(logger));
const engine = wrapper.NodeIQQNTWrapperEngine.get();
const loginService = wrapper.NodeIKernelLoginService.get();
const session = wrapper.NodeIQQNTWrapperSession.create();
const [dataPath, dataPathGlobal] = getDataPaths(wrapper);
const systemPlatform = getPlatformType();
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
await initializeEngine(engine, basicInfoWrapper, dataPathGlobal, systemPlatform, systemVersion);
await initializeLoginService(loginService, basicInfoWrapper, dataPathGlobal, systemVersion, hostname);
let quickLoginUin = cmdOptions.qq;
const historyLoginList = (await loginService.getLoginList()).LocalLoginInfoList;
const dataTimestape = new Date().getTime().toString();
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
const selfInfo = await handleLogin(loginService, logger, pathWrapper, quickLoginUin, historyLoginList, basicInfoWrapper, o3Service, dataTimestape);
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
let guid = loginService.getMachineGuid();
guid = guid.slice(0, 8) + '-' + guid.slice(8, 12) + '-' + guid.slice(12, 16) + '-' + guid.slice(16, 20) + '-' + guid.slice(20);
o3Service.reportAmgomWeather('login', 'a6', [dataTimestape, '184', '329']);
const sessionConfig = await genSessionConfig(
guid,
basicInfoWrapper.QQVersionAppid,
basicInfoWrapper.getFullQQVesion(),
selfInfo.uin,
selfInfo.uid,
dataPath,
);
await initializeSession(session, sessionConfig, logger);
const accountDataPath = path.resolve(dataPath, './NapCat/data'); const accountDataPath = path.resolve(dataPath, './NapCat/data');
fs.mkdirSync(dataPath, { recursive: true }); fs.mkdirSync(dataPath, { recursive: true });
@ -303,6 +334,7 @@ export async function NCoreInitShell() {
).InitNapCat(); ).InitNapCat();
} }
export class NapCatShell { export class NapCatShell {
readonly core: NapCatCore; readonly core: NapCatCore;
readonly context: InstanceContext; readonly context: InstanceContext;