GatewayWorker+Laravel demo


GatewayWorker 結合 Laravel 使用的簡單案例,重點是在Laravel中使用GatewayClient發送消息

主要流程:GatewayWorker主要負責推送消息給客戶端但不接受客戶端數據,Laravel主要負責接受客戶端數據並處理業務邏輯,然后使用GatewayClient推送數據,

示意圖拿一個官方圖片哈 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.html

跟Laravel結合使用的優點:

1,當 GatewayWorker服務運行時,修改了Laravel業務代碼,直接推送業務相關代碼到服務器上即可,不用重啟GatewayWorker服務;

2,可以盡情使用Laravel提供的各種便利工具處理數據和業務邏輯;

 

整個項目壓縮文件太大不便上傳,接下來直接貼代碼咯,

本地windows使用步驟:

1,啟動GatewayWorker,雙擊 start_for_win.bat

2,新建一個虛擬域名路徑指定到該項目public目錄

3,開兩個瀏覽器頁面就能互發消息了,如下面兩個效果圖,

效果圖:

項目結構:

ChatServer目錄下的4個start_*.php文件是直接復制的官方demo https://github.com/walkor/workerman-chat/tree/master/Applications/Chat

 composer.json 的 require 部分

    "require": {
        "php": ">=7.0.0",
        "fideloper/proxy": "~3.3",
        "laravel/framework": "5.5.*",
        "laravel/tinker": "~1.0",
        "workerman/gateway-worker" : ">=3.0.0",
        "workerman/gatewayclient": "^3.0"
    },

 

start_for_win.bat  本地windows啟動腳本 

php app\ChatServer\start_register.php app\ChatServer\start_web.php app\ChatServer\start_gateway.php app\ChatServer\start_businessworker.php
pause

 start.php  服務器上的啟動腳本

<?php
/**
 * run with command 
 * php start.php start
 */

ini_set('display_errors', 'on');
use Workerman\Worker;

if(strpos(strtolower(PHP_OS), 'win') === 0)
{
    exit("start.php not support windows, please use start_for_win.bat\n");
}

// 檢查擴展
if(!extension_loaded('pcntl'))
{
    exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

if(!extension_loaded('posix'))
{
    exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n");
}

// 標記是全局啟動
define('GLOBAL_START', 1);

require_once __DIR__ . '/vendor/autoload.php';

// 加載所有application/*/start.php,以便啟動所有服務
foreach(glob(__DIR__.'/app/ChatServer/start*.php') as $start_file)
{
    require_once $start_file;
}
// 運行所有服務
Worker::runAll();

Events.php  參考 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.html

<?php

/**
 * 用於檢測業務代碼死循環或者長時間阻塞等問題
 * 如果發現業務卡死,可以將下面declare打開(去掉//注釋),並執行php start.php reload
 * 然后觀察一段時間workerman.log看是否有process_timeout異常
 */
//declare(ticks=1);

use \GatewayWorker\Lib\Gateway;
class Events
{
    // 當有客戶端連接時,將client_id返回,讓mvc框架判斷當前uid並執行綁定
    public static function onConnect($client_id)
    {
        Gateway::sendToClient($client_id, json_encode(array(
            'type'      => 'init',
            'client_id' => $client_id
        )));
    }

    // GatewayWorker建議不做任何業務邏輯,onMessage留空即可
    public static function onMessage($client_id, $message)
    {

    }
}
IndexController.php  發送消息用的控制器 參考 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.html
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use GatewayClient\Gateway;

class IndexController extends Controller
{
    public function __construct()
    {
        Gateway::$registerAddress = '127.0.0.1:1236';
    }

    /**
     * web客戶端
     * @param string $uid
     * @param string $to_uid
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function client()
    {
        return view('client');
    }

    /**
     * 綁定uid
     * @return mixed
     */
    public function bind()
    {
        // 假設用戶已經登錄,用戶uid和群組id在session中
        $uid = request('uid');
        $client_id = request('client_id');

        $res = request()->all();
        $res['type'] = 'bind';
        $res['time'] = date('H:i:s');
        // client_id與uid綁定
        Gateway::bindUid($client_id, $uid);
        Gateway::sendToUid($uid, json_encode($res));
        return response()->json($res);
    }

    /**
     * 發送消息
     * @return mixed
     */
    public function send()
    {
        $uid = request('uid');
        $to_uid = request('to_uid');
        $res = request()->all();
        $res['type'] = 'send';
        $res['time'] = date('H:i:s');
        // 向任意uid的網站頁面發送數據
        Gateway::sendToUid($uid, json_encode($res));
        Gateway::sendToUid($to_uid, json_encode($res));
        return response()->json($res);
    }
}

web.php  路由 

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::match(['post', 'get'], 'index/index/{uid}/{to_uid}', 'IndexController@client');

Route::match(['post', 'get'], 'index/client/{uid}/{to_uid}', 'IndexController@client');

Route::match(['post', 'get'], 'index/bind', 'IndexController@bind');

Route::match(['post', 'get'], 'index/send', 'IndexController@send');

client.blade.php   web客戶端視圖 

<html>
<head>
    <title>{{ request('uid') }} => {{ request('to_uid') }}</title>
    <link href="https://cdn.bootcss.com/normalize/8.0.0/normalize.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script>
    <script src="https://cdn.bootcss.com/json5/0.5.1/json5.js"></script>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .chat-main {
            width: 600px;
            margin: 30px auto;
            box-shadow: 0 0 1px gray;
            border: 1px solid gray;
            line-height: 1.5em;
        }

        .chat-header {
            border-bottom: 1px solid gray;
            padding: 5px 15px;
        }

        .chat-log {
            height: 200px;
            overflow-y: auto;
            border-bottom: 1px solid gray;
            padding: 5px 15px;
        }

        .chat-log dl {
            margin: 15px 0;
        }

        .chat-log dl dd {
            display: inline-block;
            border: 1px solid gray;
            padding: 5px 15px;
            border-radius: 10px;
            border-top-left-radius: 0;
        }

        .chat-log dl.me dd {
            border-radius: 10px;
            border-top-right-radius: 0;
        }

        .chat-log dl.me {
            text-align: right;
        }

        .chat-log dl.me dd {
            text-align: left;
        }

        .user-link {
            float: right;
        }

        .user-link a {
            margin-left: 5px;
        }

        .hide {
            display: none;
        }

        .inline-block {
            display: inline-block;
        }

        .btn {
            text-align: right;
            padding: 5px 15px 15px;
        }

        #btn-send {
            display: inline-block;
            background: white;
            border: 1px solid gray;
            line-height: 2em;
            padding: 0 2em;
            outline: none;
        }

        #btn-send:focus {
            background: white;
            border-color: green;
        }

        #message {
            display: block;
            width: 570px;
            height: 100px;
            margin: 15px auto 0;
            border: 1px solid gray;
            overflow-x: hidden;
            overflow-y: auto;
            resize: none;
            outline: none;
            padding: 10px;
        }

        #message:focus {
            border-color: green;
        }

        .chat-body > .tpl {
            display: none;
        }
    </style>
