Skip to content

alirezax5/baleBotBase

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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 استفاده میکرد از آنها در درایور کش استفاده کنید حتی میتونید به گزینه صف بندی هم فکر کنید چون که صف بندی از این دو درایو پشتیبانی میکند.

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

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

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

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

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

use alirezax5\BaleBase\App\Core;
use alirezax5\BaleBase\App\Enum\CoreMode;

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

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

پلاگین ها

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

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

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

<?php

namespace alirezax5\BaleBase\Plugin;

use alirezax5\BaleBase\App\Plugin\Contract\PluginInterface;

use baleBotPhp\bale;

class Start implements PluginInterface
{
    public function getPriority(): int
    {
        return 1;
    }

    public function onMessage($update, bale $bale)
    {
        SharedManagement::set('findCommand', 'na');
        $bale->sendMessage($update->from->id, $update->text,['reply_markup'=>btn('start')]);


    }
    public function onEditedMessage($update, bale $bale)
    {

    }
    public function onCallbackQuery($update, bale $bale)
    {

    }
    public function onInlineQuery($update, bale $bale)
    {

    }
    public function onPollAnswer($update, bale $bale)
    {

    }
  
    #.. سایر آپدیت ها
    
    public function before($update, bale $bale)
    {

    }
    public function after($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 تغییر دهید.

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

<?php
return [
    "remove" => ['KeyboardRemove' => [], 'remove_keyboard' => true],
    "start" =>  [
        'keyboard' => [
            [
                ['text' => __('btn_name')],

            ],

        ],
        'resize_keyboard' => true
    ]

];
برای استفاده از پلاگین ها از متد btn استفاده کنید مثال برای استفاده در پلاگین ها :
<?php

<?php

namespace alirezax5\BaleBase\Plugin;

use alirezax5\BaleBase\App\Plugin\Contract\PluginInterface;

use baleBotPhp\bale;

class Start implements PluginInterface
{
    public function getPriority(): int
    {
        return 1;
    }

    public function onMessage($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 قرار دهید. نمونه‌ی ساختار و تعریف دیتابیس:

<?php

namespace Database;

use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Capsule\Manager as DB;

class Users extends Model
{
    protected $table = 'users';
    protected $primaryKey = 'chatid';
    protected $casts = [
        'active' => 'boolean',
        'status' => 'boolean'
    ];
    public $timestamps = false;
    protected $connection = 'main';

    public static function checkAndInsert(int $chatid): bool
    {
        return !self::check($chatid) && self::insertOrIgnore(['chatid' => $chatid]);
    }

    public static function check(int $chatid): bool
    {
        return self::where('chatid', $chatid)->exists();
    }

    public static function getAllStatusActiveUser(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();
    }
    public static function getAllStatusActiveUserByLang($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();
    }

    public static function getAllActiveUser(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();
    }

    public static function getAll(bool $limit = true, int $page = 1, int $per = 20)
    {
        $query = self::orderBy('id');
        return $limit ? $query->paginate($per, ['*'], 'page', $page) : $query->get();
    }

    public static function getByRole(string $role)
    {
        return self::where('role', $role)->get(['id', 'chatid']);
    }

    public static function getAdmins()
    {
        return self::getByRole('admin');
    }

    public static function getCountByField(string $field, $value): int
    {
        return self::where($field, $value)->count();
    }


    public static function getCountAll(): int
    {
        return self::count();
    }

    public static function getCountAdmin(): int
    {
        return self::getCountByField('role', 'admin');
    }


    public static function getUser(int $chatid)
    {
        return self::where('chatid', $chatid)->first();
    }

    public static function getUserById($id)
    {
        return self::where('id', $id)->first();

    }

    public static function updateFieldByChatId(int $chatid, string $field, $value): bool
    {
        return self::where('chatid', $chatid)->update([$field => $value]);
    }



    public static function getRecentUsers()
    {
        $twentyFourHoursAgo = Carbon::today();

        $recentUsers = DB::table('users')
            ->where('create_at', '>=', $twentyFourHoursAgo)
            ->count();

        return $recentUsers;
    }

}
نکته : برای اضافه کردن کانکشن جدید به فایل Connections.php مراجعه کنید
<?php

use alirezax5\TelegramBase\App\Shared\SharedManagement;
#ثبت داده
SharedManagement::set('findCommand', 'na');
#دریافت داده
SharedManagement::get('findCommand', 'default');
#ثبت داده ای که بعد از انجام آپدیت پاک نشود.
SharedManagement::set('findCommand', 'na',true);

لاگ گیری

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

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

<?php

use alirezax5\TelegramBase\App\Logger\LogHandler;
 LogHandler::warning("warning");
 LogHandler::info('info');

کش

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

<?php

namespace Functions;

use alirezax5\BaleBase\App\Cache\CacheManager;
use alirezax5\BaleBase\App\Environment\EnvHandler;
use baleBotPhp\bale;

class CacheData
{

    static public function getchat(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

Watchers

Forks

Packages

 
 
 

Contributors

Languages