Skip to content

Repository files navigation

baleBotBase


توجه: این پروژه را ابتدا برای ربات‌های خودم توسعه دادم و تصمیم گرفتم آن را منتشر کنم تا اگر برای شما هم کاربردی بود، بتوانید از آن استفاده کنید.

در صورت مشکل در کار با پروژه از هوش مصنوعی جیمنای با لینک زیر استفاده کنید. اکثر موارد مورد نیاز به gem داده شده است.

https://gemini.google.com/gem/13NSCMFOipq6HMvSRPZ2NvhKGzuYVrTDS?usp=sharing


🎯 هدف پروژه

هدف از توسعه این بیس، سادگی در کدنویسی و بهینه‌سازی برای سرویس‌دهی به تعداد بالای کاربر است.
سعی کرده‌ام در حد امکان مصرف منابع (CPU / RAM / I/O) پایین باشد و ساختار پروژه قابل توسعه و انعطاف‌پذیر باقی بماند.

در بخش‌های مختلف پروژه از کمک هوش مصنوعی هم استفاده شده است. کمک گرفتن هیچ ایرادی ندارد — خروجی نهایی حاصل چند سال تجربه در ساخت ربات‌های تلگرامی است و با کمک AI روی بهینگی و انتخاب بهترین ساختار تمرکز شده است.


✅ امکانات بیس

  • پشتیبانی از وبهوک, اجرای cli و کرون جاب
  • پشتیبانی از صف بندی آپدیت ها
  • پشتیبانی از منطق جدا سازی صب بندی و اجرای اسکریپت
  • امکان توسعه چند زبانه
  • امکان افزودن چندین دیتابیس
  • سیستم کشینگ
  • پشتیبانی از سیستم پلاگین
  • امکان پوشه بندی پلاگین ها برای توسعه راحت ت
  • لاگ گیری و بررسی راحت لاگ ها
  • پشتیبانی از چندین درایور کشینگ, صف بندی و دیتابیس
  • امکان استفاده از متغییر های داینامیک در زبان ها و دکمه

نصب و راه اندازی

روش اول

git clone https://github.com/alirezax5/baleBotBase.git

نیازه که git روی سیستم نصب باشه.

پس از کلون دستور زیر رو در پوشه ی سورس بزنید :

composer install

روش دوم

دانلود از بخش releases

پس از دانلود دستور زیر رو در پوشه ی سورس بزنید :

composer install

فرقی نمیکنه از کدوم روش استفاده کنید.

تنظیمات

تمامی تنطیمات و کانفیگ سورس در فایل .env قرار داره

حالت های ربات

در حال حاضر سورس حالت های زیر رو داره :

  • update_direct

در این حالت سورس با استفاده از polling آپدیت هارا دریافت میکنه و بدون صف بندی اجرا میکنه

  • update_queue

در این حالت سورس با استفاده از polling آپدیت هارا دریافت میکنه و به صف آپدیت ها اضافه میکنه

  • webhook_direct

در این حالت آپدیت هایی که از وبهوک میان به صورت مستقیم اجرا میشه

  • webhook_queue

در این حالت آپدیت هایی که از وبهوک میان به صف برای اجرای به ترتیب اضافه میشن

  • cronjob_update

در این حالت شما می توانید کرون جاب ست کنید و سورس با استفاده از polling و حلقه بی نهایت آپدیت هارو اجرا میکنه

  • cronjob_queue

در این حالت کرون جاب با استفاده از polling اپدیت ها وارد صف می شن.

راه اندازی

پیشنهاد اول راه اندازی اگر سرور دارید نصب rabbitmq, redis,Supervisor می باشد تا هم از قابلیت صف بندی استفاده کنید و هم از Supervisor برای مدیریت اجرا استفاده کنید:

در env :

BOT_MODE="update_queue"QUEUE_SAVE_TYPE="rabbitmq"CACHE_DRIVER="redis"
قرار بدید

و کانفیگ برای Supervisor :

[program:name]
command=php /www/wwwroot/domain/newBase/bot.php
directory=/www/wwwroot/domain/newBase
autorestart=true
startsecs=3
startretries=3
stdout_logfile=/www/server/panel/plugin/supervisor/log/test.out.log
stderr_logfile=/www/server/panel/plugin/supervisor/log/test.err.log
stdout_logfile_maxbytes=2MB
stderr_logfile_maxbytes=2MB
user=root
priority=999
numprocs=2
stopsignal=QUIT
process_name=name

توجه داشته باشید که مقدار های کانفیگ نمونه رو تغییر بدید.

در صورتی که از هاستینگی استفاده می کنید که از Supervisor استفاده نمیکنه:

BOT_MODE="webhook_direct"QUEUE_SAVE_TYPE="json"CACHE_DRIVER="array"
نکته : اگر هاستینگ از memcached یا redis استفاده میکرد از آنها در درایور کش استفاده کنید حتی میتونید به گزینه صف بندی هم فکر کنید چون که صف بندی از این دو درایو پشتیبانی میکند.

در صورتی که دامنه ندارید میتونید از روش کرون جاب استفاده کنید.

