laravel+GatewayWorker completes IM instant messaging and file transfer (Chapter 5: front end code development)

Function introduction

This topic will take you hand-in-hand to build the instant messaging function of imitating a letter and complete the mutual transmission of documents

Application scenario

Practical application scenarios of this topic:

  1. Chat customer service: instant messaging, real-time message transmission, sending text, voice messages and files to each other;
  2. Small scale online auction;
  3. Real time video barrage;
  4. Internet of things;
  5. And other functions related to real-time messages;

Special chapters

  1. Server configuration;
  2. Explanation of business logic;
  3. Back end instant messaging code development and configuration item explanation
  4. Server debugging error;
  5. Front end code development;
  6. Function display;

Chapter 4: front end code development

1, Required page

  • User login page (registration page: log in when the user exists, and register automatically when the user cannot exist)
  • User friend list page
  • Add friends page
  • User one-to-one chat page

2, Business logic

  • User login → enter the friends list page → add friends → Click to select friends → enter the friends one-to-one chat page → start chat → End chat;

3, Front end coding

I believe everyone's front-end ability is good. I don't need to rewrite css style here. I'll focus on demonstrating the function implementation for you

  • The code is below, smelly and long. I guess you don't like it either; Let me briefly talk about the front-end logic;
  1. The user enters the page and directly connects to the socket. When connected to the back end, the client will be returned to you_ id the unique id of the user's temporary device
  2. The user takes the temporary device id given by the back end and sends ajax to the back end to bind our user id and temporary device id;
  3. After binding, you can send messages
  4. The string sending interface directly sends the content and recipient id to the back end, and the back end calls the GatewayWorker to send messages by itself;
  5. Sending a file is the same as sending a text message. The essence of a file is actually a pile of strings. The front end converts the file into a pile of strings and sends them to the back end. When the string is forwarded to you, the back end will restore it to a file directly after the client receives base64;
  • Front end core code
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="{{asset('layui-v2.6.8/layui/css/layui.css')}}">
    <script src="{{asset('js/jquery.min.js')}}"></script>
    <script src="{{asset('layui-v2.6.8/layui/layui.js')}}"></script>
    <link rel="stylesheet" href="{{asset('css/im_chat.css')}}">
    <title>Chat page</title>
</head>
<body>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
    <legend>Chat page</legend>
</fieldset>

<main>
    <section class="message_box">
        {{--
        <div class="left">
            <img class="header_img" src="{{asset('images/linux.png')}}" alt="">
            <div class="content_left">
                <p>Opposite party</p>
            </div>
        </div>
        <div class="right">
            <div class="content_right">
                <p>We, we</p>
            </div>
            <img class="header_img" src="{{asset('images/php.png')}}" alt="">
        </div>
        <div class="left">
            <img class="header_img" src="{{asset('images/linux.png')}}" alt="">
            <div class="content_left">
                <img src="{{asset('images/demo1.jpg')}}" alt="">
            </div>
        </div>
        <div class="right">
            <div class="content_right">
                <img src="{{asset('images/demo1.jpg')}}" alt="">
            </div>
            <img class="header_img" src="{{asset('images/php.png')}}" alt="">
        </div>
        --}}

    </section>


</main>

<section class="import_box">
    <div id="string">
        <a href="javascript:;" onclick="transitionToggle()">+</a>
        <textarea name="" id="string_msg_val" cols="30" rows="5" required placeholder="Please enter chat content"></textarea>
        <button type="button" onclick="sendStringMsg()">send out</button>
    </div>

    <div id="file_box" style="display: none">
        <a href="javascript:;"  onclick="transitionToggle()">←</a>
        <input type="file" id="file_input" onchange="filechange('file_input')">
        <input type="hidden" id="base64_value">
        <button type="button" onclick="sendImgMsg()">send out</button>
    </div>

</section>

