@softvisio/core
Version:
Softisio core
409 lines (303 loc) • 11.4 kB
JavaScript
import crypto from "node:crypto";
import path from "node:path";
import L10nt from "#lib/locale/l10nt";
export default class {
#bot;
#id;
#location;
#parentCommand;
#childCommands;
#menuButton = {};
#commands = {};
#commandsList = {};
constructor ( bot, location ) {
this.#bot = bot;
this.#location = location;
}
// properties
get app () {
return this.#bot.app;
}
get bot () {
return this.#bot;
}
get telegram () {
return this.#bot.telegram;
}
get dbh () {
return this.#bot.app.dbh;
}
get id () {
this.#id ??= path.basename( this.#location ).replaceAll( "-", "_" );
return this.#id;
}
get parentCommand () {
if ( this.#parentCommand === undefined ) {
if ( this.id === "start" ) {
this.#parentCommand = null;
}
else {
let dirname = path.dirname( this.#location );
if ( dirname === "." ) {
this.#parentCommand = this.#bot.commands.get( "start" );
}
else {
while ( true ) {
this.#parentCommand = this.#bot.commands.getByLocation( dirname );
if ( this.#parentCommand ) break;
dirname = path.dirnam( dirname );
if ( dirname === "." ) break;
}
this.#parentCommand ||= this.#bot.commands.get( "start" );
}
}
}
return this.#parentCommand;
}
get childCommands () {
if ( this.#childCommands === undefined ) {
this.#childCommands = null;
for ( const command of this.#bot.commands ) {
if ( command.parentCommand === this ) {
this.#childCommands ??= [];
this.#childCommands.push( command );
}
if ( this.#childCommands ) {
this.#childCommands = this.#childCommands.sort( ( a, b ) => a.commandOrder - b.commandOrder );
}
}
}
return this.#childCommands;
}
get commandOrder () {
return 0;
}
// public
async init () {
return this._init();
}
async run ( ctx, message ) {}
async beforeRun ( ctx, message ) {
// set menu button
await this.#setMenuButton( ctx );
// set commads
await this.#setCommands( ctx );
}
async beforeExit ( ctx ) {}
isEnabled ( ctx ) {
return true;
}
getDescription ( ctx ) {
return this.id.replaceAll( "_", " " );
}
getGroupDescription ( ctx ) {}
getMenuButton ( ctx ) {
return null;
}
isChildCommandsEnabled ( ctx ) {
for ( const command of this.childCommands ) {
if ( command.isEnabled( ctx ) ) return true;
}
return false;
}
async sendCommandsList ( ctx, { level } = {} ) {
const commandsList = this.#getCommandsList( ctx, level );
if ( !commandsList ) return result( 200 );
return ctx.user.send( "sendMessage", {
"text": commandsList,
"parse_mode": "HTML",
} );
}
async [ "API_run" ] ( ctx, command ) {
return ctx.run( command );
}
dropPermissionsCache () {
this.#menuButton = {};
this.#commands = {};
this.#commandsList = {};
}
createCallbackData ( method, ...args ) {
if ( !method.includes( "/" ) ) method = this.id + "/" + method;
return this.bot.createCallbackData( method, ...args );
}
// protected
async _init () {
return result( 200 );
}
async _registerStartCallback ( id, method ) {
return this.bot.commands.registerStartCallback( id, this.id + "/" + method );
}
// private
async #setMenuButton ( ctx ) {
const menuButton = this.#getMenuButton( ctx );
if ( menuButton.data == null ) return;
const id = `${ ctx.user.locale }/${ ctx.permissions.hash }/${ menuButton.hash }`;
if ( id !== ctx.user.state.menuButtonId ) {
const res = await ctx.user.send( "setChatMenuButton", {
"menu_button": menuButton.data,
} );
if ( !res.ok ) return;
await ctx.user.updateState( {
"menuButtonId": id,
} );
}
}
async #setCommands ( ctx ) {
const commands = this.#getCommands( ctx );
const id = `${ ctx.user.locale }/${ ctx.permissions.hash }/${ commands.hash }`;
if ( id !== ctx.user.state.commandsId ) {
const res = await ctx.user.setChatCommands( commands.data );
if ( !res.ok ) return;
await ctx.user.updateState( {
"commandsId": id,
} );
}
}
#getMenuButton ( ctx ) {
const id = `${ ctx.user.locale }/${ ctx.permissions.hash }`;
if ( !this.#menuButton[ id ] ) {
const menuButton = this.getMenuButton( ctx );
const data = {
"data": null,
"hash": null,
};
if ( menuButton == null ) {
data.data = null;
}
else if ( menuButton === "commands" ) {
data.data = {
"type": "commands",
};
}
else if ( menuButton?.url ) {
data.data = {
"type": "web_app",
"text": menuButton.text || undefined,
"web_app": {
"url": menuButton.url,
},
};
}
else {
data.data = {
"type": "default",
};
}
data.hash = this.#getHash( data.data );
this.#menuButton[ id ] = data;
}
return this.#menuButton[ id ];
}
#getCommands ( ctx ) {
const id = `${ ctx.user.locale }/${ ctx.permissions.hash }`;
if ( !this.#commands[ id ] ) {
const data = {
"data": null,
"hash": null,
};
var commands = this.childCommands,
parentCommand = this.parentCommand;
if ( !commands ) {
commands = parentCommand?.childCommands;
parentCommand = parentCommand?.parentCommand;
}
// inherit
if ( !commands ) {
data.data = null;
}
else {
data.data = [];
const addedCommands = new Set();
for ( const commandInstance of commands ) {
if ( !ctx.isCommandEnabled( commandInstance ) ) continue;
addedCommands.add( commandInstance.id );
data.data.push( {
"command": commandInstance.id,
"description": this.#translate( ctx, commandInstance.getDescription( ctx ) ),
} );
}
// add parent command
if ( parentCommand && !addedCommands.has( parentCommand.id ) ) {
if ( ctx.isCommandEnabled( parentCommand ) ) {
addedCommands.add( parentCommand.id );
data.data.unshift( {
"command": parentCommand.id,
"description": this.#translate( ctx, parentCommand.getDescription( ctx ) ),
} );
}
}
// add start command
if ( !addedCommands.has( "staer" ) ) {
const commandInstance = this.#bot.commands.get( "start" );
addedCommands.add( commandInstance.id );
data.data.unshift( {
"command": commandInstance.id,
"description": this.#translate( ctx, commandInstance.getDescription( ctx ) ),
} );
}
if ( !data.data.length ) data.data = null;
}
data.hash = this.#getHash( data.data );
this.#commands[ id ] = data;
}
return this.#commands[ id ];
}
#getHash ( data ) {
return crypto.createHash( "MD5" ).update( JSON.stringify( data ) ).digest( "base64url" );
}
#getCommandsList ( ctx, level ) {
if ( !this.childCommands ) return;
level ||= 1;
if ( level !== 1 ) level = 2;
const id = `${ ctx.user.locale }/${ ctx.permissions.hash }/${ level }`;
if ( this.#commandsList[ id ] === undefined ) {
const commands = [];
// level 1
if ( level === 1 ) {
for ( const commandInstance of this.childCommands ) {
if ( !ctx.isCommandEnabled( commandInstance ) ) continue;
commands.push( `/${ commandInstance.id } - ${ this.#translate( ctx, commandInstance.getDescription( ctx ) ) }` );
}
}
// level 2
else {
for ( const commandInstance of this.childCommands ) {
// commands
if ( commandInstance.childCommands ) continue;
if ( !ctx.isCommandEnabled( commandInstance ) ) continue;
commands.push( `/${ commandInstance.id } - ${ this.#translate( ctx, commandInstance.getDescription( ctx ) ) }` );
}
// groups
for ( const commandInstance of this.childCommands ) {
if ( !commandInstance.childCommands ) continue;
if ( !ctx.isCommandEnabled( commandInstance ) ) continue;
const groupCommands = [];
for ( const groupCommand of commandInstance.childCommands ) {
if ( !ctx.isCommandEnabled( groupCommand ) ) continue;
groupCommands.push( `/${ groupCommand.id } - ${ this.#translate( ctx, groupCommand.getDescription( ctx ) ) }` );
}
// group has no commands
if ( !groupCommands.length ) continue;
commands.push( "" );
// group title
const groupDescription = commandInstance.getGroupDescription( ctx );
if ( groupDescription ) {
commands.push( "<b>" + this.#translate( ctx, groupDescription ) + "</b>" );
}
// group commands
commands.push( groupCommands.join( "\n" ) );
}
}
if ( commands.length ) {
commands.unshift( this.#translate( ctx, l10nt( "You can use these commands:\n" ) ) );
}
this.#commandsList[ id ] = commands.join( "\n" );
}
return this.#commandsList[ id ];
}
#translate ( ctx, template ) {
return L10nt.toString( template, {
"localeDomain": ctx.user.locale,
} );
}
}