ارتباط بلادرنگ برای هاست اشتراکی
فارسی | English
NoSocket یک لایه مستقل از فریمورک برای انتقال رویدادها است. هدف آن این است که وبسایتهای مستقر روی هاست اشتراکی، cPanel، وردپرس یا هاست معمولی PHP بتوانند تجربهای نزدیک به realtime داشته باشند؛ بدون نیاز به WebSocket، پردازش دائمی، Node.js، Redis، Message Broker، VPS یا daemon.
$nosocket->emit('orders', 'order.created', ['id' => 123]);import { createNoSocket } from "/assets/js/nosocket.js";
const NoSocket = createNoSocket({
namespace: `shop:user-${currentUser.id}`,
tokenProvider: ({ channels }) => fetchToken(channels),
onResync: ({ channel }) => refreshSnapshot(channel),
});
NoSocket.subscribe("orders");
NoSocket.on("order.created", (order) => console.log(order.id));
NoSocket.start();سرور رویدادها را برای مدت محدود داخل یک جدول ایندکسشده نگه میدارد. مرورگر بهجای پرسیدن «چیز جدیدی هست؟»، آخرین شناسه دریافتشده هر channel را بهعنوان cursor ارسال میکند:
POST /nosocket/poll
Content-Type: application/json
{
"subscriptions": {
"orders": { "cursor": 1523, "replay": "live" },
"notifications": { "cursor": null, "replay": "retained" }
}
}سرور فقط رویدادهای جدیدتر از cursor هر channel را برمیگرداند. اگر رویدادهای لازم بهدلیل پایان TTL حذف شده باشند، SDK رویداد nosocket.resync_required را صادر میکند تا برنامه snapshot معتبر را دوباره دریافت کند.
اگر کاربر چند تب از یک سایت باز کند، NoSocket با Web Locks API یا یک lease کوتاهمدت در مرورگر یک تب را بهعنوان leader انتخاب میکند:
- فقط تب leader سرور را poll میکند.
- تبهای follower مستقیما به سرور درخواست نمیفرستند.
- leader رویدادها را با
BroadcastChannelبرای بقیه تبها پخش میکند. - اگر
BroadcastChannelموجود نباشد، از storage event استفاده میشود. - اگر leader بسته شود، بعد از پایان lease یک تب دیگر جای آن را میگیرد.
- اگر leader مخفی شود و تب قابلمشاهده دیگری وجود داشته باشد، leadership منتقل میشود.
مثلا با ۱۰ تب باز و فاصله عادی ۳۰ ثانیه:
| روش | تعداد درخواست در دقیقه |
|---|---|
| polling معمولی برای هر تب | ۲۰ |
| NoSocket با یک leader | ۲ |
فاصله پیشفرض درخواستها با توجه به وضعیت تغییر میکند:
| وضعیت | فاصله درخواست |
|---|---|
| حالت عادی | ۳۰ ثانیه |
| کاربر اخیرا فعال بوده | ۱۰ ثانیه |
| رویداد جدید در حال رسیدن است | ۲ ثانیه برای ۳۰ ثانیه |
| پاسخ HTTP 403 | حداقل ۶۰ ثانیه توقف |
| پاسخ HTTP 429 | حداقل ۱۲۰ ثانیه توقف |
| پاسخ HTTP 504 | حداقل ۳۰۰ ثانیه توقف |
خطاهای تکراری باعث exponential backoff میشوند و فاصله انتظار حداکثر به پنج دقیقه میرسد. هدف این است که هاست اشتراکی با درخواستهای بیرویه تحت فشار قرار نگیرد.
| بخش | کاربرد |
|---|---|
nosocket/nosocket |
هسته PHP خام |
@nosocket/client |
SDK مرورگر |
nosocket/laravel |
Service Provider، Facade، route و migration لاراول |
nosocket/symfony |
controller و تنظیمات سرویس Symfony |
nosocket/codeigniter4 |
سرویس و controller برای CodeIgniter 4 |
packages/wordpress/nosocket |
افزونه وردپرس |
درایورهای دیتابیس فعلی:
- MySQL
- MariaDB
- PostgreSQL
- SQLite
composer require nosocket/nosocket
mysql -u app -p app_db < database/mysql/schema.sqlمتغیرهای محیطی زیر را تنظیم کنید:
NOSOCKET_DSN=mysql:host=localhost;dbname=app;charset=utf8mb4
NOSOCKET_DB_USER=app
NOSOCKET_DB_PASSWORD=secret
NOSOCKET_SECRET=a-random-secret-with-at-least-32-charactersیک route را به public/poll.php متصل کنید. سپس بعد از احراز هویت و بررسی دسترسی کاربر، token محدود به channelهای مجاز صادر کنید و فایل assets/js/nosocket.js را در مرورگر بارگذاری کنید.
راهنماهای تکمیلی:
- نصب
- معماری
- مرجع API
- وردپرس
- لاراول
- مقایسه با WebSocket، SSE، Pusher و Ably
- راهنمای مهاجرت نسخه ۰.۲
- مانیتورینگ و diagnostics
برای ثبت چند رویداد در یک مرحله از emitBatch() استفاده کنید. در PDO این عملیات داخل transaction انجام میشود:
$nosocket->emitBatch([
['channel' => 'orders', 'event' => 'order.updated', 'payload' => ['id' => 123]],
['channel' => 'dashboard', 'event' => 'metrics.updated', 'payload' => ['online' => 7]],
]);cleanup زمانبندیشده با cron همچنان روش اصلی است. در هاستهایی که cron قابل اتکا ندارند، میتوان cleanup احتمالاتی را بهصورت opt-in فعال کرد. همچنین صفحه diagnostics محافظتشده و metrics hook بدون وابستگی برای اتصال به ابزارهای مانیتورینگ وجود دارد.
افزونه وردپرس یک action ساده در اختیار شما میگذارد:
do_action('nosocket_emit', 'orders', 'order.created', ['id' => 123], 3600);برای WooCommerce، اعلانها، فرمها، دیدگاهها و داشبورد مدیریت میتوان از همین الگو استفاده کرد.
use NoSocket\Laravel\Facades\NoSocket;
NoSocket::emit('orders', 'order.created', ['id' => $order->id]);- channelها باید قبل از صدور token در برنامه شما authorize شوند.
- tokenها با HMAC-SHA256 امضا میشوند و شامل subject، زمان انقضا و nonce هستند.
- endpoint صدور token باید احراز هویت و محافظت CSRF داشته باشد.
- استفاده از HTTPS الزامی است.
- tokenها باید کوتاهعمر و محدود به کمترین channel موردنیاز باشند.
- برای production از
tokenProviderاستفاده کنید تا leader بتواند مجوز union کانالهای تبها را تازهسازی کند. - namespace را برای هر کاربر خصوصی کنید؛ مثلا
shop:user-42. - payloadها پیش از emit باید اعتبارسنجی شوند.
- limiter دیتابیسی داخلی کمککننده است، اما در صورت امکان جایگزین rate limiting لبه شبکه نیست.
- NoSocket جایگزین کمتاخیر WebSocket برای چت پرترافیک یا ویرایش مشارکتی نیست.
- بازیابی آفلاین فقط تا زمانی ممکن است که رویدادها با TTL تعیینشده هنوز حذف نشده باشند.
- اگر storage مرورگر غیرفعال باشد، انتخاب leader بین تبها تضمین نمیشود و ممکن است هر تب جداگانه poll کند.
- writeهای اصلی برنامه باید همچنان از routeهای معمولی و معتبر انجام شوند؛ NoSocket برای همگامسازی رابط کاربری است.
composer test
NOSOCKET_TEST_DSN=sqlite:/tmp/nosocket.sqlite composer test:integration
npm test
npm run test:e2e
php benchmarks/run.phpمدل درخواست موجود در benchmark برای ۱۰۰ کاربر با ۱۰ تب باز و فاصله عادی ۳۰ ثانیه:
| روش | درخواست در دقیقه | کاهش |
|---|---|---|
| polling جداگانه برای هر تب | ۲۰۰۰ | - |
| polling با leader در NoSocket | ۲۰۰ | ۹۰٪ |
این اعداد مدل محاسباتی هستند، نه ادعای ظرفیت یک هاست مشخص. پیش از انتشار روی محیط واقعی باید با محدودیتهای همان سرویس میزبانی تست انجام شود.
پروژه با مجوز MIT منتشر میشود. فایل LICENSE را ببینید.