</body>
<script>
    /**
     * Establish a websocket connection with GatewayWorker, and change the domain name and port to your actual domain name and port,
     * The port is the Gateway port, i.e. start_ The port specified by Gateway.php.
     * start_gateway.php You need to specify the websocket protocol in, like this
     * $gateway = new Gateway(websocket://0.0.0.0:8282);
     */
    ws = new WebSocket("ws://im.liutong.pro:8282 "); / / the port here should be the same as $gateway = new gateway (") in. \ app\GatewayWorker\Applications\YourApp\start_gateway.php websocket://0.0.0.0:8282 "); keep consistent ports;

    //Check whether websocket is linked
    ws.onopen = function () {
        console.log("Connection succeeded");
    };

    // Close websocket
    ws.onclose = function () {
        console.log("Connection closed...");
    };

    // The onmessage here will be triggered when the server actively pushes a message
    ws.onmessage = function(e){
        // Convert json data into js objects
        var data = eval("("+e.data+")");
        var type = data.type || '';
        console.log(type);
        switch(type){
            // The init type message returned in Events.php sends the client_id to the background for uid binding
            case 'init'://Listening initialization
                console.log(data);
                // Use jquery to initiate an ajax request and send the client_id to the backend for uid binding
                binding(data.client_id);
                break;
            case 'binding_success'://Listen for binding success information
                console.log(data);
                break;
            case 'string'://Listen for received text messages
                console.log(data);
                if(data.addresser_id != "{{$friend_id}}"){
                    return false;
                }
                //Renders text messages to the view
                let _html = "<div class=\"left\">\n" +
                "            <img class=\"header_img\" src=\"{{asset('images/linux.png')}}\" alt=\"\">\n" +
                "            <div class=\"content_left\">\n" +
                "                <p>"+ data.msg +"</p>\n" +
                "            </div>\n" +
                "        </div>";
                $('.message_box').append(_html);//Append a new text message to the template
                break;
            case 'img'://Monitor received picture information
                console.log(data);
                if(data.addresser_id != "{{$friend_id}}"){
                    return false;
                }
                let _img_html = "<div class=\"left\">\n" +
                    "            <img class=\"header_img\" src=\"{{asset('images/linux.png')}}\" alt=\"\">\n" +
                    "            <div class=\"content_left\">\n" +
                    "                <img src=" + data.msg + ">\n" +
                    "            </div>\n" +
                    "        </div>";
                $('.message_box').append(_img_html);//Append a new text message to the template
                break;
            default :
                alert(e.data);
        }
    };

    //Toggle input box
    function transitionToggle(){
        $('#string').toggle();
        $('#file_box').toggle();
    }

    //Bind uid
    function binding(client_id){
        //Binding business logic
        $.ajax({
            type : "POST", //Submission method
            url : "{{route('im.binding')}}",//route
            data : {
                '_token':'{{csrf_token()}}'//laravel method to prevent ajax POST request from reporting 419 error
                ,'user_id' : "{{session('user')['id']}}"
                ,'client_id' :client_id
            },//Data is transmitted in Json format
            success : function(result) {//The returned data is processed according to the result
                var data = JSON.parse(result);//Receive the JSON data returned by the server and parse it
                if (data.success) {
                    console.log('Binding results:' + data.msg);
                } else {
                    alert('Binding failed');
                }
            }
        });

    }

    //Send text message
    function sendStringMsg() {
        let msg = $('#string_msg_val').val();
        if(!msg){
            layer.msg('Please enter the content', {time: 5000, icon: 2});
            return false;
        }
        $.ajax({
            type : "POST", //Submission method
            url : "{{route('im.sendMessage')}}",//route
            data : {
                '_token':'{{csrf_token()}}'//laravel method to prevent ajax POST request from reporting 419 error
                ,'recipients_id' :"{{$friend_id}}"//Friend id
                ,'type':'string'
                ,'msg':msg
            },//Data is transmitted in Json format
            success : function(result) {//The returned data is processed according to the result
                var data = JSON.parse(result);//Receive the JSON data returned by the server and parse it
                if (data.success) {
                    console.log('Text sending result:' + data.msg);
                    //Display the sent information in html
                    let _string = " <div class=\"right\">\n" +
                        "            <div class=\"content_right\">\n" +
                        "                <p>"+ data.msg +"</p>\n" +
                        "            </div>\n" +
                        "            <img class=\"header_img\" src=\"{{asset('images/php.png')}}\" alt=\"\">\n" +
                        "        </div>";
                    $('.message_box').append(_string);//Append a new text message to the template
                    $('#string_msg_val').val(' '); / / clear the input box
                } else {
                    layer.msg('fail in send', {time: 5000, icon: 2});
                }
            }
        });
    }

    //Send picture file
    function sendImgMsg(){
        let msg = $('#base64_value').val(); / / get base64 and send it to the php interface
        $.ajax({
            type : "POST", //Submission method
            url : "{{route('im.sendMessage')}}",//route
            data : {
                '_token':'{{csrf_token()}}'//laravel method to prevent ajax POST request from reporting 419 error
                ,'recipients_id' :"{{$friend_id}}"//Friend id
                ,'type':'img'
                ,'msg':msg
            },//Data is transmitted in Json format
            success : function(result) {//The returned data is processed according to the result
                var data = JSON.parse(result);//Receive the JSON data returned by the server and parse it
                if (data.success) {
                    console.log('Text sending result:' + data.msg);
                    //Display the sent information in html
                    let _string = "<div class=\"right\">\n" +
                        "            <div class=\"content_right\">\n" +
                        "                <img src="+data.msg+" alt=\"\">\n" +
                        "            </div>\n" +
                        "            <img class=\"header_img\" src=\"{{asset('images/php.png')}}\" alt=\"\">\n" +
                        "        </div>";
                    $('.message_box').append(_string);//Append a new text message to the template
                    $('#string_msg_val').val(' '); / / clear the input box
                } else {
                    layer.msg('fail in send', {time: 5000, icon: 2});
                }
            }
        });
    }

    /**
     * Get file base64
     */
    function filechange(_id_name) {
        var selectFile = document.getElementById(_id_name);
        var filePath = selectFile.value;//File path
        var fileName = selectFile.files[0].name;//Uploaded file name
        var file = selectFile.files[0];//Uploaded files
        var extn = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();//file extension
        //Get base64string file
        if (window.FileReader) {
            var reader = new FileReader();
            reader.readAsDataURL(file);
            //Event triggered after listening for file reading
            reader.onloadend = function (e) {
                var base64String=e.target.result;
                $('#base64_value').val(base64String);
            };
        }
    }
</script>

</html>
  • Route file routes\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');
});


//Load login page
Route::get('login','LoginController@index');
//Login + registration processing
Route::post('login/loginOperation','LoginController@loginOperation')->name('login.loginOperation');


//Routes requiring middleware verification
Route::middleware(['im_auth'])->group(function () {
    //Log out
    Route::post('login/loginOut','LoginController@loginOut')->name('login.loginOut');

    //Load im user friend list
    Route::get('im/indexList', 'ImController@indexList')->name('im.indexList');
    //Add friends
    Route::post('im/addFriends', 'ImController@addFriends')->name('im.addFriends');
    //Delete friends
    Route::post('im/deleteFriends/{friend_lists_id}', 'ImController@deleteFriends')->name('im.deleteFriends');
    //Load im user chat page
    Route::get('im/chat/{friend_id}', 'ImController@chat')->name('im.chat');

    //Bind user
    Route::post('im/binding', 'ImController@binding')->name('im.binding');
    //send message
    Route::post('im/sendMessage', 'ImController@sendMessage')->name('im.sendMessage');
});
  • Backend business logic controller
<?php

namespace App\Http\Controllers;

// Auto load class
require_once __DIR__ .'/../../GatewayWorker/vendor/autoload.php';//Introduce the automatic loading class on the GatewayWorker component on the absolute path, otherwise the error of "GatewayClient\Gateway" will not be found, or you can install "GatewayClient\Gateway" in the project directory composer

use App\FriendList;
use App\ImUser;
use GatewayClient\Gateway;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

/**
 * Im controller
 * Class ImController
 * @package App\Http\Controllers
 */
class ImController extends Controller
{
    /**
     * Friends list
     */
    public function indexList()
    {
        $user = session('user');
        $data = FriendList::where('user_id', $user['id'])->paginate(20);
        return view('im.indexList', compact('data'));
    }

    /**
     * Add friends
     * @param Request $request
     */
    public function addFriends(Request $request)
    {
        $friend_id = ImUser::where('tel', $request->tel)->value('id');
        $user = session('user');
        if ($friend_id) {
            //Opposite id exists
            $is_friend = FriendList::where([
                ['user_id', $user['id']],
                ['friend_id', $friend_id],
            ])->exists();
            if(!$is_friend){
                FriendList::create([
                    'user_id'=>$user['id'],
                    'friend_id'=>$friend_id,
                ]);
                FriendList::create([
                    'user_id'=>$friend_id,
                    'friend_id'=>$user['id'],
                ]);
                return redirect()->route('im.indexList');
            }
        }
        dd('Wrong mobile phone number');
    }

    /**
     * Delete friends
     * @param $id
     */
    public function deleteFriends($friend_lists_id){
        $friendList = FriendList::where('id',$friend_lists_id)->first();

        DB::beginTransaction();
        try{
            $del_1 = FriendList::where([
                ['user_id',$friendList['user_id']],
                ['friend_id',$friendList['friend_id']]
            ])->delete();
            $del_2 = FriendList::where([
                ['user_id',$friendList['friend_id']],
                ['friend_id',$friendList['user_id']]
            ])->delete();
            DB::commit();
        }catch (\Exception $exception){
            DB::rollBack();
            dd('Deletion failed:' . $exception->getMessage());
        }

        if($del_1 && $del_2){
            return redirect()->back();
        }
        dd('Deletion failed');
    }

    /**
     * Chat page
     * @param Request $request
     * @param $friend_id Friend id
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function chat(Request $request, $friend_id)
    {
        return view('im.chat',compact('friend_id'));
    }

    /**
     * Bind user
     * @param Request $request
     */
    public function binding(Request $request){
        $client_id = $request->client_id;//The connection id assigned to us by GatewayWorker
        $user = session('user');
        $uid  = $user['id'];//My primary key id in our database IM user table
        Gateway::bindUid($client_id,$uid);
        $message = [
            'type' => 'binding_success',
            'msg' => 'Binding succeeded'
        ];
        Gateway::$registerAddress = '127.0.0.1:1238';
        Gateway::sendToUid($uid, json_encode($message));//Send data to any uid's web page
        $message['code'] = 200;
        $message['success'] = 1;//1: Success, 0: failure
        return json_encode($message);
    }

    /**
     * send message
     * @param Request $request->recipients_id Recipient ID, the value of the friend_id field in our friend_lists friend table
     * @param Request $request->type Message type: string: text message, img: picture
     * @param Request $request->msg information content
     */
    public function sendMessage(Request $request){
        $post = $request->all();
        $user = session('user');
        $user_id = $user['id'];
        $message = [
            'type' => $request->type,
            'addresser_id' => $user_id,//Sender id
            'recipients_id' => $post['recipients_id'],//Recipient id
            'msg' => $post['msg'],
        ];
        //Detect whether it is a file. If yes, give the file a randomly generated file id to facilitate front-end operation
        switch ($request->type){
            case 'img':
                $message['file_id'] = time() . rand(10,99);//File id
                break;
            default:
                $message['file_id'] = '';
                break;
        }
        Gateway::$registerAddress = '127.0.0.1:1238';
        Gateway::sendToUid($post['recipients_id'], json_encode($message));//Send data to sender's uid website page
        $message['code'] = 200;
        $message['success'] = 1;//1: Success, 0: failure
        return json_encode($message);
    }
}

Note: if the back-end logic controller reports an error and says, "the gateway client \ gateway error cannot be found", remember to use require_once at the top of the php code to introduce it;
If it is imported or cannot be found: there must be no composer required worker / gatewayclient in the project root directory \ app\GatewayWorker. Just install the directory;

I posted the code to gitee
https://gitee.com/liutong199309/php-laravel–gateway-worker

Tags: PHP Front-end Laravel socket websocket

Posted on Fri, 03 Dec 2021 22:25:11 -0500 by fleabay