Halo, Saya melihat analisis bot Anda di YouTube, dan mereka semua memiliki satu masalah besar: semua kode adalah alas kaki untuk 5k baris. Karena itu, saya punya pertanyaan: bagaimana Anda melihat bahwa proyek dengan VK-IO harus diatur. Karena dalam bentuknya saat ini, itu adalah footcloth atau indeks + konfigurasi + sekumpulan file yang terlihat seperti ini:
/** <strong i="8">@filename</strong>: config.ts */
export const vk = new VK({ /* ... */ })
/** <strong i="11">@filename</strong>: feat1.ts */
import { vk } from "./config"
vk.updates.on('message', async(ctx, next) => {
/* code */
})
/** <strong i="14">@filename</strong>: index.ts */
import { vk } from "./config"
import "./feat1"
vk.updates.startPolling().then(() => console.log("Bot works!"))
Dan itu juga memiliki masalah:
Akan senang mendengar jawaban Anda untuk ini dan menggandakannya dengan sangat eksplisit dalam dokumentasi, dan mungkin README.md
Saya tidak akan mengatakan bahwa pendekatan "resmi", saya hanya akan membagikan preferensi pribadi saya dan sedikit bagian praktisnya.
Saya lebih suka menggunakan pendekatan monorepo untuk mengatur modul terdistribusi (perpustakaan benar-benar menggunakannya). Anda dapat mengambil template siap pakai untuk layanan, dan memisahkan implementasi bot dari perpustakaan menggunakan abstraksi (karena setiap perubahan yang melanggar akan membutuhkan banyak perhatian untuk menyesuaikannya). Ada baiknya juga menggunakan mesin virtual untuk kondisi yang identik dalam pengembangan dan produksi, misalnya Docker akan membantu di sini.
Ketergantungan bot harus eksplisit, mis. tidak menambahkan "fitur" dengan satu impor, jika tidak, mimpi buruk debugging nyata akan dimulai di sini. Kode abstrak:
// commands/random.ts
import { Command } from '@my-project/core';
import { getRandomIntegerInRange } from '@my-project/utils';
export const randomCommand = new Command({
slug: 'random',
aliases: [
'ΡΠ°Π½Π΄ΠΎΠΌ',
'random'
],
description = 'ΡΠ°Π½Π΄ΠΌΠΎΠ½ΠΎΠ΅ ΡΠΈΡΠ»ΠΎ Π² ΠΏΡΠΎΠΌΠ΅ΠΆΡΡΠΊΠ΅';
arguments: [
{
type: 'integer',
key: 'min',
label: 'ΠΌΠΈΠ½ΠΊ/ΠΌΠ°ΠΊΡ',
default: null
},
{
type: 'integer',
key: 'max',
label: 'ΠΌΠΈΠ½ΠΊ/ΠΌΠ°ΠΊΡ',
default: null
}
],
handler(context) {
// Π Π°Π±ΠΎΡΠ°Π΅ΠΌ Ρ Π°ΡΠ³ΡΠΌΠ΅Π½ΡΠ°ΠΌΠΈ, Π° Π½Π΅ ΡΠ΅ΠΊΡΡΠΎΠΌ
let { min = null, max = null } = context.commander.params;
if (min === null && max === null) {
min = 0;
max = 100;
} else if (max === null) {
max = min;
min = 0;
}
const result = getRandomIntegerInRange(min, max);
return context.answer({
text: `ΡΠΈΡΠ»ΠΎ Π² ΠΏΡΠΎΠΌΠ΅ΠΆΡΡΠΊΠ΅ ${min} - ${max}: ${result}`
});
}
});
// commands/index.ts
export * from './random';
// bot.ts
import {
Bot,
SessionManager,
RedisSessionStorage,
RateLimitManager,
CommanderManager
} from '@my-project/core';
import * as commands from './commands';
const sessionManager = new SessionManager({
storage: new RedisSessionStorage({})
});
const rateLimitManager = new RateLimitManager({
maxPerSecond: 1
});
const commanderManager = new CommanderManager();
for (const command of Object.values(commands)) {
commanderManager.add(command);
}
const bot = new Bot({
// ...options
});
// ΠΡΠΎ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΊΠ°ΡΡΠΎΠΌΠ½Π°Ρ ΡΠ΅ΠΏΠΎΡΠΊΠ° middleware Π² Π±ΠΎΡΠ΅
bot.incoming.on('message', sessionManager.middleware);
bot.incoming.on('message', rateLimitManager.middleware);
bot.incoming.on('message', commanderManager.middleware);
bot.start()
.then(() => {
console.log('Bot started', error);
})
.catch((error: Error) => {
console.error('Error starting bot', error);
process.exit(1);
});
Hal-hal penting dari kode di atas:
@my-project/core
, yang berisi hal-hal yang diperlukan untuk bot.Dispatcher
. Mengapa ini perlu? Semuanya sangat sederhana - Anda dapat memanggil perintah dari mana saja dengan parameter yang ditentukan. Dari teks, kami menguraikan argumen yang dijelaskan dalam perintah dengan cara apa pun yang nyaman, dan tombol-tombol di keyboard sudah diatur dengan mereka dan dialamatkan ke perintah yang kami butuhkan. Jadi, kami menghindari duplikasi logika dan mengatur validasi argumen. Misalnya memanggil satu perintah dari yang lain:export const dndCommand = new Command({
// ...
handler(context) {
return context.commander.enter('random', {
params: {
min: 1,
max: 20
}
});
}
});
Ini adalah pendekatan yang saya gunakan di bot saya, dan ternyata cukup nyaman untuk diterapkan dari bot yang sederhana hingga yang rumit. Paling-paling, paket @my-project/core
seharusnya hanya menjadi alias perpustakaan yang telah menerapkan dan menguji semuanya, dan file terlihat seperti ini:
export { Bot, Command } from 'super-bot-library';
export { ViewerManager } from './middlewares';
Dalam kasus perubahan di perpustakaan, maka dimungkinkan untuk mengganti salah satu antarmuka. Tapi tidak ada yang melarang menyimpan semua logika hanya untuk proyek.
Ada implementasi lain yang menarik dari logika bot pada kait, yang digunakan misalnya dalam React
atau Vue
, Anda dapat menyodoknya langsung menggunakan kode ini .
Terima kasih atas jawaban yang sangat baik dan terperinci. Dan saya ingin meminta Anda untuk membiarkan masalah ini terbuka sehingga orang lain dapat membacanya juga
Komentar yang paling membantu
Saya tidak akan mengatakan bahwa pendekatan "resmi", saya hanya akan membagikan preferensi pribadi saya dan sedikit bagian praktisnya.
Desain umum
Saya lebih suka menggunakan pendekatan monorepo untuk mengatur modul terdistribusi (perpustakaan benar-benar menggunakannya). Anda dapat mengambil template siap pakai untuk layanan, dan memisahkan implementasi bot dari perpustakaan menggunakan abstraksi (karena setiap perubahan yang melanggar akan membutuhkan banyak perhatian untuk menyesuaikannya). Ada baiknya juga menggunakan mesin virtual untuk kondisi yang identik dalam pengembangan dan produksi, misalnya Docker akan membantu di sini.
Arsitektur
Ketergantungan bot harus eksplisit, mis. tidak menambahkan "fitur" dengan satu impor, jika tidak, mimpi buruk debugging nyata akan dimulai di sini. Kode abstrak:
Hal-hal penting dari kode di atas:
@my-project/core
, yang berisi hal-hal yang diperlukan untuk bot.Dispatcher
. Mengapa ini perlu? Semuanya sangat sederhana - Anda dapat memanggil perintah dari mana saja dengan parameter yang ditentukan. Dari teks, kami menguraikan argumen yang dijelaskan dalam perintah dengan cara apa pun yang nyaman, dan tombol-tombol di keyboard sudah diatur dengan mereka dan dialamatkan ke perintah yang kami butuhkan. Jadi, kami menghindari duplikasi logika dan mengatur validasi argumen. Misalnya memanggil satu perintah dari yang lain:Kesimpulan
Ini adalah pendekatan yang saya gunakan di bot saya, dan ternyata cukup nyaman untuk diterapkan dari bot yang sederhana hingga yang rumit. Paling-paling, paket
@my-project/core
seharusnya hanya menjadi alias perpustakaan yang telah menerapkan dan menguji semuanya, dan file terlihat seperti ini:Dalam kasus perubahan di perpustakaan, maka dimungkinkan untuk mengganti salah satu antarmuka. Tapi tidak ada yang melarang menyimpan semua logika hanya untuk proyek.
Ada implementasi lain yang menarik dari logika bot pada kait, yang digunakan misalnya dalam
React
atauVue
, Anda dapat menyodoknya langsung menggunakan kode ini .