پردازشگر خارجی
پردازشگر خارجی پلی است بین کد شما و Telegram. وقتی منطق سازنده کافی نیست، یک واکنش خاص را به سرور خود تحویل میدهید: سرور رویدادها را دریافت میکند و با دستوراتی در قالب Telegram Bot API پاسخ میدهد، در حالی که GetMyBot حملونقل، تحویل و تمام Telegram را بر عهده میگیرد.
این چیست
واکنشها در GetMyBot به صورت بصری ساخته میشوند: ماشه ← شرایط ← اقدامات. منطق پیچیده یا غیراستاندارد — پایگاه داده خودتان، محاسبات، ارتباط با سیستمهای خارجی، ML، سناریوهای شاخهای — بیان آن در سازنده دشوار است. پردازشگر خارجی این محدودیت را برمیدارد: بکاند اختصاصی خود را متصل میکنید و پردازش واکنشهای کامل را به آن میسپارید.
سرویس خارجی رویدادهایی از GetMyBot دریافت میکند (ماشه فعال شد، کاربر متن فرستاد، دکمهای فشار داد) و در پاسخ به بات دستور میدهد چه چیزی بفرستد. GetMyBot دستورات را با توکن بات خودش اجرا میکند — در بالای آن rate-limit، تکرار، بیتکراری و گزارش مکالمه کار میکنند.
مدل کار
- GetMyBot یک WebSocket-سرور است. سرویس شما خودش به آن متصل میشود و نیازی به آدرس عمومی یا endpoint وبهوک ندارد. GetMyBot اتصالات خروجی به سرویس شما برقرار نمیکند، پس سطح SSRF وجود ندارد.
- احراز هویت — با توکن یکپارچهسازی. سرویس هنگام اتصال توکن را ارائه میدهد؛ GetMyBot آن را با هش مقایسه میکند و اتصال را نگه میدارد.
- رویدادها و دستورات — در قالب Telegram Bot API. سرویس یک رویداد دریافت میکند و با آرایهای از فراخوانیهای «متد + پارامترها» پاسخ میدهد، دقیقاً مانند کار با یک بات معمولی.
- دستورات را GetMyBot با توکن خودش اجرا میکند. سرویس هرگز مستقیم با Telegram ارتباط برقرار نمیکند: دستورات اعتبارسنجی میشوند و وارد outbox داخلی GetMyBot میشوند، که از آنجا با توکن بات با rate-limit، تکرار، بیتکراری و گزارش ارسال میشوند.
یک اتصال همه مکالمات یک یکپارچهسازی را پردازش میکند — رویدادهای کاربران مختلف مالتیپلکس میشوند و با فیلد session_id از هم تمایز مییابند.
تنظیم یکپارچهسازی
- بخش یکپارچهسازیها را در منوی چپ باز کنید و روی افزودن یکپارچهسازی کلیک کنید.
- سرویس پردازشگر خارجی را انتخاب کنید و یک نام وارد کنید.
- پس از ایجاد، کارت موارد زیر را نشان میدهد:
- آدرس WebSocket — به شکل
wss://api.mybot.app/ext/ws/<integrationID>، که در آن<integrationID>UUID این یکپارچهسازی است. سرویس شما از طریق آن متصل میشود. بدون id در مسیر اتصال برقرار نمیشود. - توکن اتصال — یک بار هنگام ایجاد نشان داده میشود. آن را کپی و در مکان امنی ذخیره کنید؛ امکان مشاهده مجدد توکن وجود ندارد (فقط هش آن ذخیره میشود).
- بازصدور توکن — دکمهای که توکن جدیدی تولید میکند و فوراً توکن قدیمی را بیاعتبار میکند. پس از بازصدور، توکن را در سرویس خود بهروز کنید.
- نشانگر آنلاین — نشان میدهد آیا سرویس شما در این لحظه اتصال فعال دارد.
- آدرس WebSocket — به شکل
پارامترهای اضافی یکپارچهسازی که بر پروتکل تأثیر میگذارند:
session_ttl_seconds— زمان زندگی سشن به ثانیه (پیشفرض3600).on_unavailable_reaction_id— واکنش پشتیبان که اگر سرویس در لحظه فعالسازی آفلاین باشد راهاندازی میشود (ببینید قابلیت اطمینان).
اتصال به واکنش
پردازشگر خارجی نه به عنوان ماشه جداگانه، بلکه به عنوان اقدام متصل میشود. در ویرایشگر واکنش، اقدام انتقال به پردازشگر خارجی را اضافه کنید و یکپارچهسازی مورد نظر را انتخاب کنید.
هر ماشه موجود در GetMyBot میتواند مکالمه را باز کند — دستور، متن، فشار دکمه، پارامتر از لینک، درخواست وب ورودی، برنامهریزی. وقتی چنین ماشهای فعال میشود و به اقدام میرسد، GetMyBot یک سشن پروکسی باز میکند و رویداد session.open را به سرویس میفرستد.
اگر در آن لحظه سرویس متصل نباشد، GetMyBot واکنش پشتیبان را از تنظیمات یکپارچهسازی (on_unavailable_reaction_id) اجرا میکند. اگر واکنش پشتیبانی تعریف نشده باشد — هیچ اتفاقی نمیافتد (بیصدا، بدون خطا برای کاربر).
اتصال و احراز هویت
Endpoint: GET /ext/ws/{integrationID} روی WebSocket (wss). integrationID — UUID یکپارچهسازی نوع «پردازشگر خارجی». محدودیت اندازه فریم — 256 KiB.
احراز هویت از دو روش امکانپذیر است.
1. هدر در زمان handshake (ترجیحی). توکن را در هدر Authorization ارسال کنید:
Authorization: Bearer <token>
2. فریم auth. اگر هدر Bearer ارسال نشده، در طول 10 ثانیه پس از برقراری اتصال، اولین فریم را ارسال کنید:
{ "type": "auth", "token": "<token>" }
اگر در 10 ثانیه فریم auth نرسید — اتصال با کد 4401 بسته میشود. توکن نادرست در هر یک از روشها — نیز close با 4401.
توکن هنگام ایجاد یکپارچهسازی تولید میشود، یک بار نشان داده میشود و فقط به صورت هش (sha256) ذخیره میشود، مقایسه با constant-time انجام میشود. چرخش توکن:
POST /api/bots/{botID}/integrations/{integrationID}/rotate-token
Endpoint توکن plaintext جدید را برمیگرداند؛ توکن قدیمی فوراً از کار میافتد.
رویدادها: بات ← سرویس
هر رویداد یک فریم JSON است (EventEnvelope). فیلد type یکی از: session.open، message، callback، session.cancel، session.expired.
مجموعه کامل فیلدهای پوشش:
{
"type": "session.open",
"session_id": "string",
"bot_id": "string",
"user": {
"tg_user_id": 123456789,
"first_name": "Ivan",
"username": "ivan",
"params": { "utm": "promo" }
},
"chat": { "id": 123456789, "type": "private" },
"update": { "...": "raw Telegram Update (raw JSON)" },
"event": { "...": "normalized GetMyBot event (raw JSON)" }
}
session_id— شناسه سشن (مکالمه).bot_id— شناسه بات.user— دادههای کاربر:tg_user_id(int64)، اختیاریfirst_name،username، همچنینparams— پارامترهای کاربر (از جمله از لینک)، map کلید←مقدار.chat— چت:id(int64) وtype(مثلاً"private").update— raw Telegram Update (raw JSON). برایsession.open،message،callbackموجود است.event— رویداد نرمالشده GetMyBot (raw JSON).
محتوا بر اساس نوع متفاوت است:
session.open— ماشه فعال شد، مکالمه جدیدی باز شد. دارایupdate(raw Update) وevent(رویداد نرمالشده کامل)،user.paramsپر شده است.message— زمانی ارسال میشود که سرویس «در انتظار» (expect=text/any) باشد و کاربر پیامی فرستاده باشد. محتوا مانندsession.openاست.callback— کاربر دکمهای را که سرویس قبلاً فرستاده فشار داد.updateخام است؛ درuserفقطtg_user_idپر شده؛eventفقطcallback_dataاصلی تعریفشده توسط سرویس در دکمه را دارد:
{ "callback_data": "<مقدار اصلی تعریفشده توسط سرویس در دکمه>" }
session.cancel/session.expired— پوشش حداقلی:session_id،bot_id،user.tg_user_id،chat.id(برایcancelهمچنینchat.type). فیلدهایupdate/eventوجود ندارند. این رویدادها فقط اگر سرویس آنلاین باشد تحویل داده میشوند — در صف آفلاین قرار نمیگیرند.
دستورات: سرویس ← بات
دستور یک فریم JSON است (CommandEnvelope). فیلد type یکی از: execute، session.close، auth، ping، pong.
{
"type": "execute",
"session_id": "string",
"methods": [
{ "method": "sendMessage", "params": { "text": "سلام" } }
],
"expect": "none"
}
session_id— سشنی که دستور به آن تعلق دارد.token— فقط برایtype: "auth"(ببینید اتصال و احراز هویت).methods— آرایهای از اشیاء{ "method": "<نام متد Telegram Bot API>", "params": { ... } }. نام متد دقیقاً مانند Telegram Bot API (مثلاًsendMessage)،params— شیء پارامترهای آن متد.expect— آیا سرویس منتظر پاسخ کاربر است:"none"،"text"یا"any"(مقدار خالی به عنوانnoneتفسیر میشود).session.close— مکالمه را صریحاً ببندید.
دستورات مستقیماً به Telegram نمیروند: GetMyBot آنها را اعتبارسنجی میکند و در outbox خود قرار میدهد، از آنجا با توکن بات (با rate-limit، تکرار، بیتکراری، گزارش) ارسال میشوند.
نحوه پردازش execute
دستور execute کاملاً رها میشود اگر: session_id خالی باشد؛ سشن پیدا نشود یا در وضعیت open نباشد؛ سشن به یکپارچهسازی دیگری تعلق داشته باشد؛ سشن منقضی شده باشد.
سپس:
- Rate-limit: تا 60
executeدر دقیقه برای هر سشن (پنجره لغزان). بیش از این حد — رها میشود. - تا 30 متد در یک
execute؛ اضافیها بیصدا رها میشوند. - برای هر متد، whitelist بررسی میشود (ببینید متدهای مجاز) — متد خارج از لیست رد میشود.
- Chat-guard: اگر در
paramsفیلدchat_idیاfrom_chat_idبا مقداری غیر از0و غیر ازchat_idسشن وجود داشته باشد — کل متد رد میشود (نمیتوان به چت دیگری فرستاد). میتوانchat_idرا اصلاً ذکر نکرد: GetMyBot به اجبار چت سشن را تعیین میکند. - دکمههای inline با
callback_dataبه صورت خودکار توکنیزه میشوند (نمای داخلیx:<token>)؛ عمر دکمه = تا انقضای سشن. دکمههایurl/webapp/switch_inlineدست نخورده میمانند.
متدهای مجاز
سرویس به بات دستور میدهد، بنابراین مجموعه متدها با whitelist محدود شده — فقط ارسال و کار با پیامهای مکالمه فعلی. متدهای خارج از لیست بیصدا نادیده گرفته میشوند (این خطا نیست).
- ارسال:
sendMessage،sendPhoto،sendDocument،sendVideo،sendAudio،sendMediaGroup،sendAnimation،sendVoice،sendLocation،sendChatAction؛ - ویرایش و حذف:
editMessageText،editMessageCaption،editMessageReplyMarkup،deleteMessage؛ - پاسخ به فشار:
answerCallbackQuery؛ - فوروارد و کپی:
forwardMessage،copyMessage؛ - پین:
pinChatMessage،unpinChatMessage.
متدهای سطح حساب (setWebhook، getUpdates، logOut، close، setMyCommands و غیره) مجاز نیستند.
انتظار و چرخه زندگی سشن
پس از هر execute، سرنوشت سشن به expect و وجود یا عدم وجود دکمههای inline با callback_data در دستور بستگی دارد:
expect=textیاany— پیام بعدی کاربر با رویدادmessageبه سرویس فوروارد میشود.expect=noneو در دستور هیچ دکمه inline با callback نبود — سشن به طور خودکار بسته میشود. این یک پیام «پایانی» است.expect=none، اما دکمههای callback وجود دارند — سشن باز میماند: فشارها تا زمانی که توکن دکمهها زنده هستند (تا TTL) دریافت میشوند.
مهم: expect بر دریافت فشار دکمهها تأثیر نمیگذارد. فشار دکمههای توکنیزه مستقل از مقدار expect دریافت میشوند — تا زمانی که سشن و توکن دکمه زنده هستند. expect فقط کنترل میکند که آیا سرویس منتظر پاسخ متنی/دلخواه است.
مرزهای مکالمه
زمینه مکالمه دقیقاً تا زمانی که سشن باز است زندگی میکند:
- پاسخ متنی با انتظار فعال (
expect=text/any) — به سرویس با رویدادmessageمیرود، نه اینکه واکنشهای معمولی بات را راهاندازی کند. - فشار دکمه توکنیزه — با رویداد
callbackباcallback_dataاصلی به سرویس میرود. GetMyBot همیشه خودش فشار را تأیید میکند (answerCallbackQuery)؛ تعلق فشار (بات + کاربر + چت سشن) بررسی میشود. دکمه سشن را نمیبندد. /cancel(همچنین/cancel@botو «لغو») با سشن خارجی فعال — سشن بسته میشود، به سرویسsession.cancelفرستاده میشود، به کاربر «لغو شد.» ارسال میشود.- یک مکالمه برای هر کاربر. باز کردن سشن جدید، سشن باز قبلی این کاربر را جابجا میکند — برای آن
session.cancelفرستاده میشود. - انقضای TTL. توسط تایمر، سشن
expiredعلامتگذاری میشود و (اگر سرویس آنلاین باشد)session.expiredبه سرویس فرستاده میشود.
محدودیتها و تایماوتها
- اندازه فریم: 256 KiB.
- TTL سشن: پیشفرض 3600 ثانیه (با پارامتر
session_ttl_secondsیکپارچهسازی قابل تنظیم است). - تکرار دستورات: 60
executeدر دقیقه برای هر سشن (پنجره لغزان). - متدها در یک
execute: تا 30 (اضافیها رها میشوند). - سشنهای باز برای هر یکپارچهسازی: تا 1000.
- صف آفلاین: تا 100 رویداد برای هر سشن.
- Heartbeat:
pingهر 30 ثانیه؛ تایماوت عدم فعالیت — 60 ثانیه. - تایماوت فریم auth: 10 ثانیه.
قابلیت اطمینان (heartbeat، آفلاین، صف، fallback)
- Heartbeat. سرور هر 30 ثانیه یک فریم
{"type":"ping"}میفرستد. اگر از کلاینت بیش از 60 ثانیه فعالیتی نبود — اتصال بسته میشود. کلاینت میتواندping/pongخودش را برای نگه داشتن فعالیت ارسال کند. قطع اتصال مکالمات را از بین نمیبرد: سشنها تا TTL یا اتصال مجدد در پایگاه داده زنده میمانند. - اتصال مجدد — در طرف سرویس. اگر اتصال قطع شد، سرویس شما باید دوباره متصل شود. سشنهای باز در پایگاه داده تا انقضای TTL از ریاستارتها جان سالم به در میبرند.
- Fallback هنگام آفلاین در شروع. اگر در لحظه فعالسازی واکنش سرویس متصل نباشد — واکنش پشتیبان از تنظیمات یکپارچهسازی (
on_unavailable_reaction_id) اجرا میشود. اگر تعریف نشده باشد — هیچ اتفاقی نمیافتد (بیصدا). - صف آفلاین. رویدادهای
message/callbackکه به دلیل آفلاین بودن تحویل داده نشدهاند، در صف آفلاین (تا 100 رویداد، FIFO، تا انقضای سشن ذخیره میشود) قرار میگیرند و هنگام اتصال مجدد ارسال میشوند. رویدادهایsession.open/session.cancel/session.expiredدر صف قرار نمیگیرند. - ضمانت تحویل — at-most-once. در صورت پر شدن یا منقضی شدن صف، رویدادها رها میشوند. منطق را طوری طراحی کنید که از دست دادن یک رویداد خاص سناریو را خراب نکند.
نشانگر آنلاین
برای بررسی اینکه سرویس اتصال فعال دارد یا خیر، از endpoint استفاده کنید:
GET /api/bots/{botID}/integrations/{integrationID}/status
پاسخ:
{ "online": true }
همین نشانگر روی کارت یکپارچهسازی در پنل در دسترس است. معادل آن در MCP — ابزار get_integration_status.
امنیت
GetMyBot دستورات سرویس خارجی را با توکن خودش اجرا میکند، بنابراین حفاظت سختگیرانه است.
- بدون سطح SSRF. GetMyBot به عنوان سرور WebSocket عمل میکند و خودش اتصالات خروجی به سرویس برقرار نمیکند — این سرویس است که به GetMyBot متصل میشود. URL کنترلشده از خارج که پلتفرم به آن مراجعه کند، وجود ندارد.
- توکن به صورت هش ذخیره میشود (sha256)، مقایسه با constant-time، چرخش پشتیبانی میشود.
- ایزولهسازی مستأجر. دستور به یکپارچهسازی خودش سخت وابسته است؛ سشن — به بات + کاربر + چت. رویدادهای باتهای دیگران وارد سوکت شما نمیشوند.
- Whitelist متدها +
chat_idاجباری اجازه نمیدهند بات به یک فرستنده انبوه پیام به چتهای دلخواه تبدیل شود. - توکن بات به بیرون منتقل نمیشود — سرویس هرگز مستقیم با Telegram ارتباط برقرار نمیکند.
- ماسکزدن اسرار. توکن یکپارچهسازی و مقادیر حساس در گزارشها و لاگها پنهان میشوند.
نمونهها
یک پردازشگر حداقلی: با باز شدن مکالمه، پیامی ارسال میکند و سشن را میبندد (expect: "none"). شناسه یکپارچهسازی و توکن را جایگزین کنید. آدرس حتماً باید شامل <integrationID> در مسیر باشد.
Node.js
import WebSocket from "ws";
const URL = `wss://api.mybot.app/ext/ws/${process.env.MYBOT_INTEGRATION_ID}`;
const ws = new WebSocket(URL, {
headers: { Authorization: `Bearer ${process.env.MYBOT_TOKEN}` },
});
ws.on("message", (raw) => {
const ev = JSON.parse(raw);
if (ev.type === "session.open") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{ method: "sendMessage", params: { text: "سلام از پردازشگر خارجی!" } }],
}));
}
});
Python
import json, os, asyncio, websockets
async def main():
url = f"wss://api.mybot.app/ext/ws/{os.environ['MYBOT_INTEGRATION_ID']}"
headers = {"Authorization": f"Bearer {os.environ['MYBOT_TOKEN']}"}
async with websockets.connect(url, additional_headers=headers) as ws:
async for raw in ws:
ev = json.loads(raw)
if ev["type"] == "session.open":
await ws.send(json.dumps({
"type": "execute",
"session_id": ev["session_id"],
"expect": "none",
"methods": [
{"method": "sendMessage", "params": {"text": "سلام از پردازشگر خارجی!"}}
],
}))
asyncio.run(main())
دکمه Inline و پردازش callback
برای دریافت فشار دکمه، دکمهای با callback_data ارسال کنید (GetMyBot آن را به صورت خودکار توکنیزه میکند). با expect: "none" همراه دکمه، سشن باز میماند تا زمانی که توکن دکمه زنده است — فشار با رویداد callback میرسد که در آن event.callback_data برابر مقدار اصلی است. نیازی به تأیید فشار (answerCallbackQuery) نیست — GetMyBot این کار را خودش انجام میدهد.
if (ev.type === "session.open") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{
method: "sendMessage",
params: {
text: "دکمه را فشار دهید",
reply_markup: { inline_keyboard: [[{ text: "بزن بریم", callback_data: "go" }]] },
},
}],
}));
} else if (ev.type === "callback" && ev.event.callback_data === "go") {
ws.send(JSON.stringify({
type: "execute",
session_id: ev.session_id,
expect: "none",
methods: [{ method: "sendMessage", params: { text: "دکمه فشار داده شد!" } }],
}));
}
مراحل بعدی
- یکپارچهسازیها — مرور کلی سرویسهای قابل اتصال.
- واکنشها — نحوه ساخت ماشهها، شرایط و اقدامات.
- درخواستهای وب و webhookها — روش سادهتری برای فراخوانی URL خارجی بدون مکالمه.