GatewayWorker+Laravel demo

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

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

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

跟Laravel結合使用的優勢:jquery

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

2,能夠盡情使用Laravel提供的各類便利工具處理數據和業務邏輯;git

 

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

本地windows使用步驟:web

1,啓動GatewayWorker,雙擊 start_for_win.batajax

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

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>

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

 本文連接 http://www.javashuo.com/article/p-vpjlgdej-dx.html

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

相關文章
相關標籤/搜索