chore: build

Co-Authored-By: Wesley F. Young <25684570+Wesley-Young@users.noreply.github.com>
This commit is contained in:
手瓜一十雪 2024-08-08 20:42:09 +08:00
parent 54b06872eb
commit f588d3f35b
9 changed files with 211 additions and 144 deletions

View File

@ -4,8 +4,8 @@
"type": "module", "type": "module",
"version": "1.8.3", "version": "1.8.3",
"scripts": { "scripts": {
"build:liteloader": "vite build --mode ", "build:liteloader": "vite build --mode liteloader",
"build:shell": "vite build --mode production", "build:shell": "vite build --mode shell",
"build:webui": "cd ./src/webui && vite build", "build:webui": "cd ./src/webui && vite build",
"lint": "eslint --fix src/**/*.{js,ts}", "lint": "eslint --fix src/**/*.{js,ts}",
"depend": "cd dist && npm install --omit=dev" "depend": "cd dist && npm install --omit=dev"

5
src/index.ts Normal file
View File

@ -0,0 +1,5 @@
//LiteLoader/Shell ES统一出包口
if(!(window as any).LiteLoader) {
//LiteLoader 模式
}
//Shell模式

View File

@ -9,7 +9,7 @@ import { SelfInfo } from "@/core/entities";
import { LoginListener } from "@/core/listeners"; import { LoginListener } from "@/core/listeners";
import { NodeIKernelLoginService } from "@/core/services"; import { NodeIKernelLoginService } from "@/core/services";
import { WrapperNodeApi, NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper"; import { WrapperNodeApi, NodeIQQNTWrapperSession } from "@/core/wrapper/wrapper";
import { NapCatOneBot11Adapter } from "@/onebot"; import { NapCatOneBot11Adapter } from "@/onebot/main";
//LiteLoader ES入口文件 //LiteLoader ES入口文件
export async function NCoreInitLiteLoader(session: NodeIQQNTWrapperSession, loginService: NodeIKernelLoginService) { export async function NCoreInitLiteLoader(session: NodeIQQNTWrapperSession, loginService: NodeIKernelLoginService) {

View File

@ -1,12 +1,2 @@
import { InstanceContext, NapCatCore } from "@/core"; export * from './main';
export * from './types';
//OneBot实现类
export class NapCatOneBot11Adapter{
readonly core: NapCatCore;
readonly context: InstanceContext;
constructor(core: NapCatCore, context: InstanceContext) {
this.core = core;
this.context = context;
}
}

14
src/onebot/main.ts Normal file
View File

@ -0,0 +1,14 @@
import { NapCatCore, InstanceContext } from "@/core";
//OneBot实现类
export class NapCatOneBot11Adapter {
readonly core: NapCatCore;
readonly context: InstanceContext;
constructor(core: NapCatCore, context: InstanceContext) {
this.core = core;
this.context = context;
}
}

View File

@ -0,0 +1,65 @@
export interface OB11User {
user_id: number;
nickname: string;
remark?: string;
sex?: OB11UserSex;
level?: number;
age?: number;
qid?: string;
login_days?: number;
categroyName?:string;
categoryId?:number;
}
export enum OB11UserSex {
male = 'male',
female = 'female',
unknown = 'unknown'
}
export enum OB11GroupMemberRole {
owner = 'owner',
admin = 'admin',
member = 'member',
}
export interface OB11GroupMember {
group_id: number
user_id: number
nickname: string
card?: string
sex?: OB11UserSex
age?: number
join_time?: number
last_sent_time?: number
level?: string
qq_level?: number
role?: OB11GroupMemberRole
title?: string
area?: string
unfriendly?: boolean
title_expire_time?: number
card_changeable?: boolean
// 以下为gocq字段
shut_up_timestamp?: number
// 以下为扩展字段
is_robot?: boolean
qage?: number
}
export interface OB11Group {
group_id: number
group_name: string
member_count?: number
max_member_count?: number
}
export interface OB11Sender {
user_id: number,
nickname: string,
sex?: OB11UserSex,
age?: number,
card?: string, // 群名片
level?: string, // 群等级
role?: OB11GroupMemberRole
}

View File

@ -0,0 +1 @@
export * from './entity';

View File

@ -28,119 +28,95 @@ export async function NCoreInitShell() {
let basicInfoWrapper = new QQBasicInfoWrapper({ logger }); let basicInfoWrapper = new QQBasicInfoWrapper({ logger });
let wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion()); let wrapper = loadQQWrapper(basicInfoWrapper.getFullQQVesion());
// from constructor
let engine = new wrapper.NodeIQQNTWrapperEngine();
let util = new wrapper.NodeQQNTWrapperUtil();
let loginService = new wrapper.NodeIKernelLoginService();
let session = new wrapper.NodeIQQNTWrapperSession();
// from get dataPath
let dataPath = util.getNTUserDataInfoConfig();
if (!dataPath) {
dataPath = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(dataPath, { recursive: true });
}
let dataPathGlobal = path.resolve(dataPath, './nt_qq/global');
// from initConfig
engine.initWithDeskTopConfig(
{
base_path_prefix: '',
platform_type: 3,
app_type: 4,
app_version: basicInfoWrapper.getFullQQVesion(),
os_version: 'Windows 10 Pro',
use_xlog: true,
qua: basicInfoWrapper.QQVersionQua!,
global_path_config: {
desktopGlobalPath: dataPathGlobal,
},
thumb_config: { maxSide: 324, minSide: 48, longLimit: 6, density: 2 }
},
new wrapper.NodeIGlobalAdapter(new GlobalAdapter())
);
loginService.initConfig({
machineId: '',
appid: basicInfoWrapper.QQVersionAppid!,
platVer: systemVersion,
commonPath: dataPathGlobal,
clientVer: basicInfoWrapper.getFullQQVesion(),
hostName: hostname
});
let selfInfo = await new Promise<SelfInfo>((resolve) => { let selfInfo = await new Promise<SelfInfo>((resolve) => {
let loginListener = new LoginListener(); let loginListener = new LoginListener();
// from constructor
loginListener.onUserLoggedIn = (userid: string) => {
logger.logError('当前账号(' + userid + ')已登录,无法重复登录');
};
loginListener.onQRCodeLoginSucceed = async (loginResult) => resolve({ loginListener.onQRCodeLoginSucceed = async (loginResult) => resolve({
uid: loginResult.uid, uid: loginResult.uid,
uin: loginResult.uin, uin: loginResult.uin,
nick: '', // 获取不到 nick: '', // 获取不到
online: true online: true
}); });
loginService.addKernelLoginListener(); loginService.addKernelLoginListener(new wrapper.NodeIKernelLoginListener(
let ShellNapCat = new NapCatShell(logger, BasicInfo);
ShellNapCat.loginService.addKernelLoginListener(new wrapper.NodeIKernelLoginListener(
proxiedListenerOf(loginListener, logger))); proxiedListenerOf(loginListener, logger)));
}) });
// from initSession
const sessionConfig = await genSessionConfig(
basicInfoWrapper.QQVersionAppid!,
basicInfoWrapper.getFullQQVesion(),
selfInfo.uin,
selfInfo.uid,
dataPath
);
const sessionListener = new SessionListener();
sessionListener.onSessionInitComplete = (r: unknown) => {
if (r !== 0) {
throw r;
}
};
session.init(
sessionConfig,
new wrapper.NodeIDependsAdapter(new DependsAdapter()),
new wrapper.NodeIDispatcherAdapter(new DispatcherAdapter()),
new wrapper.NodeIKernelSessionListener(sessionListener)
);
try {
session.startNT(0);
} catch (__) {
session.startNT(); // may still throw error; we do not catch that
}
// Initialization end!
const accountDataPath = path.resolve(dataPath, './NapCat/data');
fs.mkdirSync(dataPath, { recursive: true });
logger.logDebug('本账号数据/缓存目录:', accountDataPath);
} }
export class NapCatShell { export class NapCatShell {
public QQWrapper: WrapperNodeApi;
public WorkMode: NapCatCoreWorkingEnv = NapCatCoreWorkingEnv.Shell;
public Core: NapCatCore | undefined;
public engine: NodeIQQNTWrapperEngine;
public util: NodeQQNTWrapperUtil;
loginService: NodeIKernelLoginService;
session: NodeIQQNTWrapperSession;
loginListener: LoginListener;
get dataPath(): string {
let result = this.util.getNTUserDataInfoConfig();
if (!result) {
result = path.resolve(os.homedir(), './.config/QQ');
fs.mkdirSync(result, { recursive: true });
}
return result;
}
get dataPathGlobal(): string {
return path.resolve(this.dataPath, './nt_qq/global');
}
private initSession(BasicInfo: QQBasicInfoWrapper, uin: string, uid: string): Promise<number> {
return new Promise(async (res, rej) => {
if (!BasicInfo.QQVersionAppid) throw new Error("QQVersionAppid must be provided");
const sessionConfig = await genSessionConfig(BasicInfo.QQVersionAppid, BasicInfo.getFullQQVesion(), uin, uid, this.dataPath);
const sessionListener = new SessionListener();
sessionListener.onSessionInitComplete = (r: unknown) => {
if ((r as number) === 0) {
return res(0);
}
rej(r);
};
this.session.init(sessionConfig,
new this.QQWrapper.NodeIDependsAdapter(new DependsAdapter()),
new this.QQWrapper.NodeIDispatcherAdapter(new DispatcherAdapter()),
new this.QQWrapper.NodeIKernelSessionListener(sessionListener)
);
try {
this.session.startNT(0);
} catch (__) { /* Empty */
try {
this.session.startNT();
} catch (e) {
rej('init failed ' + e);
}
}
});
}
constructor(logger: LogWrapper, QQBasic: QQBasicInfoWrapper) {
this.QQWrapper = loadQQWrapper(QQBasic.getFullQQVesion());
this.engine = new this.QQWrapper.NodeIQQNTWrapperEngine();
this.util = new this.QQWrapper.NodeQQNTWrapperUtil();
this.loginService = new this.QQWrapper.NodeIKernelLoginService();
this.session = new this.QQWrapper.NodeIQQNTWrapperSession();
this.loginListener = new LoginListener();
this.loginListener.onUserLoggedIn = (userid: string) => {
logger.logError('当前账号(' + userid + ')已登录,无法重复登录');
};
this.initConfig(QQBasic.getFullQQVesion(), QQBasic.QQVersionAppid, QQBasic.QQVersionQua);
this.loginListener.onQRCodeLoginSucceed = (arg) => {
this.initSession(QQBasic, arg.uin, arg.uid).then((r) => {
selfInfo.uin = arg.uin;
selfInfo.uid = arg.uid;
const dataPath = path.resolve(this.dataPath, './NapCat/data');
fs.mkdirSync(dataPath, { recursive: true });
logger.logDebug('本账号数据/缓存目录:', dataPath);
//this.initDataListener();
}).catch((e) => {
logger.logError('initSession failed', e);
throw new Error(`启动失败: ${JSON.stringify(e)}`);
});
};
}
initConfig(QQVersion: string | undefined, QQVersionAppid: string | undefined, QQVersionQua: string | undefined) {
if (!QQVersion || !QQVersionAppid || !QQVersionQua) throw new Error('QQVersion, QQVersionAppid, QQVersionQua must be provided');
this.engine.initWithDeskTopConfig({
base_path_prefix: '',
platform_type: 3,
app_type: 4,
app_version: QQVersion,
os_version: 'Windows 10 Pro',
use_xlog: true,
qua: QQVersionQua,
global_path_config: {
desktopGlobalPath: this.dataPathGlobal,
},
thumb_config: { maxSide: 324, minSide: 48, longLimit: 6, density: 2 }
}, new this.QQWrapper.NodeIGlobalAdapter(new GlobalAdapter()));
this.loginService.initConfig({
machineId: '',
appid: QQVersionAppid,
platVer: systemVersion,
commonPath: this.dataPathGlobal,
clientVer: QQVersion,
hostName: hostname
});
}
} }

View File

@ -8,14 +8,14 @@ import nodeResolve from '@rollup/plugin-node-resolve';
import { builtinModules } from 'module'; import { builtinModules } from 'module';
import fs from 'node:fs'; import fs from 'node:fs';
import babel from 'vite-plugin-babel'; import babel from 'vite-plugin-babel';
//依赖排除
const external = ['silk-wasm', 'ws', 'express', 'fluent-ffmpeg', 'log4js', 'qrcode-terminal']; const external = ['silk-wasm', 'ws', 'express', 'fluent-ffmpeg', 'log4js', 'qrcode-terminal'];
const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].flat(); const nodeModules = [...builtinModules, builtinModules.map(m => `node:${m}`)].flat();
// let nodeModules = ["fs", "path", "events", "buffer", "url", "crypto", "fs/promise", "fsPromise", "os", "http", "net"]
// nodeModules = [...nodeModules, ...nodeModules.map(m => `node:${m}`)]
function genCpModule(module: string) { function genCpModule(module: string) {
return { src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false }; return { src: `./node_modules/${module}`, dest: `dist/node_modules/${module}`, flatten: false };
} }
let startScripts: string[] | undefined = undefined; let startScripts: string[] | undefined = undefined;
if (process.env.NAPCAT_BUILDSYS == 'linux') { if (process.env.NAPCAT_BUILDSYS == 'linux') {
if (process.env.NAPCAT_BUILDARCH == 'x64') { if (process.env.NAPCAT_BUILDARCH == 'x64') {
@ -47,47 +47,63 @@ const baseConfigPlugin: PluginOption[] = [
cp({ cp({
targets: [ targets: [
// ...external.map(genCpModule), // ...external.map(genCpModule),
{ src: './src/napcat.json', dest: 'dist/config/' }, // { src: './src/napcat.json', dest: 'dist/config/' },
{ src: './static/', dest: 'dist/static/', flatten: false }, // { src: './static/', dest: 'dist/static/', flatten: false },
{ src: './src/onebot11/onebot11.json', dest: 'dist/config/' }, // { src: './src/onebot11/onebot11.json', dest: 'dist/config/' },
{ src: './package.json', dest: 'dist' }, // { src: './package.json', dest: 'dist' },
{ src: './README.md', dest: 'dist' }, // { src: './README.md', dest: 'dist' },
{ src: './logo.png', dest: 'dist/logs' }, // { src: './logo.png', dest: 'dist/logs' },
...(startScripts.map((startScript) => { // ...(startScripts.map((startScript) => {
return { src: startScript, dest: 'dist' }; // return { src: startScript, dest: 'dist' };
})), // })),
] ]
}), }),
nodeResolve(), nodeResolve(),
]; ];
const ShellBaseConfig = () => defineConfig({
let corePath = resolve(__dirname, './src/core/src');
if (!fs.existsSync(corePath)) {
corePath = resolve(__dirname, './src/core.lib/src');
}
const baseConfig = (mode: string = 'shell') => defineConfig({
resolve: { resolve: {
conditions: ['node', 'default'], conditions: ['node', 'default'],
alias: { alias: {
'@/core': corePath, '@/core': resolve(__dirname, './src/core/src'),
'@': resolve(__dirname, './src'), '@': resolve(__dirname, './src'),
'./lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg', './lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg',
}, },
}, },
build: { build: {
sourcemap: mode === 'development', sourcemap: false,
target: 'esnext', target: 'esnext',
// minify: mode === 'production' ? 'esbuild' : false,
// 压缩代码出现了未知问题导致无法运行,暂时不启用
minify: false, minify: false,
lib: { lib: {
entry: mode === "shell" ? 'src/shell/napcat.ts' : "src/liteloader/napcat.ts", entry: 'src/shell/napcat.ts',
formats: ['es'],
fileName: () => 'napcat.mjs',
},
rollupOptions: {
external: [...nodeModules, ...external]
},
},
});
const LLBaseConfig = () => defineConfig({
resolve: {
conditions: ['node', 'default'],
alias: {
'@/core': resolve(__dirname, './src/core/src'),
'@': resolve(__dirname, './src'),
'./lib-cov/fluent-ffmpeg': './lib/fluent-ffmpeg',
},
},
build: {
sourcemap: false,
target: 'esnext',
minify: false,
lib: {
entry: "src/liteloader/napcat.ts",
formats: ['es'], formats: ['es'],
fileName: () => 'napcat.mjs', fileName: () => 'napcat.mjs',
}, },
rollupOptions: { rollupOptions: {
// external: [ /node:*/ ],
external: [...nodeModules, ...external] external: [...nodeModules, ...external]
}, },
}, },
@ -96,14 +112,14 @@ const baseConfig = (mode: string = 'shell') => defineConfig({
export default defineConfig(({ mode }): UserConfig => { export default defineConfig(({ mode }): UserConfig => {
if (mode === 'shell') { if (mode === 'shell') {
return { return {
...baseConfig(mode), ...ShellBaseConfig(),
plugins: [ plugins: [
...baseConfigPlugin ...baseConfigPlugin
] ]
}; };
} else { } else {
return { return {
...baseConfig(mode), ...LLBaseConfig(),
plugins: baseConfigPlugin, plugins: baseConfigPlugin,
}; };
} }