</head>
<body>

<div class="hide">
    bind<input type="text" id="bind" value="{{ url('index/bind') }}"><br>
    send<input type="text" id="send" value="{{ url('index/send') }}"><br>
</div>

<div class="chat-main">
    <div class="chat-header">
        <div class="chat-title inline-block">
            {{ request('uid') }} => {{ request('to_uid') }}
        </div>
        <div class="user-link inline-block">
            <span class="inline-block">模擬用戶</span>
            <a class="inline-block" href="{{ url('index/index',['uid'=>1111,'to_uid'=>2222]) }}">1111</a>
            <a class="inline-block" href="{{ url('index/index',['uid'=>2222,'to_uid'=>1111]) }}" target="_blank">2222</a>
        </div>
    </div>
    <div class="chat-body">
        <div class="chat-log">

        </div>
        <dl class="tpl">
            <dt>1111(12:00:00)</dt>
            <dd>aaaabbbbbb</dd>
        </dl>
    </div>
    <div class="chat-footer">
        <form action="" id="form">
            <div class="hide">
                cliend_id<input type="text" name="client_id" id="client_id" value="{{ request('uid') }}"><br>
                uid<input type="text" name="uid" id="uid" value="{{ request('uid') }}"><br>
                to_uid<input type="text" name="to_uid" value="{{ request('to_uid') }}"><br>
            </div>
            <textarea name="message" id="message" cols="30" rows="10"></textarea>
            <div class="btn">
                <button type="button" id="btn-send">發 送</button>
            </div>
        </form>
    </div>
</div>


<script>

    /**
     * 與GatewayWorker建立websocket連接,域名和端口改為你實際的域名端口,
     * 其中端口為Gateway端口,即start_gateway.php指定的端口。
     * start_gateway.php 中需要指定websocket協議,像這樣
     * $gateway = new Gateway(websocket://0.0.0.0:7272);
     */
    ws = new WebSocket("ws://127.0.0.1:7272");
    // 服務端主動推送消息時會觸發這里的onmessage
    ws.onmessage = function (e) {
        // json數據轉換成js對象
        var data = JSON5.parse(e.data);
        var type = data.type || '';
        switch (type) {
            // Events.php中返回的init類型的消息,將client_id發給后台進行uid綁定
            case 'init':
                $('#client_id').val(data.client_id);
                // 利用jquery發起ajax請求,將client_id發給后端進行uid綁定
                $.get($('#bind').val(), $('#form').serialize(), function (res) {
                    console.log('bind', res);
                }, 'json');
                break;
            case 'send':
                var $tpl = $('.chat-body>.tpl').clone().show();

                if (data.uid == $('#uid').val()) {
                    $tpl.find('dt').html('(' + data.time + ') ' + data.uid);
                    $tpl.addClass('me')
                } else {
                    $tpl.find('dt').html(data.uid + ' (' + data.time + ')');
                }

                $tpl.find('dd').html(data.message.replace(/\n/gim, '<br>'));

                $('.chat-log').append($tpl);

                scrollBottom();
                break;
            // 當mvc框架調用GatewayClient發消息時直接alert出來
            default:
                console.log('default', e.data);
        }
    };

    $('#form').submit(function (e) {
        return false;
    });

    var isScrollBottom = true;

    function scrollBottom(){
        if (isScrollBottom) {
            $('.chat-log').scrollTop($('.chat-log')[0].scrollHeight);
        }
    }

    $('#btn-send').click(function (e) {
        if ($.trim($('#message').val())) {
            $.get($('#send').val(), $('#form').serialize(), function (res) {
                console.log('send', res);
                $('#message').val('');
                scrollBottom();
            }, 'json');
        }
    });

    $('.chat-log').scroll(function (e) {
        var outerHeight = $(this).outerHeight();
        var scrollTop = $(this).scrollTop();
        var scrollHeight = $(this)[0].scrollHeight;
        if (outerHeight + scrollTop >= scrollHeight - 15) {
            isScrollBottom = true;
        } else {
            isScrollBottom = false;
        }
    })
</script>

</body>
</html>

==============================================

 本文鏈接 https://www.cnblogs.com/stumpx/p/9156850.html

==============================================


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM