خب، از تایتل معلومه هدف چیه. اگه گفتید هدف چیه!؟
قراره یه بات تلگرام بنویسم با TelegrafJs که تحت NodeJs روی Heroku با استفاده از Axios برای گرفتن دیتا از GitHub API اجرا میشه ?. خیلی عجیب بود، نه؟
بی شوخی بریم توضیح بدیم. این بلاگ یه پروژه آموزشی هست که قراره اینا رو یاد بگیریم:
قراره کلی خسته بشیما! پس همراه باشید که قراره کلی کیف کنیم و چیز میز یاد بگیریم. اول بریم سراغ راه اندازی محیط و شروع به کار.
اول از همه ساخت یه پوشه و اینیت کردن گیت هست.
حالا نوبت اینیت کردن npm هست. بله. پس خیلی راحت اونم انجام میدیم.
با دستور npm init شروع میکنیم به ساخت اون فایل package.json و وارد کردن اطلاعات. خب، این انجام شد، مرحله بعدی اینه که بیایم بگیم که بدون اینکه هر دفعه پروژه رو اجرا کنیم، یه کاری کنیم که هر دفعه بعد هر سیو، خودش watch کنه و خودش رو Restart کنه. برای استفاده از این مورد، میایم از nodemon استفاده میکنیم. برای نصب nodemon:
حالا هم نصب شد. بریم فایل اپلیکیشن رو بسازیم. قبلش بیایم یه کاری کنیم. بیایم ترمینال رو نصف کنیم، بالا کامیت ها و پایین اجرا. خب، با دستور tmux وارد تیماکس بشید، بزنید کنترل B و شیفت " رو بزنید تا صفحه نصب بشه. بالا با دستور code [dot] وارد vs code بشیم و پایین فایل اپلیکیشن رو بسازیم.
حالا، وارد package.json بشید و داخل scripts دستور تست رو وارد کنید به این صورت:
"scripts": {
"test": "nodemon app.js"
},
حالا وارد پایین ترمینال بشید و با دستور npm test برنامه رو اجرا کنید. میدونم برنامه خالیه. اما ولی خب میخوایم اجراش کنیم دیگه. فقط، چون تلگرام نیازمند vpn هست و درخواست های بات قراره وارد دستگاه ما بشه و جواب برگرده، من با استفاده از torsocks برنامه رو اجرا میکنم.
خب، حالا اجرا شد، ترمینال بالایی میشه قسمتی برای نصب، کامیت و غیره، پایین رو اصلا کاری نداریم. بزارید اجرا بمونه همینطوری. بریم بالا dotenv رو نصب کنیم، فایل env و env.example رو بسازیم و یه بات در BotFather بسازیم.
خب، وقتی نصب کردیم، خودش خودکار ریست شد برنامه با اینکه ما چیزی کد نزدیم. برنامه با هر تغییری، ریست میشه. یادتون نره. این خوبه، بد نیست. بریم وارد تلگرام بشیم، یه بات بسازیم.
بات ما ساخته شد. یه توکن هم بهمون داده. حالا ما چرا اومدیم dotenv رو نصب کردیم و اینا. ما یه چیزی داریم به اسم environment variables یا به فارسی میشه مقادیر محیطی. اینا مقادیری هست که ما میدیم و میخوام پنهان باشه. مثلا یوزرنیم و رمز دیتابیس، توکن تلگرام و اینا رو میایم اونجا میزاریم. با استفاده از dotenv هم اونا رو میخونیم. dotenv توسط gitignore اگنور میشه. یعنی نادیده گرفته میشه. اینطوری ما با خیال راحت میایم هر چی بخوایم مینویسیم و فقط داخل اون محیط هست. با فایل env.example چیکار داریم؟ اونجا میایم نام مقادیر رو میزاریم ولی بهشون مقدار نمیدیم. چرا؟ چون مثلا الان من داخل لینوکس ام دارم این اپ رو توسعه میدم، میخوام وقتی رفتم سر مک، ادامه توسعه رو انجام بدم. میام اون فایل که اگزمپل هست و ایگنور نمیشه رو پسوندش رو حذف میکنم میشه env و اون موقع مقدار رو بهش میدم.
خب، مقادیر رو بزاریم.
فقط مونده یه فایل gitignore رو هم بزاریم که پوشه ماژول ها و .env رو ایگنور کنه تا تو گیت اد نشه. خب من این رو دارم از قبل، پس از یه جا کپی میکنم اونجا. ولی قبلش بیایم یه git status بگیریم ببینیم یه چیزی رو.
وقتی اینجا وضعیت رو میبینیم، اون فایل .env و node_modules رو میبینیم. خب میخوایم نباشن اینا. پس فایل ایگنور رو کپی کنیم.
اینم از این، حالا من اینا رو کامیت میکنم و میریم مرحله آموزش بات.
گفتیم قراره بات رو با TelegrafJs بنویسیم. پس نیازه اونو اول از همه نصب کنم.
نصب شد و تغییرات پکیج رو کامیت کردیم. یه سری دستور هست که در zsh اینا الیاس شدند. یعنی مثلا شما جای git add میزنید ga. بریم اینا هم مرور کنیم مهم هاش رو:
اینم از این مورد. وارد کد بشیم دیگه. بریم کتابخونه رو ایمپورت کنیم، مقادیر محیطی رو بخونیم، بات رو برای استارت آماده کنیم.
اول از همه که اومدیم کتابخونه رو اوردیم بالا، بعد کانفیگ dotenv و بعدش اومدیم گفت که همه مقادیر رو بریز تو متغیر env. بعد که بات رو اومدیم شروع کنیم، میگیم یه نیو کن تلگراف رو که بهش داریم توکن بات رو میدیم. بعدش در انتها لانچ میکنیم بات رو.
بات الان اجرا شده. ولی هیچ دستوری نداره. شما هر کاری کنی کاری انجام نمیده. حالا بیایم درخواست های کاربر رو هندل کنیم.
هندل کردن دستورات کاربر به چند دسته تقسیم میشه. بگیم که اگه دستور بود، بگیم که اگه دقیقا فلان چیز رو شنیدی و یا بر روی فلان چیز اکت نشون بده. مثلا چی؟
اولی گفتیم اگه دستور استارت رو وارد کرد. دومی گفتیم اگه دقیقا گفت hi و سومی گفتیم اگه فقط روی استیکر بود. اون آخر فقط استیکر نیست. میتونیم کلی چیز بگیم. مثلا:
خب، میبینیم که ما همیشه داریم ctx رو به عنوان دومین چیز در متد میدیم. اون چیه؟
داخل ctx اطلاعاتی از چت، پیام، کاربر و غیره هست. ما حتی با استفاده از ctx میایم ریپلی میکنیم. بریم روی اینا یه چیزی ریپلی کنیم:
با متد replay ما الان میتونیم یه چیزی رو ریپلی کنیم. انواع ریپلی ها هم هستا. ریپلی عکس، متن، html و غیره. حالا تست کنیم.
خب، به زیبایی داره بات ما کار میکنه. این یه آموزش خیلی سریع بود برای اینکه یه بات ساده بسازیم. ببینید این یه جورایی کرش کورس هست. عمیق نمیشیم تو بات تلگرام مثلا. میگیم و میریم و سعی میکنیم کامل اون موضوع رو توضیح بدیم تا حدی.
ما فعلا فقط میخوایم یه پیام بگیره، اون رو به عنوان یوزرنیم حساب کنه. پس میگیم متد on و بهش message رو میدیم. داخل ctx، آیتم message و آیتم text میشه متی که ما ارسال میکنیم. بیایم یه کاری کنیم پیام ما رو بخونه و همونو برگردونه:
حالا که متن رو داخل یه متغیر میریزه میخوایم که تست کنیم.
بله. سر بلند بیرون اومد برنامه و میتونیم بریم مرحله بعد.
مرحله بعد آشنایی با API گیتهاب هست! مرحله شیرین API ها.
برای استفاده از API گیتهاب وارد این لینک باید بشید. به قول خارجیا، magic happens here!
https://api.github.com/
بریم اندپورنت های مهم رو ببینیم.
User data => https://api.github.com/users/{users} Repos data => https://api.github.com/users/{BlackIQ}/repos Repo data => https://api.github.com/repos/{username}/{repo name} Followers of a user => https://api.github.com/users/{username}/followers Followings of a user => https://api.github.com/users/{username}/following
ما فقط قراره از اولی استفاده کنیم. مهم نیست زیاد بقیه. بریم کاربر گل، امیرحسین با ایدی BlackIQ رو ببینیم داستانش چطوریه.
حالا اطلاعات منو مثلا میتونید ببینید و لینک و اینا هم هست. لینک فالوور ها، فالووینگ ها، ریپو ها و غیره.
این یه نیمچه آشنایی بود با API گیتهاب. مرحله بعدی استفاده از Axios هست برای گرفتن اطلاعات.
بریم نصب کنیم این لایبرری رو!
خب، حالا که نصب شد. بریم ایمپورت کنیم.
حالا که ایمپورت کردیم بریم یکم درباره Axios صحبت کنیم. توسط این لایبرری میتونیم درخواست های Get، Post و غیره رو انجام بدیم. ما فعلا نیاز داریم فقط و فقط دیتا از گیتهاب بگیریم. پس از Get استفاده میکنیم.
حالا یه متد گت اجرا شد، اجرا میشه، درخواست میده، و ما میگیم که اگه درست انجام دادی، یه data بده اما ولی اگه ارور بود، ارور رو بده. داخل دیتایی که ما میگیریم چیه؟ این دیتا شامل مواردی میشه که مهم ترین اونا data هست. دیتایی که خودمون گرفتیم نه، داخل این دیتا که ما گرفتیم یه دیتا دیگه وجود داره. برای اینکه گمراه نشید بزارید اونی که میگیریم رو بزاریم response. حالا بیایم دیتایی که میگیریم رو به بات بفرستیم. یعنی ریپلی ما، دیتا باشه.
برای اینکه ریپلی به صورت Json باشه، باید اون data که از API گرفتیم رو بدیم به JSON.stringify و اون رو ریپلی کنیم. حواستون باشه متغیر input رو به username تغییر دادم که یکم خوانا تر باشه.
حالا دیتا که گرفته شده به صورت Json به ما برمیگرده. خیلی واضح هست ولی بازم تست کنیم.
اینم از این. ما الان دیتا رو میگیریم. خب، حالا کافیه بیایم یه حرکتی بزنیم. بیایم تعریف کنیم قراره چیه رو برگردونیم به کاربر بات. قبل از اینکه چیزی رو برگردونیم، یه بار دیگه به دیتایی که از API میاد یه نگاه بندازیم. برای فرمت کردن Json از jsonformatter استفاده میکنیم. حالا دیتا رو گذاشتم داخل ورودی، اومدم از خروجی اونایی که لازم داریم رو نگه داشتم و اونایی که نیاز نمیشن رو حذف.
خب، لاگین یعنی همون یوزرنیم ما، آواتار و لینک پروفایل هم به سادگی مفهوم هستند. لینک بلاگ/سایت و توییتر هم هستند. اطلاعات Bio موقعیت مکانی و شرکت هم نگه داشتیم. در آخر تعداد فالوور و فالووین ها، همینطوری ریپوزیتوری ها و گیست ها و در آخر آخر، جوین گیتهاب.
این اطلاعات رو نگه میداریم تا به صورت یک متن ساده به کاربر نمایش بدیم. متن رو به صورت Markdown مینویسیم و با متد replyWithMarkdown اون رو ریپلی میکنیم. خب، اگه که MD کار کرده باشید با سینتکس آشنا هستید. اما اگه نه، اینجا یه خلاصه میریم. همینطوری دقت کنید که توی تلگرام یکم تفاوت داره. خیلی ریز.
Bold a text:
Markdown: **Text** | Telegram Markdown: *Text*
Italic a text:
Markdown: *Text* | Telegram Markdown: _Text_
Link:
Markdown & Telegram Markdown: [Text](Link)
خلاصه، اینطوری ما میتونیم بولد کنیم، ایتالیک کنیم و لینک بزاریم. متنی که ما درست کردیم به این صورت هست:
حالا، این متن که درست شده، لازم هست که تستش کنیم. یه مرور کنید کد رو، تا بریم تست.
حالا وقتشه که برنامه رو تست کنیم.
اینم تست. برنامه خیلی خوب دیتا رو میگیره، دیتا رو میده. مرحله بعدی چی بود؟ اجرا برنامه روی هروکو. اما ولی قبلش بیایم کامیت کنیم یادمون نره.
برای اجرا روی هروکو ابتدا نیاز هست که هروکو روی سیستم شما نصب باشه. از طریق Snap خیلی راحت میتونید نصب کنید با این دستور:
sudo snap install heroku --classic
حالا، داخل ترمینال وارد کنید دستور لاگین رو:
اینجا باید مرورگر که باز میشه رو لاگین کنید داخل حسابتون:
حالا که لاگین بشه همچین صفحه ای رو مشاهده میکنید و داخل ترمینال شما لاگین میشید:
حالا، باید یه فایل بسازیم به اسم Procfile و بهش بگیم که شما باید چی رو اجرا کنی. دستوری که قراره اجرا بشه، دستور node app.js هست. پس بیایم این دستور رو توی package.json به عنوان start بنویسیم. یعنی در قسمت scripts این رو اضافه کنیم به این صورت:
حالا وقت این هست که Procfile رو بسازیم و بهش بگیم که بیا برای ما استارت رو اجرا کن:
از اینجا به بعد دیگه با هیچ فایلی کار نخواهیم داشت. فقط کافیه که اپ رو بسازیم و بگیم روی هروکو پوش کنه. در آخر هم توکن بات رو به عنوان متغیر های محیطی یا همون env variables بدیم. حالا فعلا تغییرات رو کامیت کنیم:
برای دیپلوی کافیه یه اول بگیم که برامون برنامه رو بساز. با دستور heroku create x:
یه ریپو برامون ساخته شد. الان بیایم متغیر هامون رو اضافه کنیم. برای تنظیم متغیر ها کافیه بگیم که heroku config:set و بعد بهش مقدار رو با نام بدیم. مثال:
اینم از این. حالا مقدار توکن بات هم قرار دادیم. نوبت به پوش کردن میرسه که با دستور git push heroku master این کار رو انجام میدیم:
حالا برنامه ما پوش شد. اما ولی ارور پایین برای چی هست؟
ارور میگه که یه برنامه دیگه با این توکن داره اجرا میشه. پس این نشون میده برنامه ما درست هست. حالا برنامه لوکال رو متوقف میکنیم چون روی هروکو در حال اجرا هست.
این برنامه نه کرش کورس بود، نه دوره بود و نه موضوع خاصی رو اختصاصی گسترش دادیم. همینطوری گفتیم یه چیز ساده بنویسیم تازه روش هم کار نکردیم زیاد. فقط خواستم یه خلاصه از این مباحث نشون بدم.