Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重制app类 #1

Merged
merged 1 commit into from
Sep 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ bot_sysadmin_id:
bot_name: "琳酱"

# TG风格: "/" QQ风格: "."
command_style: "/"
command_style: "/"

# 轮询超时消息不处理时间(秒)
outdate_seconds: 300
116 changes: 10 additions & 106 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,120 +1,24 @@
// 读取配置和模块
import fs from 'fs';
// import Promise from 'promise';
import yaml from 'js-yaml';
// import readline from 'readline'
import std from './lib/std.js';
import fatalError from './lib/fatal_error.js';
import db from './lib/db.js';
import {
botOnOff,
commandParser,
getCommands,
getGlobalMessageHandles,
getReplyHandles,
registCommand,
registGlobalMessageHandle,
registReplyHandle
} from './lib/command.js';
import { App } from './types/app.js';
import { YamlConfig } from './types/config.js';
import { exit } from 'process';
import TelegramBot, { BotCommand } from 'node-telegram-bot-api';
import { CreateBot } from './types/bridge.js';
import { reverseReadFileIfExists } from './util/fs.js';
} from '@/lib/command.js';
import { BotCommand } from 'node-telegram-bot-api';
import { Application } from '@/lib/app.js';

// 创建app
const app: App = {
db,
std,
registCommand,
registGlobalMessageHandle,
registReplyHandle,

_config: undefined,

get config(): YamlConfig {
if (this._config) {
return this._config;
} else {
throw '未找到config';
}
},
get bot(): TelegramBot {
if (this._bot) {
return this._bot;
} else {
throw '无bot被初始化';
}
},


get version() {
return JSON.parse(fs.readFileSync('package.json', { encoding: 'utf-8' })).version;
},
get configExample() {
return fs.readFileSync('config.example.yml', { encoding: 'utf-8' }).toString();
},

async initConfig() {
// 读取配置文件
const configContent = reverseReadFileIfExists('config.yml');
if (!configContent) {
await std.questionSync(
'未找到配置文件。是否使用默认配置文件config.examle.yml覆盖config.yml (yes)',
(answer) => {
if (answer === 'yes') {
try {
app.setConfig(app.configExample);
console.log('写入完成,本程序自动退出。');
} catch (err) {
fatalError(err, '写入配置文件失败。');
process.exit(-1);
}
} else {
console.log('请正确配置config.yml. 本程序将自动退出.');
}
process.exit(0);
});
return;
}
this._config = yaml.load(configContent) as YamlConfig;
},
writeConfig(config_data: string) {
fs.writeFileSync('./config.yml', config_data);
},
};

if (process.argv[2] === '--version') {
console.log(`Linquebot ${app.version}`);
console.log('本程序具有超级琳力');
process.exit(0);
}

// 初始化配置
await app.initConfig();

console.log(app.config);
console.log('---------------');

if (!app.config) { exit(-1); }

// 创建bot
if (app.config.platform.settings[app.config.platform.enabled] === undefined) {
console.log(`未找到${app.config.platform.enabled}的配置,请检查config.yml`);
exit(-1);
}
console.log(`Laauching bot at Platform[${app.config.platform.enabled}]...`);
const createBot = (await import(`./bridges/${app.config.platform.enabled}/index.js`)).createBot as CreateBot;

app._bot = createBot(app.config.platform.settings[app.config.platform.enabled]);

if (!app._bot) {
console.log('bot创建失败,请检查bridge是否正确。');
exit(-1);
}
/** 创建app */
const app = new Application();
/** 初始化app */
await app.init();

app.bot.on('message', (msg) => {
if (Number(new Date)/1000 - msg.date > app.config.outdate_seconds) {
console.log('古老消息被忽略。详见 config.outdate_seconds');
}
console.log(msg);
commandParser(app, msg);
if (botOnOff(app, msg)) {
Expand Down
146 changes: 146 additions & 0 deletions src/lib/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// 读取配置和模块
import fs from 'fs';
// import Promise from 'promise';
import yaml from 'js-yaml';
// import readline from 'readline'
import std from '@/lib/std.js';
import fatalError from '@/lib/fatal_error.js';
import db from '@/lib/db.js';
import {
registCommand,
registGlobalMessageHandle,
registReplyHandle
} from '@/lib/command.js';
import { App } from '@/types/app.js';
import { YamlConfig } from '@/types/config.js';
import process from 'process';
import TelegramBot from 'node-telegram-bot-api';
import { CreateBot } from '@/types/bridge.js';
import { reverseReadFileIfExists } from '@/util/fs.js';
import chalk from 'chalk';

/**
* `@/types/app.ts` 的 App 实现
*/
export class Application implements App {
private _bot?: TelegramBot;
private _config?: YamlConfig;
private _configExample: string;
private _version: string;

constructor() {
const packageJSON = reverseReadFileIfExists('package.json');
if (packageJSON) {
this._version = JSON.parse(packageJSON).version;
} else {
throw 'no version found';
}
try {
this._configExample = reverseReadFileIfExists('config.example.yml') || '';
if (!this._configExample) {
throw 'no config example found';
}
} catch(err) {
this._configExample = '';
console.warn(chalk.yellow('No config.example.yml found. This program will not be able to provide a config example.'));
}
}

async init(): Promise<void> {
console.log('Reading config.yml ...');
await this.initConfig();
console.log(this.config);
console.log('---------------');
console.log('Initializing bot ...');
if (this.config.platform.settings[this.config.platform.enabled] === undefined) {
console.log(`未找到平台${this.config.platform.enabled}的配置,请检查config.yml`);
process.exit(-1);
}
console.log(`Launching bot at Platform[${this.config.platform.enabled}]...`);

const createBot = (await import(`../bridges/${this.config.platform.enabled}/index.js`)).createBot as CreateBot;

try {
this._bot = createBot(this.config.platform.settings[this.config.platform.enabled]);
if (!this._bot) {
throw 'bot is undefined';
}
} catch (err) {
console.log(`-------${chalk.red('[ERROR]')}--------`);
console.log('Launching bot failed. Please check the error information below:');
console.error(err);
process.exit(-1);
}
console.log('---------------');
}

get config(): YamlConfig {
if (this._config) {
return this._config;
} else {
throw '未找到config';
}
}

get bot(): TelegramBot {
if (this._bot) {
return this._bot;
} else {
throw '无bot被初始化';
}
}

get db() {
return db;
}

get std() {
return std;
}

get version(): string {
return this._version;
}
get configExample() {
return this._configExample;
}

private async initConfig() {
// 读取配置文件
const configContent = reverseReadFileIfExists('config.yml');
if (!configContent) {
await std.questionSync(
'未找到配置文件。是否使用默认配置文件config.examle.yml覆盖config.yml (yes)',
(answer) => {
if (answer === 'yes') {
try {
this.writeConfig(this.configExample);
console.log('写入完成,本程序自动退出。');
} catch (err) {
fatalError(err, '写入配置文件失败。');
process.exit(-1);
}
} else {
console.log('请正确配置config.yml. 本程序将自动退出.');
}
process.exit(0);
});
return;
}
this._config = yaml.load(configContent) as YamlConfig;
};

private writeConfig(config_data: string) {
fs.writeFileSync('./config.yml', config_data);
};

get registCommand() {
return registCommand;
};
get registGlobalMessageHandle() {
return registGlobalMessageHandle;
}
get registReplyHandle() {
return registReplyHandle;
}
}
32 changes: 26 additions & 6 deletions src/types/app.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import TelegramBot from 'node-telegram-bot-api';
import { YamlConfig } from './config.js';
import { registCommand, registGlobalMessageHandle, registReplyHandle } from '@/lib/command.js';
import { Std } from '@/lib/std.js';

export interface App {
/** @hidden */
_config?: YamlConfig;
/** @hidden */
_bot?: TelegramBot;
/**
* 用户在 config.yml 的配置
*/
Expand All @@ -15,11 +12,34 @@ export interface App {
* Telegram bot
*/
get bot(): TelegramBot;
/**
* 初始化app。只应执行一次。
*/
init(): Promise<void>;
/**
* 数据库获取
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get db(): any;

/**
* 获得标准输入输出交互器
*/
get std(): Std;

/**
* 获取版本号
*/
get version(): string;

/**
* 获取配置示例
*/
get configExample(): string;

registCommand: typeof registCommand;
registGlobalMessageHandle: typeof registGlobalMessageHandle;
registReplyHandle: typeof registReplyHandle;

// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
// [key: string]: any;
}
4 changes: 4 additions & 0 deletions src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export interface YamlConfig {
* TG风格: "/" QQ风格: "."
*/
command_style: '/' | '.';
/**
* 由于一场关机导致轮询时爬取古老消息,记作超时不处理的消息最短时间(秒)
*/
outdate_seconds: number;
}

export interface TelegramPlatform {
Expand Down
21 changes: 17 additions & 4 deletions src/util/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import fs from 'fs';

/**
* 读取文件,如果文件不存在则返回null
* Default use { encoding: 'utf-8' } as `options`
* @param fileName filename or file descriptor
* @param options If the encoding option is specified then this function returns a string. Otherwise it returns a buffer.
*/
export const readFileIfExists = (fileName: string) => {
export const readFileIfExists = (
fileName: string,
options: { encoding: BufferEncoding; flag?: string | undefined; } | undefined = { encoding: 'utf-8' }
) => {
const fileExist = fs.existsSync(fileName);
if (!fileExist) {return null;}
return fs.readFileSync(fileName, { encoding: 'utf-8' });
return fs.readFileSync(fileName, options);
};

const defaultDirs = [
Expand All @@ -18,10 +24,17 @@ const defaultDirs = [

/**
* 从里到外读取文件,如果文件不存在则返回null
* Default use { encoding: 'utf-8' } as `options`
* @param fileName filename or file descriptor
* @param options If the encoding option is specified then this function returns a string. Otherwise it returns a buffer.
*/
export const reverseReadFileIfExists = (fileName: string, reverseDirs: string[] = defaultDirs) => {
export const reverseReadFileIfExists = (
fileName: string,
reverseDirs: string[] = defaultDirs,
options: { encoding: BufferEncoding; flag?: string | undefined; } | undefined = { encoding: 'utf-8' }
) => {
for (const dir of reverseDirs) {
const fileContent = readFileIfExists(dir + fileName);
const fileContent = readFileIfExists(dir + fileName, options);
if (fileContent !== null) {return fileContent;}
}
return null;
Expand Down
Loading