ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2. Pusher 세팅(채팅)
    Laravel/Chat 2021. 1. 16. 22:12
    반응형
    SMALL

    # What?

    웹소켓 라이브러리

     

    # How?

    * 주의사항 : laravel 8.29 미만에서 현재 에러남. 8.29 이상으로 세팅필요

    1. 라이브러리 설치

    npm install --save laravel-echo pusher-js
    composer require pusher/pusher-php-server
    composer require beyondcode/laravel-websockets
    php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="migrations"
    php artisan migrate
    php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
    php artisan websockets:serve

    @ bootstrap.js

    import Echo from 'laravel-echo';
    
    window.Pusher = require('pusher-js');
    
    window.Echo = new Echo({
        broadcaster: 'pusher',
        key: process.env.MIX_PUSHER_APP_KEY,
        cluster: process.env.MIX_PUSHER_APP_CLUSTER,
        forceTLS: true
    });

     

    2. Pusher 사이트 회원가입 후 환경세팅

    dashboard.pusher.com/accounts/sign_in

     

    Sign in - Pusher

     

    dashboard.pusher.com

    @ .env

    ...
    BROADCAST_DRIVER=pusher
    ...
    
    PUSHER_APP_ID=
    PUSHER_APP_KEY=
    PUSHER_APP_SECRET=
    PUSHER_APP_CLUSTER=

    @ app.php

        'providers' => [
    		...
            App\Providers\BroadcastServiceProvider::class,
     		...
    
        ],

    * 메시지 안간다하면
    시도 1) broadcasting.php의 useTLS false로 바꾼다음에 캐쉬 삭제 및 서버 재시작 후 테스트해보기, app.js forceTLS는 true여야함(useTLS 상관 없을지도?) 

    시도 2) 그래도 해결 안된다면 pusher 버전이 잘못된걸수도 있음(옛날 프로젝트거 복붙해서 쓰다보니 업데이트 안됐다던지) -> 그런거라면 위 커맨드 참고해서 관련패키지들 npm install이랑 composer intall 다시 해보기

    시도 3) 혹시 아래값에 값을 직접 넣은거 아닌지 확인, 맞다면 아래와 똑같이 다시 변경 후 캐시 지우기

    MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
    MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
    php artisan optimize:clear

    시도 4) vapor로 배포한거라면 .env값 변경 후 vapor deploy production까지 해야 변경값이 적용됨

     

    시도 5) pusher 키값을 여러 프로젝트에서 쓰고 있다면 맞물려서 오류가 나는걸수도 있으므로 해당 프로젝트용만을 위한 pusher 키값을 따로 만들기(로컬이랑, 실배포용도 따로 쓰기) 

     

    시도 6) Inertia.js를 쓰고 있다면 채팅방 접속할 때 Link나 Inertia.get으로 링크 이동할 시 pusher event는 읽으나, 메세지 읽어온 후 리렌더링이 안되는 경우가 있음. 그냥 일반 a링크로 바꾸기

    3. 이벤트 생성 및 채널 설정

    php artisan make:event MessageCreated

    1) 이벤트 클래스에 ShouldBoradcast 상속

    => 이렇게만 만들어도 broadcast 시 MessageCreated라는 이름으로 알아서 이벤트 발생함. 그러면 이걸 view단에서 listen하고 있다가 어떤 작업을 하는거.

     

    2) 받을 데이터 및 처리과정 설정

     

    3) 상황에 따라 자기 자신에게는 broadcast하지 않도록 설정

    => 이미 메세지 생성 시 메세지 목록에 메시지 push 작업을 해놓은 경우 => MessageCreated를 listen하고 있다가 message를 push하는 처리를 해놨으므로 같은 메세지가 두 번 푸시됨. => 따라서 자기 자신에게는 MessageCreated broadcast가 전달되지 않도록 해야함.

     

    4) 어떤 채널 이용할건지 설정

     

    @ MessageCreated.php

    class MessageCreated implements ShouldBroadcast
    {
        use Dispatchable, InteractsWithSockets, SerializesModels;
    
        public $message;
    
        /**
         * Create a new event instance.
         *
         * @return void
         */
        public function __construct(Message $message)
        {
            $this->message = $message;
    
            $this->dontBroadcastToCurrentUser();
        }
    
        /**
         * Get the channels the event should broadcast on.
         *
         * @return \Illuminate\Broadcasting\Channel|array
         */
        public function broadcastOn()
        {
            return new PrivateChannel('messages.'.$this->message->chat_id);
        }
    }

     

    @ MessageController.php

    class MessageController extends ApiController
    {
        public function store(Request $request)
        {
            $request->validate([
                "receiver_id" => "required|integer",
                "chat_id" => "required|integer",
                "body" => "nullable|string|max:500",
                "read" => "nullable|boolean" // 읽거나 이미 같은 채팅방을 보고 있다면 read 가 true로 넘어올거.
            ]);
    
            $chat = Chat::find($request->chat_id);
    
            if(!$chat)
                return $this->respondNotFound();
    
            if(!$chat->users->contains($request->receiver_id) || !$chat->users->contains(auth()->id()))
                return $this->respondForbidden();
    
            $message = Message::create([
                "sender_id" => auth()->id(),
                "chat_id" => $chat->id,
                "receiver_id" => $request->receiver_id,
                "body" => $request->body
            ]);
    
            event(new MessageCreated($message));
    
            return $this->respondCreated(MessageResource::make($message));
        }
    }
    

    - private일 경우 channels.php에 권한 설정하기(채팅 그룹원끼리만 소통하도록 세팅)

     

    @ channels.php

    Broadcast::channel('chats.{chat}', function ($user, \App\Models\Chat $chat) {
        return $chat->users->contains($user->id);
    });

    @ Chats/Show.vue

    <template>
        <div class="area-chat">
        
            <div class="chat-container">
                <div class="chat-inner">
                    <div class="wrap">
                        <div class="date-wrap">
                            <span class="date">{{chat.month}}월 {{chat.date}}일</span>
                        </div>
    
                        <message :message="message" v-for="message in messages.data" :key="message.id" />
                    </div>
                </div>
            </div>
    
            <input-chat @change="(data) => {form.body = data; store()}" />
    
    
        </div>
    </template>
    <script>
    import {Link} from '@inertiajs/inertia-vue';
    import Pagination from "../../Components/Pagination";
    import InputChat from '../../Components/Form/InputChat';
    import Message from "../../Components/Message";
    import Avatar from "../../Components/Avatar";
    
    export default {
        components: {Avatar, Message, Link, Pagination, InputChat},
        data(){
            return {
                owner: this.$page.props.owner.data,
                chat: this.$page.props.chat.data,
                messages: this.$page.props.messages,
                form: this.$inertia.form({
                    chat_id: this.$page.props.chat.data.id,
                    body: "",
                })
            }
        },
    
        methods:{
            store(){
                this.form.post("/messages", {
                    preserveScroll: true,
                    preserveState: true,
                    replace:true,
                    onSuccess: (page) => {
    
                    }
                });
            },
    
            // 채널 연결(메시지 생성 시 웹소켓으로 받아내기)
            setChannel() {
                if(Object.keys(window.Echo.connector.channels).length === 0 || !window.Echo.connector.channels[`private-chats.${this.chat.id}`]){ // 채널 중복 접속 방지
                    window.Echo.private(`chats.${this.chat.id}`)
                        .listen("MessageCreated", (e) => {
                            this.messages.data.push(e.message);
    
                            this.$emit("created");
                        });
                }
    
            },
        },
    
        mounted() {
            this.setChannel();
        }
    }
    </script>

     

    * 안될경우

    1. .env파일에 PUSHER 설정값이 반영 안되어있을 수 있음 (.env에 MIX_PUSHER_APP_KEY에다 값을 직접 넣어놧으면 실서버에서 반영 제대로 안돼 아래 형태로 되어있는지 확인필요 -> 실서버뿐만 아니라 로컬도)

    -> 그래도 안되는듯? 걍 bootstrap.js에서 .env가 prod인지 dev인지 확인해서 분기처리 후 키값 가져가게 해야할듯

    MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
    MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
    php artisan optimize:clear
    php artisan view:clear
    npm run watch

    2. bootstrap.js에서 proccess.env값을 제대로 못 받아올 수 있음

    npm install laravel-mix@latest --save-dev
    LIST

    'Laravel > Chat' 카테고리의 다른 글

    3. View단 세팅  (0) 2021.01.17
    1. 기본 스키마 세팅  (0) 2021.01.15

    댓글

Designed by Tistory.