فایل های مورد نیاز:

اگر از صف بندی استفاده نمی کنید :

usealirezax5\BaleBase\App\Core;
include'./vendor/autoload.php';
$core = newCore();
$core->run();

اما اگر میخواید استفاده کنید به 2 فایل نیاز دارید :

usealirezax5\BaleBase\App\Core;
usealirezax5\BaleBase\App\Enum\CoreMode;
include'./vendor/autoload.php';
$core = newCore(CoreMode::UPDATES_ONLY);
$core->runFetchQueueUpdate();
برای دریافت آپدیت ها
usealirezax5\BaleBase\App\Core;
include'./vendor/autoload.php';
$core = newCore();
$core->run();
برای اجرای آپدیت ها

نکته : شما حتی می توانید دریافت و اجرا آپدیت رو در سرور ها مختلف قرار بدید.

پلاگین ها

سورس از پوشه بندی پلاگین ها پشتیبانی میکنه برای همین میتونید پلاگین هارو دسته بندی کنید فقط باید دقت داشته باشید که نام پوشه را در namespace کلاس قرار داده باشید

برای تنظیم کانفیگ ها میتوانید به فایل .env مراجعه کنید.

نمونه کد پلاگین :

<?phpnamespacealirezax5\BaleBase\Plugin;
usealirezax5\BaleBase\App\Plugin\Contract\PluginInterface;
usebaleBotPhp\bale;
class Start implements PluginInterface
{
publicfunctiongetPriority(): int
{
return1;
}
publicfunctiononMessage($update, bale$bale)
{
SharedManagement::set('findCommand', 'na');
$bale->sendMessage($update->from->id, $update->text,['reply_markup'=>btn('start')]);
}
publicfunctiononEditedMessage($update, bale$bale)
{
}
publicfunctiononCallbackQuery($update, bale$bale)
{
}
publicfunctiononInlineQuery($update, bale$bale)
{
}
publicfunctiononPollAnswer($update, bale$bale)
{
}
#.. سایر آپدیت هاpublicfunctionbefore($update, bale$bale)
{
}
publicfunctionafter($update, bale$bale)
{
}
}

نام متدها در ساختار PascalCase تعریف می‌شوند و هر نوع آپدیت، به متد مخصوص خودش ارسال خواهد شد. پارامترهای $update و $bale در تمام متدها به‌صورت ثابت ارسال می‌شوند.

متد getPriority

این متد برای تعیین اولویت اجرای پلاگین استفاده می‌شود.

پیشنهاد می‌شود هنگام دریافت اطلاعات اولیه‌ی کاربر، مقدار اولویت را روی 0 قرار دهید. اگر ترتیب اجرای پلاگین برای شما اهمیتی ندارد، مقدار 999 را تنظیم کنید.

متدهای before و after

before قبل از اجرای متد مربوط به آپدیت فراخوانی می‌شود.

after پس از اجرای متد آپدیت اجرا خواهد شد.

این ساختار به شما اجازه می‌دهد منطق پیش‌پردازش و پس‌پردازش را به‌صورت مجزا و تمیز مدیریت کنید.

زبان ها

بیس به شما این امکان رو میده یک ربات چندزبانه رو توسعه بدید در فایل .env شما می توانید زبان پیشفرض,مسیر زبان ها و مدت زمان کش زبان ها را تنظیم نمایید. پیشفرض در پوشه Language و با پسوند php باید متون خود رو ذخیره کنید.

برای فرخوانی متن و تغییر زبان می توانید از مثال زیر استفاده کنید :

<?php# دریافت ترجمه براساس نام کلید در فایل json__('name');
# برای تنظیم زبان
Language::getInstance()->setLanguageDir( 'fa');
# برای جایگزین کردن مقدار خاص در متن ترجمه__('name',['id'=>1]);
نمونه فایل زبان :
return [
"key" => "value",
"key2" => "value #id",
];

دکمه ها

دکمه‌ها به‌صورت پیش‌فرض در فایل btn.php در ریشه‌ی سورس قرار دارند. در صورت نیاز، می‌توانید مسیر این فایل را از طریق تنظیمات .env تغییر دهید.

نمونه‌ی فایل تعریف دکمه‌ها:

<?phpreturn [
"remove" => ['KeyboardRemove' => [], 'remove_keyboard' => true],
"start" => [
'keyboard' => [
[
['text' => __('btn_name')],
],
],
'resize_keyboard' => true
]
];
برای استفاده از پلاگین ها از متد btn استفاده کنید مثال برای استفاده در پلاگین ها :
<?php<?phpnamespacealirezax5\BaleBase\Plugin;
usealirezax5\BaleBase\App\Plugin\Contract\PluginInterface;
usebaleBotPhp\bale;
class Start implements PluginInterface
{
publicfunctiongetPriority(): int
{
return1;
}
publicfunctiononMessage($update, bale$bale)
{
SharedManagement::set('findCommand', 'na');
$bale->sendMessage($update->from->id, $update->text,['reply_markup'=>btn('start')]);
}
}

دیتابیس

