ساخت websocket با  laravel websocket

سلام دوستان امروز قراره بفهمیم پطور میتونیم یه websocket راه اندازی کنیم .همونطور که میدونید سرویس های زیادی برای ارائه وب سوکت ها به ما هستن از بهترین اونا میشه : سرویس pusherسرویس Socket IOسرویس alby و ......اشاره کرد .نکته : اگه اینارو میدونی و فقط کد ها و سیستم پیاده سازیش تو laravel رو همین آموزشو برو پایین .*** کد ها در آخر آموزش درج شده ***اما همونطور که میدونید هیچکس محض رضای خدا موش نمیگیره و تمامی این سرویس ها پولی هستن ، یا فقط چند ماه یا حتی چند دخواست در آن ها رایگان هست .برای نمونه میشه به pusher اشاره کرد .خب اینجا بازم قدرت های بی حد مرز لاراول قراره شگفت زده تون کنه . پکیج laravel-websocket از کمپانی beyondco.de رو داریم ککه خیلی به کار میاد .ولی قبل از آموزش بریم ی ذره از websocket و سیستم های REAL - TIME اطلاعات به دست بیارم که بدونیم قراره چه کنیم . خب بریم که یه سیستم request => response رو با یه real time مقایسه کنیم.تو دخواست های HTTP هی درخواست ارسال میشه و بازخورد دریافت میشه به ازای هر درخواست یک بازخورد هست .اما اگر دبه سمت راست تصویر که مربوط به در خواست های REAL -TIME هست توجه کنید یک بار درخواست ارسال میشه و در پشت درخواست HTTP شما میتونید درخواست های همزمان (Real Time ) رو شاهد باشد .پردازش درخواست های Real time رو میتونید در این آموزش مشاهده کنید .خب حالا که یه توضیح مخاصر مفیدی رو داشتیم بریم به سمت پیاده سازی در کد ها . نسخه پکیج ها و لاراول نسخه php م : "php": "^8.0.2"لاراول : "laravel/framework": "^9.19"لاراول وب سوکت :"beyondcode/laravel-websockets": "^1.13"نسخه node م : v18.12.1نسخه npm م : V8.17.0البته این مشخصات برای کسایی که با DOCKER و غیره کار میکنند . برای آموزش laravel-websocket با نسخه laravel 9 و 7 و 6 و5 میتونید آموزشش رو از اینجا ببینید .خب دیگه بیشتر از این طولش نیدم .در مرحله اول laravel رو نصب کنید .laravel new LaravelWebsocket?? خب اگه لاراول رو به صورت Global نصب نکردید هم میتونید از اینجا آموزشش رو ببینید .در مرحله بعد باید پکیج وب سوکت را در پروژه/اپلیکیشن لاراولی خود نصب کنید .composer require beyondcode/laravel-websocketsحالا وقتشه migrations های پکیج رو از vendor فراخوانی کنید .php artisan vendor:publish --provider=&quotBeyondCode\LaravelWebSockets\WebSocketsServiceProvider&quot --tag=&quotmigrations&quotخب اگه روی ویندوز دارید برنامه می نویسید یکی از شبیه ساز های سرور استفاده کنید .یا از wampserverیا از xamppserverحالا یه DataBase به اسم دلخواه خود ایجاد کنید .و با دستور زیر Table هارو در phpmyadmin یا ... ایجاد کنید .php artisan migrate خب یکی دیگه از سرویس های provide شده رو publish کنید .حالا configre از websocket رو هم با دستور زیر فراخوانی/publish کنید .php artisan vendor:publish --provider=&quotBeyondCode\LaravelWebSockets\WebSocketsServiceProvider&quot --tag=&quotconfig&quotخداروشکر دیگه کارمون با آرتیزان و کامند لاین تموم شد.(البته فعلا ....?)حالا .... بریم سراغ کانفیگ WebSocket .فایل .env رو باز کنید ..env BROADCAST_DRIVER=log ..................... PUSHER_APP_ID= PUSHER_APP_KEY= PUSHER_APP_SECRET= PUSHER_HOST= PUSHER_PORT=443 PUSHER_SCHEME=https PUSHER_APP_CLUSTER=mt1 ..............................فایل یبه صورت پیش فرض این شکلی هست .مراحل زیر رو برای تغییر مقادیر فایل انجام دهید .در خط BROADCAST_DRIVE مقدار log را به pusher تغییر دهید .در خط PUSHER_APP_ID مقدار abcds را جایگزاری کنید .در خط PUSHER_APP_KEY مقدار a1b2c3d4s5 را جایگزاری کنید . در خط PUSHER_APP_SECRET مقدار qwertyasddf11123 را جایگزاری کنید .در خط PUSHER_HOST مقدار localhost را جایگذاری کنید .در خط PUSHER_POST مقدار 6001 را جایگذاری کنید .در خط PUSHER_SCHEME مقدار http را جایگذاری کنید .در خط PUSHER_APP_CLUSTER مقدار mt1 را جایگذاری کنید .خب بریم بگیم که یه توضیح ریزیم درباره مقداردهی های بالا بدیمدرباره ی برودکست درایور که داریم بهش سیستم pusher رو معرفی میکنیم چون در اصل هم در بک و هم در فرانت داریم از سرویس های pusher استفاده میکنیم چون هم کامله هم بهترین interface رو داره .و مقادیر APP ID , KEY , SECRET رو چون داریم سرور websocket رو خودمون میسازیم هر اسمی که بدیم به تمامی سرویس داده میشه .هاست هم که داریم میگیم برو از سروری که خودمون درست کردیم استفاده کن ، در واقع برای اتصال pusher به server های خودشه .و سر آخر PUSHER_SCHEME رو هم چون SSL ندارم از https به http تغییر میدهیم .ای بابا PUSHER_APP_CLUSTER رو فراموش کردیم ، البته چندان هم مهم نیست برای اتصال به سرور های آسیایی ، با ... استفاده میشه و چون خودمون هاستیم لازم نیست . پس فقط میزاریم باشه .در نتیجه باید یه همچین چیزی داشته باشیم..env BROADCAST_DRIVER=pusher ..................... PUSHER_APP_ID=abcds PUSHER_APP_KEY=a1b2c3d4s5 PUSHER_APP_SECRET=a1b2c3d4s5 PUSHER_HOST=localhost PUSHER_PORT=6001 PUSHER_SCHEME=https PUSHER_APP_CLUSTER=mt1 .............................. خب بریم سراغ یه دستور دیگه ابا command line و artisan :composer require pusher/pusher-php-serverیه نکته مهم تو سایت خود beyoncode کد زیر رو میگه ولی بخاطر اینکه هی داره به روز میشه ما ازش استفاده نمیکنیم :composer require pusher/pusher-php-server &quot~3.0&quot /C^ یه خب یه سَری بزنیم به فایل websocket که کانفیگش کنیم .config/websocket.php .......... 'pusher' => [ 'driver' => 'pusher', 'key' => env('PUSHER_APP_KEY'), 'secret' => env('PUSHER_APP_SECRET'), 'app_id' => env('PUSHER_APP_ID'), 'options' => [ 'host' => env('PUSHER_HOST') ?: 'api-'.env('PUSHER_APP_CLUSTER', 'mt1').'.pusher.com', 'port' => env('PUSHER_PORT', 443), 'scheme' => env('PUSHER_SCHEME', 'https'), 'encrypted' => true, 'useTLS' => env('PUSHER_SCHEME', 'https') === 'https', ], 'client_options' => [ // Guzzle client options: https://docs.guzzlephp.org/en/stable/request-options.html ], ], .........خب نیازی به توضیح نیست ولی ما موظفیم دیگه تمامی خط ها ، همه data ها رو از environment یا .env اطلاعاتی که دادیم رو جایگذاری میکنیم .البته یه ارورر اینجا قراره داشته باشیم . تو option تو host یه شرط گذاشته که وصل شه به سایتای pusher برا همین ما برش میداریم ............... 'options' => [ 'host' => env('PUSHER_HOST') , ..............و بعد از مرحله قبل باید بریم سراغ app.php تو پوشه config کد زیرو از حالت کامنت دربیارید .config/app.php App\Providers\BroadcastServiceProvider::class,خب دیگه کار راه اندازی بک تموم شد .یکی از ترمینال هارو باز کنید و دستور زیر رو اجرا کنید .// terminal 1 php artisan serv و با باز کردن مرورگر و رفتن به آدرس http://localhost:8000/ ،باید شاهد عکس زیر باشید .یک ترمینال دیگر را باز کنید و دستور زیر را اجرا کنید .php artisan websocket:servو در ترمینال شاهد این باشید .خب حالا وارد لینک زیر شوید ، تبریک میگم شما در داشبورد websocket خود هستید .LARAVEL WEBSOCKET با زدن دکمه connect باید شاهد به عمل آمدن نمودار و event و ... باشیم .dashboard laravel websocketترمینال وب سوکت ساخت websocket application با لاراولخب حالا با دستور زیر یک event بسازید با اسم دلخواه اما در نظر داشته باشید که قراره براتون ثبت و ارسال دیتا رو تو websocket انجام بده . البته بهتر فقط بگیم "ارسال دیتا" چون ثبت اون مقوله ی گسترده ای داره و حتی منم بلد نیستم ?.حالا ن در اون حد که بلد نباشم ولی به چند روش انجام میشه یکیش مثلا listener ها هست ، حالا از بحث دور نشیم.پس event رو بسازید .php artisan make:event SendMessو الان event ساخته شده رو باز کنید باید مشابه (دقیقا کد زیر باشد ) .app/events/ChatMess.php <?php namespace App\Events; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class ChatMess { use Dispatchable, InteractsWithSockets, SerializesModels; /** * Create a new event instance. * * @return void */ public function __construct() { // } /** * Get the channels the event should broadcast on. * * @return \Illuminate\Broadcasting\Channel|array */ public function broadcastOn() { return new PrivateChannel('channel-name'); } }این event شماست که به 3 بخش کلی تقسیم میشه و باید چند بخش هم خودمون اضافه کنیم .بخش اول constructor: در اینجا شما باید تمام مقادیر که میخواهید وارد websocket شن رو مدیریت کنین.بخش دوم variable : شما باید در بالا ترین سطح ممکن که در اینجا پایین use s و بعد تعریف کلاس هست متغیر هاتونو تعریف کنید .بخش سوم broadcastingOn : پاس دادن متغیر در چنل ها رو ، این طابع مشخص میشود .بهتر بگیم آدرس channel هاست . اما این فقط یه event باید قشنگ چکش کاریش کنیم ، و باز هم در مرحله اول در قسمت تعریف کلاس شما باید implements کنید از ShouldBroadcast .در مرحله دوم پارامتر ها و variable ها رو تعریف کنید که اینجا دوتا داریم یک $Message و دو $Username که بهتره فل حال public باشن . در مرحله سوم متغیر هارو مقدار دهی میکنیم در کانستراکتور .در مرحله چهارم PrivateChannel رو به Channel تغییر میدیم .خب تا اینجا فقط چکش کاریش بود حالا یه سری قسمت ها رو باید اضافه کرد .قسمت اول function BroadcastAs هستش که نام event یا بهتر نام جایگزین event را برمیگرداند .قسمت دوم function BroadCastWith هستش که مقدار هارو تو websocket برمیگردونه . که میشه کد زیر :<?php namespace App\Events; use http\Message; use Illuminate\Broadcasting\Channel; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PresenceChannel; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class ChatMessage implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public $Message ,$username; public function __construct($m ,$u) { $this->Message = $m; $this->username = $u; } public function broadcastOn() { return new Channel('my-channel-name'); } public function broadcastAs() { return &quotCHM&quot } public function broadcastWith() { return [ 'username' => $this->username, 'message' => $this->Message ]; } }خب کارمون با php فل حال تمومه .# بریم سراغ jsلازمه که همینجا پوشه وکل node_module رو نصب کنیم .و بعد باید pusher-js و laravel-echo رو با دستورات زیر نصب کنید .terminal :// کد های ترمینال npm install npm install -s laravel-echo pusher-js بعد این بریم تو پوشه resource و بعد تو js و bootstrap.js رو باز کنید .حاجی این bootstrap.js اون بوت استرپ "فریمورک css "نیستا .....خداروشکر اینجا کدای اتصال به websocket هست فقط باید از کامنت درش بیاریم .import _ from 'lodash'; window._ = _; /** * We'll load the axios HTTP library which allows us to easily issue requests * to our Laravel back-end. This library automatically handles sending the * CSRF token as a header based on the value of the &quotXSRF&quot token cookie. */ import axios from 'axios'; window.axios = axios; window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; /** * Echo exposes an expressive API for subscribing to channels and listening * for events that are broadcast by Laravel. Echo and event broadcasting * allows your team to easily build robust real-time web applications. */ import Echo from 'laravel-echo'; import Pusher from 'pusher-js'; window.Pusher = Pusher; window.Echo = new Echo({ broadcaster: 'pusher', key: import.meta.env.VITE_PUSHER_APP_KEY, cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1', wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`, wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80, wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443, forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https', enabledTransports: ['ws', 'wss'], });از خط 21 به پایین مد نظر ماست که باید یه توضیح ریزی بدم .اول pusher-js و laravel-echo رو import میکینم , دوباره باید تمام مقدارایی که تو config/websocket.php دادیم رو هم اینجا بدیم ولی خی چون لاراول از سیستم environment استفاده میکنه فقط همون دفعه اول تو فایل .env نیاز بود و دیگه نیازی نیست .البته لازم به ذکر که تا اینجا یه erorr داریم که مربوط میشه به خط 30 اگه یادتون باشه گفتیم چون داریم از سیستم آماده pusher استفاده میکنیم فقط با یه سری تغییرات تو configre سرور نیازی به تغییر یا ساخت یه رابط جدید نیست پس تغییرات زیادی تو داده نشده و چون این کد برای استفاده مستقیم خوده سرویس pusher برنامه نویساش برای هاست نیاز دونستن برای سرعت بالا از تغییر لوکیشن استفاده کنن. پس خط 30 رو به کد زیر تغییر بدید . wsHost: import.meta.env.VITE_PUSHER_HOSTو cluster هم به دردمون نمیخوره و چون امکان ایجاد خطا رو میده برش میداریم و با کد زیر جا به جاش میکنیم.cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER,حالا به resource/js/app.js برید و یه متغیر از نو const ایجاد کنید و یک چنل رو با Echo تو آماده سازی کنید .const channel = Echo.channel('my-channel-name');حالا listener بزاریدش ChatMess یا CHM ، این به این معنی که هر وقت رو اون channel ها با این event یا این رویداد اتفاق افتاد ، هر واکنشی براش تعریف کنیم رو انجام میده .پس :channel.listen('CHM',(e)=>{ console.log(e.username , e.message); });چنل رو که بالا مقدار دهی کردیم هیچ ، بعد میایم منتظرش میزاریم تا event که تو Php نوشتیم اجرا بشه و بعد مقادیر مورد نظر رو log میگیریم . و برای اینکه کد خوانا تر باشه app.js رو یه ذره تغییرش میدیمimport './bootstrap'; let MessagesBox = document.getElementById(&quotMessages&quot); const channel = Echo.channel('my-channel-name'); channel.listen('CHM',(e)=>{ MessagesBox += `<li>${e.username} : ${e.message}</li>` }); //تفاوتش با بالا تو اینه که با هر رویدادی یه ال ای تو المنتی با کلاس مسیج اضافه میشه.و از اونجایی که ما js مینویسم ن node بهتر که یه view ایجاد کنید یا مثل من از welcome.blage.php استفاده کنید .برید تو resource/view/welcome.blade.php همه چیو پاک کنید و فقط کد زیرو اجرا بگیرید :<!doctype html> <html lang=&quoten&quot> <head> <meta charset=&quotUTF-8&quot> <meta name=&quotviewport&quot content=&quotwidth=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0&quot> <meta http-equiv=&quotX-UA-Compatible&quot content=&quotie=edge&quot> <title>Document</title> </head> <body> @vite('resource/css/app.css') <ul id=&quotMessages&quot> </ul> @vite('resource/js/app.js') </body> </html>و برای اجرای کد های js از دستور زیر در خط فرمان استفاده کنید .npm run devفقط لازمه تو routes/web.php یه route ایجاد کرد و event رو فراخونی کرد .Route::get('/event', function () { broadcast(new \App\Events\ChatMessage('hi',&quotmahdi&quot)); });تمومه .ممنون میشم نظراتتون رو برام بنویسید .