تنظیمات مربوط به دیتابیس را می‌توانید در فایل .env ویرایش کنید. از آن‌جایی که این بیس از illuminate/database استفاده می‌کند، می‌توانید برای نحوه‌ی کار با کوئری‌ها و مدل‌ها از مستندات لاراول کمک بگیرید:

🔗 https://laravel.com/docs/12.x/queries

به‌طور کلی، فایل‌های مربوط به دیتابیس را در پوشه‌ی Database قرار دهید. نمونه‌ی ساختار و تعریف دیتابیس:

<?phpnamespaceDatabase;
useCarbon\Carbon;
useIlluminate\Database\Eloquent\Model;
useIlluminate\Database\Capsule\ManagerasDB;
class Users extends Model
{
protected$table = 'users';
protected$primaryKey = 'chatid';
protected$casts = [
'active' => 'boolean',
'status' => 'boolean'
];
public$timestamps = false;
protected$connection = 'main';
publicstaticfunctioncheckAndInsert(int$chatid): bool
{
return !self::check($chatid) && self::insertOrIgnore(['chatid' => $chatid]);
}
publicstaticfunctioncheck(int$chatid): bool
{
returnself::where('chatid', $chatid)->exists();
}
publicstaticfunctiongetAllStatusActiveUser(bool$limit = true, int$page = 1, int$per = 20)
{
$query = self::where('status', true)->orderBy('id');
return$limit ? $query->paginate($per, ['*'], 'page', $page) : $query->get();
}
publicstaticfunctiongetAllStatusActiveUserByLang($lang = 'all',bool$limit = true, int$page = 1, int$per = 20)
{
if ($lang == 'all')
$query = self::where('status', true)->orderBy('id');
else$query = self::where('status', true)->where('lang', $lang)->orderBy('id');
return$limit ? $query->paginate($per, ['*'], 'page', $page) : $query->get();
}
publicstaticfunctiongetAllActiveUser(bool$limit = true, int$page = 1, int$per = 20)
{
$query = self::where('active', true)->orderBy('id', 'DESC');
return$limit ? $query->paginate($per, ['*'], 'page', $page) : $query->get();
}
publicstaticfunctiongetAll(bool$limit = true, int$page = 1, int$per = 20)
{
$query = self::orderBy('id');
return$limit ? $query->paginate($per, ['*'], 'page', $page) : $query->get();
}
publicstaticfunctiongetByRole(string$role)
{
returnself::where('role', $role)->get(['id', 'chatid']);
}
publicstaticfunctiongetAdmins()
{
returnself::getByRole('admin');
}
publicstaticfunctiongetCountByField(string$field, $value): int
{
returnself::where($field, $value)->count();
}
publicstaticfunctiongetCountAll(): int
{
returnself::count();
}
publicstaticfunctiongetCountAdmin(): int
{
returnself::getCountByField('role', 'admin');
}
publicstaticfunctiongetUser(int$chatid)
{
returnself::where('chatid', $chatid)->first();
}
publicstaticfunctiongetUserById($id)
{
returnself::where('id', $id)->first();
}
publicstaticfunctionupdateFieldByChatId(int$chatid, string$field, $value): bool
{
returnself::where('chatid', $chatid)->update([$field => $value]);
}
publicstaticfunctiongetRecentUsers()
{
$twentyFourHoursAgo = Carbon::today();
$recentUsers = DB::table('users')
->where('create_at', '>=', $twentyFourHoursAgo)
->count();
return$recentUsers;
}
}
نکته : برای اضافه کردن کانکشن جدید به فایل Connections.php مراجعه کنید
<?phpusealirezax5\TelegramBase\App\Shared\SharedManagement;
#ثبت داده
SharedManagement::set('findCommand', 'na');
#دریافت داده
SharedManagement::get('findCommand', 'default');
#ثبت داده ای که بعد از انجام آپدیت پاک نشود.
SharedManagement::set('findCommand', 'na',true);

لاگ گیری

برای تنظیم مسیر فایل لاگ، نام فایل، و همچنین فعال یا غیرفعال کردن سیستم لاگ، می‌توانید مقادیر مربوطه را در فایل .env تغییر دهید.

نمونه‌ای از ثبت لاگ:

<?phpusealirezax5\TelegramBase\App\Logger\LogHandler;
LogHandler::warning("warning");
LogHandler::info('info');

کش

برای تنظیم تنظیمات کش میتونید به .env مراجعه کنید نمونه کد:

<?phpnamespaceFunctions;
usealirezax5\BaleBase\App\Cache\CacheManager;
usealirezax5\BaleBase\App\Environment\EnvHandler;
usebaleBotPhp\bale;
class CacheData
{
staticpublicfunctiongetchat(bale$bale, $chatid)
{
$cacheKey = EnvHandler::get('CACHE_PREFIX') . 'getchat_' . $chatid;
if (!CacheManager::isInitialized())
return$bale->getchat($chatid);
if (CacheManager::has($cacheKey)) {
return CacheManager::get($cacheKey);
}
$getchat = $bale->getchat($chatid);
CacheManager::put($cacheKey, $getchat, 300);
return$getchat;
}

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages