Laravel and Websockets for Real Time Application | All you need to know

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey there sm you see a lot of web apps today have some sort of real-time features integrated with them for example when you're chatting with someone in a messaging app you can see whether they're typing or not or whether they're online or not or even when you're using a collaborative app like google docs you could see the cursor positions of your peers and the text they have added to the document in real time and now the big question is what is the voodoo magic that powers these real-time features well to answer this question let's first consider our options we could get this to work using http let's use a chart app as an example let's say we have a person a here and another person b on the right and our app server sitting in the middle now a wants to send a message to b so a go ahead and type in something in the messenger app and now practically speaking on b screen b should see the status of a as typing and now one of the many ways to get this to work in http is for a to send a request to the server that would update a state of the current conversation record between a and b in the database and now in order for b to get the latest status update of the current conversation b needs to send in a http request to the server once every few seconds to get the latest update on a conversation otherwise there's no other way for b to check if a is typing or not this method used by b is called polling and it is far from being efficient why well because http is rather slow for real-time communication depending on the location of the app server and also the associated logic in the api endpoint a http request could take up to a few hundred milliseconds or even a few seconds in some cases this delay is certainly not suitable for a real-time app secondly http request is rather heavy every http request contains a header and also a body and other than a request body the http request also contains cookies and also other metadata about the request and the same goes with the http response sent back by the server in the realtime app there'll be a lot of messages coming back and forth between the client and also the server if we're using http to facilitate the real-time communication someone's got to pay for the bandwidth overhead associated with these http requests and trust me it won't be cheap so what's a better solution then to correct a real-time app in contrast to http and this is exactly where websockets comes into the picture we needed something that's fast that's lightweight and supported by the browser and websocket takes all of these boxes but before we go on any further let's first understand what is websocket well websocket is another way for computers to talk to each other and just like http we can use websocket to send and receive data from a web server however the main difference between websocket and http is that in websocket the connection between a client and a server is persisted and maintained while in http the connection ends as soon as the server sends back a http response now the persisted connection in web socket gives it a huge advantage in building real-time app because now if the client or the server wants to send each other a message they don't need to start a new connection but instead they can just send the message through the existing connection there is no need to re-establish the connection and go through the authentication processes again we only need to do it for one time when we first establish the connection and that is the reason on why websocket is much faster than http when transmitting messages now there are two common patterns when building app with web sockets the first one is what we call the pub sub pattern or publisher subscriber pattern in a pub sub pattern there's always one publisher and a lot of subscribers the server is usually the publisher and there'll be a lot of clients subscribed to this publisher when the server wants to send out or publish a message the message will be sent out to all of the subscribers this is a one-way communication method where the server can only send out data and the client can only receive you can see the pub sub patents in a lot of financial app where they are streaming real-time financial data on a price chart or a candlestick chart the pub sub pattern can also be used to stream live video data where all the clients will receive streaming data from the camera on the server so if you want to build a video streaming platform like twitch.tv or a monitoring service like a cctv system for your home you might want to consider pub sub when designing your app the second common pattern is something called rpc which stands for remote procedure code in contrast to the pub sub pattern which can only send data in one way rpc is a two-way communication protocol and it is very similar to http a set the fact that we're using websocket and a connection between the client and server is maintained so here's how it works first of all the client will establish a connection with the server once the connection is opened and persisted the client will send a request through the connection to the server the server will receive the request and process the request by running some logic on a server side and send back a reply to the client this is very much similar to http request and response where the client and server are exchanging data the request in rpc could contain a body where it contains all the data needed by the server to run the process on the server side and similarly the reply sent back by the server could also contains a body to be used by the client later on once the client received a reply the client could go ahead and read the body of the reply and proceed to do some other processing and if needed the client could send another request to the server through the websocket connection and the process repeats itself and by looking at how rpc works we can kind of understand why is it called remote procedure code procedure is another name for functions and here we're really executing a remote functions on the server by sending out a request to the server and the server will go ahead and send back the result of the function in the form of reply and as i mentioned just now rpc is a two-way communication protocol the client can send data to the server through request and the server can send back data through reply however due to the nature of rpc the data transmitted in this websocket connection can only happen with one client only in contrast to pub sub where the data is sent out to multiple clients at the same time a typical application that uses rpc is a chart messaging app in fact in a chart app it could be a combination of rpc and pub sub working together here's one of the many strategies that you could use to build a chart app let's say we are in a chart group there's one server and four users now alice wants to send a message to her friends what alice could do is to make an rpc connection to the server and send a request to ask the server to record a message in a chat group once the server has saved the message the server would then broadcast the message to everyone else in the room using the top sub patent if someone else in the room wanted to send a message to the group then they'll make another rpc connection to the server and the process repeats isn't that neat using web sockets in your app in the right place could really make your app runs faster than usain bolt but it doesn't mean that you should use websocket for everything from now on websocket has its own overhead and it could be quite complicated to set up a proper websocket server regardless websocket is a promising technology that can really improve your user experience by bringing in real-time features to your web app alright key takeaways for this lesson websocket is a communication protocol to transmit data between computers where is commonly used in real-time applications in contrast to http websocket persists and maintains its connection with the server so the subsequent data transmission between the server and the client will be lightning fast and that makes websocket an ideal candidate to transmit data in a real-time application there are two common websocket app patents pub sub and rpc which stands for publisher subscriber and remote procedure code respectively pubsub involves one server that broadcasts messages to multiple clients it is commonly seen in financial app where there is a need to stream real-time price data rpc is very similar to http where the client will send a request and expect a reply from the server rpc can be used in messaging app that's it for now and i'll see you again in the next video hey there sm laravel makes it quite easy for us to create real-time app it has built-in support for pub sub pattern for websocket and just a quick recap the pub sub pattern is where there's one websocket server publishing data to multiple clients so in order for the pub start pattern to work we need to configure a websocket server in our laravel app and thankfully we didn't need to start from scratch laravel provided us a few options for our websocket server the first option is to use something called pusher as our websocket server pusher is essentially a subscription-based web service that will provide us our websocket server once we sign up with them it is very easy to use and laravel is fully integrated with it we just need to write the configuration in a few lines of code and that's it our websocket server will be up and running since day one but the only thing is we need to pay them for every single month they do provide us a free plan but with limitations now the second option is another web service called adley ably is a competitor of pusher and it is also a subscription-based websocket server they offered a very similar pricing compared to pusher and also fully integrated with laravel but if you are like me who has no money to pay for these services and my coffee we might want to consider some open source options where we have full control and no limitations alright the first open source alternative is laravel websockets this is a websocket server written in php provided by beyondcode and spati two of the biggest open source contributors in laravel's community laravel websocket is available as a composer package and it fits in perfectly in our app there are two other open source options larger echo server and society however they are written in node so you'll need to install nodejs before using them the other thing about node is that we couldn't run php code in these two packages that means we can extend and modify those two packages at the time when we need it so these two options might be less appealing compared to larvae websocket our final decision is very clear we'll be using larval websocket now for the client larvae provided us an official package called laravel echo which is a javascript npm package meant to be run on all the websocket subscribers we will discuss more about echo in the next few videos for now we'll be focusing on the server side alright let's dive into the code and get started right away there is quite a bit of configuration that we needed to do to get our websocket server up and running all right first of all let's install laravel web socket we'll go to a terminal and type in composer require beyond code larval websocket the installation node is in the package documentation the link is in the description once we have installed the package we'll need to publish its configuration so we'll go ahead and type in php addition vendor publish and look for laravel websocket in a list seems like number two is the one let's type number two and there you go we have just copied the migration files and the configuration files to our app and then we'll run phpr design migrate to create all the tables needed by laravel websocket alright now let's take a look at the package config file the first option here allows us to set a port to the package dashboard the package does provide us a debugging dashboard out of the box for us to see any incoming and outgoing websocket connections don't worry about it for now i'll be showing you around later on the next option here is for us to set our app's information that we want to connect with this websocket server some people might want to set up a websocket server for multiple apps in one go and this is a place for you to define all the information about your apps and this is referred to as the soil code multi-tenancy architecture and the next option app provider is simply a helper class for us to resolve the correct app for our tenants you can pass in your custom provider class if you have a much more complicated logic allowed origins is where we defined all the addresses that we were allowed to connect to our websocket server any addresses that's not listed here will be banned from connecting to the websocket server max request size is the size of the payload that's allowed to contain in a websocket request path is the uri to visit the websocket dashboard that i mentioned just now the middleware listed in the middleware array will be applied to every request visiting the dashboard the statistics section is where you configure on how we want the package to collect data each of the fields listed here has its own documentation in this file you can have a read if you want to customize the logic the ssl section is where we put in the configuration if we want to get our websocket server to use ssl certificate you will need this when you want to encrypt the messages transmitted by your websocket server and lastly we have a channel manager option and this will be the class that contains the logic to maintain all the websocket connections on this server by default laravel websocket stores all the connections in a php array if you want to store the websocket connection details in somewhere else like in a mysql database then you'll need to write your own manager class now larvae websocket is used as a pusher replacement and that means we can still pretend that we're still using pusher and we need to install all the dependencies required by pusher in particular the php server so in our terminal i'll type in composer require pusher php server once that's installed we'll go ahead and configure our environment variable for the package to work let's go to our env file and we'll go ahead and change our broadcast driver to pusher and we'll pass some dummy values to the pusher app id and push the app key and secret environmental variables if you're using pusher this will be your api keys and secrets for authentication since laravel websocket is a drop-in replacement for pusher we are not using these values for authentication instead laravel websocket will use these values in its configuration to identify the app tenancy just in case there are multiple apps connecting to the same websocket server at the same time okay let's move on next we'll need to set up a queue driver as i mentioned before laravel is implementing the pub sub pattern and the whole real-time architecture is driven by event the very same event that we have in our app folder whenever there's a new event fired in our app we could choose to whether broadcast this event or not if we choose to broadcast the event laravel will then send the event to the websocket server and a websocket server will broadcast the event to its client however the process of sending the event to the websocket server is rather time consuming it is much more efficient to do the job later so what we can do is to send this job to a queue system and we process the queue later on when the server is less busy and that is how laravel handles event broadcasting in a real-time app laravel provided us a few queue drivers out of the box typically we would use redis as the queue driver but just for demonstration i'll be using the sync driver for now the sync driver as its name suggests will process the job synchronously so there's no queue system at all if we are using the sync driver laravel will send the job to the websocket server directly without listing them in a queue anyway to set up the queue driver we will go back to the env file and set the queue connection key to sync which should be the default value out of the box you can take a look at the other possible drivers in the queue configuration fab there are other queue drivers like database bin stock and amazon sqs on our disposal and now once we have set up our queue driver we need to go to our app configuration file and enable our broadcast service provider otherwise we'll not be able to broadcast our event through websocket alright now we're ready to see if a websocket server is ready to run or not we'll go to our terminal laravel websocket actually provided us a nice php addition command to start our websocket server if you type in php addison you can actually see that we have a few new commands let's type in php addition websockets serve to start a web socket server and we'll visit the websocket debugging dashboard to test if our bad boy is running or not so let's go to our browser and visit the url as defined in the websocket configuration file which by default will be laravel websocket and you should see a web page similar to this let's click on the connect button and if you're able to see this dashboard that means you have set up everything correctly if not seek help it's a good time to stop here or continue in the next lesson alright key takeaways for this lesson pusher aptly library websockets society and laravel echo server are websocket servers that are supported by laravel laravel websockets is a wonderful open source drop-in replacement for pusher laravel uses the pubsub websocket pattern to publish real-time app events we need to set up a queue driver for laravel to broadcast websocket events the broadcast service provider should be enabled in the app config otherwise laravel cannot broadcast real-time websocket events laravel websockets exposed a debugging dashboard for our websocket connections that's it for now and i'll see you again in the next video hey there sam in the previous lesson i mentioned that every app event is broadcastable to the websocket clients let's discuss further on this topic in short when we want to broadcast our app event laravel requires us to broadcast these events through something called channels there are three types of channels in laravel the public channel presence channel and private channels when websocket clients want to connect to our server they'll need to subscribe through one of these channels provided by the websocket server here's how they work a public channel does not need authentication and anyone in the world can connect to this channel presence channel and private channel requires authorization and a difference between presence and private is that but presence channel is aware of all the users that are currently connected to the channel in other words all the users in the presence channel can see the information of each other this is perfect for chat room application where the users know who is online who is offline who posted this message and that message so on and so forth a presence channel is useful when the identity of the user connected to this channel is important to the application private channel on the other hand is for situation where we don't want users to know each other and we simply only want authorized user to connect to this channel we can use private channel for general purposes for example getting all the login user to connect to the same private channel in our app so that we can easily broadcast notification to all of our users we don't need each user to know each other so in this case a private channel will be perfect alright now let's look at how we can broadcast laravel app events and define broadcast channels the first thing that we need to do is to go to our appconfig file and uncomment the broadcast service provider under the application service provider section the broadcast service provider here is different to the one provided by the call framework listed up here the purpose of the core broadcast service provider is to set up the necessary code for broadcasting to work in laravel while the one down here is for us to set up our app broadcast service logic like defining the channel authentication routes setting up the middlewares and so on and now if we look inside the service provider we can see that it is a very simple service provider class containing only two lines of code the routes function from the broadcast facade will register the authentication routes for presence and private channels to work and line 19 here will register the authentication routes for private and presence channels that we define inside the channels.php file leaving inside the routes folder let's take a look inside it and as you can see here this file is pretty similar to the other routes file that we have in our app but instead of using the route facade we're using the broadcast facade here and we're defining a channel this time not a route endpoint the syntax is pretty similar to its route counterpart so the first argument is the channel name and the second argument is a callback function that will determine whether the current authenticator user can subscribe to a given channel or not the first argument in the callback function is the instance of the current login user and any subsequent argument represents the value of the placeholders in a channel name so in a sample snippet here it is representing the id placeholder in the channel name for a private channel we'll need to return a condition and if the condition is true that means the current authenticator user will be able to subscribe to this channel in a presence channel however in order for us to authenticate a user we need to return the user information in the callback function rather than just returning a boolean we will discuss more about this in the next video where we'll look at how to connect our front end to the backend but here is a simplified overview on how websocket authentication work in laravel so here's the client and here's a server when a client wants to subscribe to a private or presence channel the client will first send a http request to the server that is directed to the off endpoint in laravel which is by default slash broadcasting slash off upon receiving the http request laravel will then trigger the callback function as we defined in the channel.php file if the callback function returns a truthy result then the server will return a success response back to the client with the appropriate metadata for the client to establish a successful websocket connection with the server in a subsequent request the data in a http response is mandatory to make this websocket connection now if the callback function that we define in the channel.php file is returning a 4c result then the server will return a unsuccessful response and therefore the client cannot establish a websocket connection with the server this initial http request and response is what we call as handshake okay now let's look at how we can set up our event classes to get laravel to broadcaster to the websocket clients and just for demonstration i'll be creating a dummy event class let's go to our terminal and type in php addison make event and our code playground event and now let's go to our newly created event class and the first thing that we need to do in order to make this class broadcastable is to make it implement the should broadcast interface laravel will automatically broadcast any event classes that implements the should broadcast interface and now if we scroll down a little bit more we can see that as a function called broadcast on this is a function where we define which websocket channel that we want to broadcast this event on and by default laravel has made this event to broadcast on a private channel and now just for demonstration i'll change it to a public channel instead which will just be the channel class instead of the private channel class now the first argument in a channel constructor is the name of the channel now our app could have multiple websocket channels so it's a good idea to have some sort of naming conventions otherwise our channel names could go our hand very very quickly personally i like to name my channel in this way first i'll start with the channel type in our case here we are broadcasting on the public channel so it'll be public followed by a dot the second part will be the resource name and most of the time it'll be a model name in our case here since we're creating a dummy class so i'll call it playground you can put as many parts as you want but for the final part i always like to use it as the channel number or the channel id i'll hard coded as one for now channel numbers or channel id is great to manage websocket events for example if someone is working on post number one you wouldn't want events from post number two to affect post number one do you that's gonna cause chaos and never gonna lead to a happy ending all right let's test if our event is working we first need a way to send out this event so i'll go to the web php file and in a playground dummy endpoint i'll fire an instance of the playground event and now we'll go to our terminal and start our websocket server by typing in php addison websockets serve once we're done let's go to our browser and visit the debugging dashboard provided by laravel websockets let's click on the connect button and you should see some events pops up in the event list and if we go back to our terminal you should also see some debugging messages inside the terminal okay now we'll attempt to call the playground endpoint to fire an instance of the playground event let's click on the send button oh no we see an error it says pusher error off key should be a valid app key now in the last lesson i mentioned that laravel websocket is a pusher drop-in replacement we will need to configure laravel to use larvae websocket as the websocket server rather than using pusher to do that we need to go to the broadcasting config and in the pusher driver we'll add in a few more options by putting in the host and port we can define our own custom websocket server address and since we're not using any ssl certificate we should set use tls and encrypt it to false okay now let's go back to postman and try again and we see a 200 response fantastic let's go back to the browser and look at the debugging dashboard and we see a new event popped up in an event list which is our playground event and if we go to our terminal we can see that our event is logged in a console with the event name and the channel name and as you can see here the default event name is the fully qualified php class name of our playground event and here's a question what if i want to use my own custom event name the answer is super simple we just need to define another function in our event class and a function name is called broadcast s and we should return the custom function name that we want i'll call it playground for now let's test our code we'll go back to postman and send another request and back in our browser we can see there's a new event popping up and now with a custom event name called playground great we can also attach information inside the broadcasted event where the data attached in the event can be used by the front end to do that we need to go back to the event class and define a new method called broadcast with and whatever we return in this function will be attached as part of the event payload so here i'm just gonna return a simple dummy array and we'll go back to postman and try to send another request and now if we go to our terminal we can see that the latest event contains a payload in the data field and it is exactly the same as what we put in inside the broadcast with function isn't that neat so that's a basic intro on broadcasting in laravel and how to broadcast an event we'll discuss further in the next lesson about the front end private channel and presence channel i'll see you there key takeaways for this lesson if a websocket client wants to subscribe to a websocket channel in laravel the client will first need to perform a http handshake in other words to authenticate the user before establishing a persistent websocket connection event classes will need to implement the should broadcast interface before laravel can broadcast them to the web socket we'll need to configure the host and port of the pusher driver in broadcasting.php config file to get laravel to use our save hosted laravel websocket server otherwise laravel will attempt to use pusher out of the box by default laravel will use the event fully qualified class name as the event name if we want to use our own custom event name we need to define the broadcast as function inside the class we can attach data inside the event payload by defining a broadcast with functions inside the event class that's it for now and i'll see you again in the next video hey there sam let's learn how we can subscribe to a websocket channel on the front-end javascript thankfully laravel has provided us a client library called laravel echo that takes care of all the hard work for us so we can easily subscribe to our channel and listen to events so first thing first let's go to our terminal and run npn install laravel echo we will also need to install the client library of pusher.js because we're using the laravel websocket server as a proxy to the actual pusher server and now once we have installed the npm packages we'll need to configure webpack in order for us to use these packages in our front-end javascript and thankfully laravel provided us a tool called laravel mix which is a wrapper around webpack to let us configure webpack with an easy to use api to configure laravel mix we need to go to the file webpack.mix.js which is living in the root of our project directory now if you're not building the front end this part might not be that relevant to you we are really just compiling all of our front end code for our app now i want to enable the hot module reload feature in webpack so what i need to do in this file is to call the option function from laravel mix and pass in the option where i'll define the host and the port for the hot reload development server the hot reload development server will serve as a proxy server to store all the compiled assets and once we're done we will create a new blade file for our websocket experimentations and i'll go ahead and load our javascript where the source url is in our hot reload server laravel mix allows us to resolve the compiled assets in the hot reload server by using the mix helper functions and once we're done we can ensure that the code in our app.js will become available to this black file alright let's take a look inside our app js it is quite empty and the only line is loading the bootstrap.js file and bootstrap.js is really loading all the global libraries into the windows object and at the very bottom of this file we can see that in a commenter code here laravel has provided us some snippets for us to load laravel echo let's uncomment it and what it is really doing here is to load echo and pusher into the windows object so that we can call these libraries globally in our app let's take a brief look at the configuration of echo the broadcaster option is for us to define the broadcast driver which in our case will still be pusher since we're using laravel web sockets key is the api key of pusher and we're simply reading it from the dot emv file laravel mix will automatically load all the nv variables with the mix prefix cluster is the cluster information about the websocket server we don't really need it in our case because we are not using pusher force tls is only required when we are using ssl we will set the phones for now and on top of this existing configuration we also need to pass in a few more for echo to work correctly the first one is the ws host key which is a host name of our websocket server and in our case it has the same domain name as our front end client we can just use window.location.hostname and we also need to set the port of the websocket server and also send encrypted phones and again because we're not using ssl and finally to set the enable transport property so that will restrict the transport of data to the websocket protocol only wss is a secure version of the websocket protocol that utilize the ssl certificate just like https in http okay now we have finished setting up echo we are ready to connect to our websocket server let's go to app.js and currently we have only one public channel defined on our server from the previous lesson to subscribe to a public channel we simply need to call the channel function on the echo object that we have set on a windows global object this function will return us a channel object that contains a multitude of helper functions for us to work with our web sockets channels we can call the subscribe function to register a callback that will be triggered when we have successfully connected to a channel i'll simply cancel out subscribe just for demonstration and now let's try to run our app we'll go to our terminal start our server and start the websocket server and we also need to start the whole reload development server and thankfully laravel has provided us a script called hot in our package.json and now the last thing that we need to test our code is to set up an endpoint to serve our websocket dummy blade file now simply go to the web.php file and register a new endpoint called ws which will simply send back the websocket view okay now everything is ready let's go to our browser and visit our app and in the browser console we can see that the callback has been triggered and we are subscribed to the public channel and just to double check if we go to our terminal we can see that in a console it says that subscription succeeded and there's a new connection subscribed to the public channel great and now let's look at how we can receive events in a front-end client to do that we need to call the listen function on the channel object the first argument is the event name so in a playground event that we created in the previous lesson we have made it so that it will be broadcasted under a custom name code playground since we have used a custom name so in a listen function we need to put a dot prefix before the event name otherwise laravel echo will be using the default prefix which is the fully qualified event namespace in laravel's app the second argument that the listen function will receive is a callback function to handle the event and the argument is the event payload just for demonstration in the function body i'll console out the event for now let's go back to our browser i'll hit refresh and go to postman and send a request to the playground endpoint that we created in a previous lesson to fire the playground event and in the browser console we see the event payload printed out in the console which is exactly the data i have attached inside the playground event that i have defined inside the broadcast with function isn't that neat can you think of any application that you can view with this feature let me know in the comments below but for now just as a quick example we can easily build a simple messaging application using websockets let's give this a go first of all i'll add an input box in our html for the user to type in their messages next i'll add an event listener so that whenever the user has entered a message we'll send an api request to the server and the server will broadcast an event to the other subscribing clients and the broadcaster event will contain the text message that the user has just entered so within the event listener we'll grab the user input and go ahead and send a post request to an api endpoint which will be defining it very soon in our api server okay now let's go to our web.php file and we'll quickly define a new endpoint called chart message this post endpoint should fire an event that will be broadcasted to the websocket i think it's a good idea to refactor our playground event to something more meaningful i'll refactor the playground event class into chat message event and this class will accept a string message in the constructor and i'll rename the channel name to public chart 1 instead of public playground1 and i also renamed the event broadcast name to chat message and the event payload will only contain one property which is the message to be broadcasted and now back inside our app.js will change the subscription channel to public chart one and also refactor the event name alright let's test our code we'll go to our browser type in a message and oops the page refreshes because i forgot to call prevent default on the submit event let's try again the page stopped refreshing but we got nothing in the console and the reason is because we haven't defined anything in the body of our chart message post endpoint so let's go back to web.php we will fire the chart message event in the endpoint and pass the message insider request into the constructor of the event class all right let's go back to our browser and try for one more time i'll hit enter in the input box and this time we see our message appearing in a console great and now if i open a separate browser window and type in 1-3 in the text box and we see the message123 appearing in the first browser window because both of the browser windows are now subscribing to the same channel and the message event is broadcasted to all of the subscribers that's the reason on why the first browser window is receiving the message123 that i typed in in the second browser window alright let's keep going now i want to keep a history of all the messages that we have typed in the dom let's see how we can achieve this i'll go back to the html and correct a list and i'll put in all the messages inside this list and now i'll go back to app.js and every time we got a new message from the websocket we'll create a new list item and add it to the message list okay let's test our code i'll type in one two three in the browser window and a message shows up in the other let's try it on the second browser window i'll type in 222 and it shows up in the first browser window as well isn't that great we got a basic aspect of a chat app working now the next thing that we need to do is to make use of the private or presence channel so that will only allow authorized user to send messages we'll continue in the next lesson i'll see you there key takeaways for this lesson laravel echo is the official javascript client for us to subscribe and receive websocket events from the server laravel mix is a powerful wrapper around webpack that provides a painless api to configure webpack we use the channel function from echo to subscribe to a websocket channel and the subscribe method led us to define a callback that will be triggered when we have successfully subscribed to our channel the listing function allows us to listen to websocket events and we should use a dot prefix when we want to listen to a custom event in echo otherwise echo will be prefixing the fully qualified class name of the websocket event that's it for now and i'll see you again in the next video hey there sm let's look at how we can authorize a user to join a channel as i mentioned in a few lessons ago we will need to use either a private channel or a presence channel if we want to implement authorization let's start by changing the channel of our chart message event currently it's on the public channel so i'll change the class name to private channel instead and also refactor our channel name next we'll need to define the authorization logic for our newly created private channel we'll go to channel.php that lives inside the routes folder and will define the new channel in here we will call the channel method from the broadcast facade and the first argument will be our channel name which will be private chat and an id the second argument is a callback function that takes in the current login user as the first argument and the second argument is the id placeholder that we have in our channel name and in the callback function will return a condition where it will determine if the user is allowed to join a channel or not for now i'll just return true just for demonstration and that means to always let the current login user join our channel without any extra conditions now also note that if our website visitor is not logged into our app they cannot join a private channel by default if someone wants to join a private or presence channel laravel will authenticate them using the default authentication guard which was defined in an offconfig file and if you want to have a final control on a per channel level you could pass in a third argument in a channel function where you define the guards that you want to apply to authenticate the user but 90 of the time you don't really need to touch this option anyway let's test our code we'll go back to app.js and subscribe to the private channel instead of the public channel now instead of calling the channel method we should call the proper method to connect to a private channel and now we go to our browser and we see a 403 error coming from the post request sending to the broadcasting of endpoint this is the http handshake that i mentioned in the previous lessons so the client attempted to establish a connection with the server but got rejected by the server because we're not logged in because of the default authentication guards that laravel has attached to the channel to fix this error we first need to login before we subscribe to the channel and we'll copy and paste the login logic that we have created in a several episodes ago from the app blade file and then we'll move our channel subscription logic after we have logged in and now let's go to our browser hit refresh and we no longer see errors and that means we have successfully subscribed to the private channel and now let's see what will happen if we return false in the authorization callback function let's go back to our browser hit refresh and we see the 403 error again on the broadcasting of endpoint and that means the handshake is rejected we definitely don't want that so let's change it back to true alright let's move on i would like to display the author of each message in the dom as well and that means every time when we emit the chart message event we should also attach the current login user in the event so let's go to our chart message post endpoint and we'll pass in an instance of the current login user to the event constructor and within the event class we'll set a user as a class property and attach the user in the event payload we don't want to attach every information about a user inside the event payload so we just put in the name and email field okay now let's test our code let's go back to the browser and send a message and in the console the event payload that we received contains the user email and name and we can certainly make use of the information inside the event payload to make our ui better let's do that and i'm gonna turn on my 10x speed boost lifehack to code faster [Music] i would also like to put in all the people who are online in this chat room in the navbar i'll put in some placeholder avatar for now [Music] and there we go we've got a nicely styled template to work on now we just need to populate the data into our dom first of all let's clear our hard coded data and we will modify our list item creation in javascript i'll copy one of the hard coded block and paste it inside our arcgis as a reference and i'll go ahead and replicate the structure in javascript and we'll go to our browser and test it and it works and now i'll open a new browser window and test if it is working as expected and it works great and now the next thing that we need to do is to put all the online users on the navbar and that means we need to keep track on who's entering the channel and who's exiting the channel unfortunately this is not something that a private channel can easily achieve so instead we need to use a presence channel and just a quick recap the difference between a private channel and a presence channel is that a presence channel is aware of all the users that's currently in the channel i'll show you what i mean first of all let's change the channel that the chat message event will broadcast to to a new presence channel and i'll go to channel.php and refactor the authorization logic in a private channel we need to return a boolean in the authorization callback function however in a presence channel we will need to return the authorized user so if we decide to let the login user to join the channel we should return the user instance otherwise we don't need to return anything in a callback function and now let's go to our app.js to subscribe to a presence channel we'll need to call the join method on echo instead of the private function and now we have access to a few more api in a presence channel the function to define the on subscribe hook is called here instead of subscribed and the callback function accepts an argument which represents an array of all the users who are currently in the channel so later on we'll be populating every one of these users into our navbar we also have another method called joining which will be triggered whenever there's a new user join the channel and also a living method which will be code when a user leaves the channel alright let's give this bad boy a test run and upon reloading our browser we can see that the user array is printed out when we subscribe to the channel but when i refresh the second browser window we are not seeing the joining method being code and that's because currently we're logged in as the same user i'll quickly make a login form so we can log in as other users alright our form is ready i'll log in as the first user and the second user in a private window alright as you can see as the second user log in the console is printing out the newly joined user information which is what we return in a channels.php callback function and now if user number 2 tries to exit the chat room we'll see the leaving callback function got triggered as well so that means our presence channel callbacks are registered correctly and now let's polish our code so that will show all the online user in f bar i'll create an empty array to store all the online users and when a here function is called i'll reset this array to be the users currently in a channel and i also create a helper function called render avatars which will simply look through all the users online and generate an avatar for each of them and append it into the navbar let's give this a go and it's working but i forgot to put in the initials inside the vata a clear helper function to retrieve the user initials and put the initials within the avatar let's try again and it's working great and now let's write the logic for the leaving and joining callbacks so when a user has joined the channel we will add the user to our users online array and re-render the avatars and when a user is leaving the channel we will filter out the user from the user's online array and again re-render the evatas avatars alright let's run this bad boy for another time we'll log in the first user and the second user and we see both users initials are popping up in the navbar great and will send a message on behalf of each user and they are showing correctly in the chat box wonderful and now if the second user is leaving the users of valata in the navbar disappears great our app is working as we expected and one last thing i would like to show a divider whenever someone joins the room or exit the room let's refactor our code or create a helper function to generate a new text box in the app and the function body is pretty much what we have done in the event listener for the chat message event so i'll cut and paste it and modify it accordingly and now when a user joins or leave the channel i would also like to add a new chat message to notify everyone in the room about it alright let's test our code we'll log in as the first user and second user in the private window and upon logging in we see the message the second user has joined the room in our first browser window and when the second user leaves the room we see the message has left the room isn't that neat and now we're still lacking of one feature which is typical in a chat room that is whenever someone is typing a message i would like to show a typing notification to everyone in the room we'll talk more about this in the next lesson key takeaways for this lesson private and presence channel will only allow authenticated user to join in they uses the default off guard to authenticate users presence channel keeps tracks of all the subscribing clients while private channel doesn't we use the private function in echo to subscribe to private channel and the join function for presence channel we need to define an authorization callback in channels.php for private and presence channel the private channel of callback should return a boolean while the presence should return the authenticated user instance that's it for now and i'll see you again in the next video hey there sm http is rather slow compared to websocket and in a real-time app speed is the utmost priority so if you want to get more juice out of our app we should make good use of websocket currently our chart app is not perfect here's what has been happening behind the scene this is our client number one and this is our server so client one wants to send a message to the group chart and it will do so by sending in a http request to the server the server received a request and proceed to send out an event then the event will be broadcasted through the websocket server to client 2. now as we know http request is slow it could cause some delay for the event to arrive in clan 2 and will be the bottleneck for this websocket architecture and things gets even worse if we are using an asynchronous queue driver to broadcast the event which will cause further delay in the whole process now the point here is that if there are events that we don't need to pass through the laravel server we could have established a connection directly with the websocket server and transmit the data to our peers without going through our laravel app at all by using this path we can transmit data to the ps in a near real-time speed and now the big question is how are we supposed to achieve this well there are two ways that i can think of right now one is a long way which is more powerful but at the same time more complicated that is to set up a websocket rpc api on our websocket server the second way is a shorter and easier way which is to use a built-in laravel echo function called whisper that will allow websocket clients to talk to each other without going through our laravel server we'll discuss the short way in this lesson and a long way in the next video okay now i want to implement the someone is typing feature in our chat room so the idea here is that if someone started to type something in a chat box we will broadcast the event to everyone else in the channel alright let's get into it so here in our app.js i'll add an event listener to the input message box so for every keystroke i will whisper or broadcast a typing event to everyone in a channel the whisper function accepts two arguments the first argument is the event name and the second argument is the event payload and i'll just put in the user email here and now to listen to the incoming whisper messages we will need to call the listen for whisper function on the channel and upon receiving the typing event i would like to show a small display in a dom to notify everyone in the room let's go to our html and do exactly that i'll add a span just above our input element back to app.js target the element and when someone's typing i'll simply set the text content of the span to the email in the event payload and adding a text is typing at the end of it and now before we test our code we need to make sure that in our websocket config we have enabled the client messages option and remember to restart your websocket server after that ok now let's go to our browser and test our code our login has two different users in two browser windows and now if i type in something in one window the other window shows the typing notification great and now here's another problem when i clear the content in the input box the typing notification still exists in the other window and it is also a good idea to leave a small spacing on the left hand side of the notification let's fix these two things quickly i'll add a small padding left on a span and in the input event listener when a value in the text box has a line of 0 that means the user has cleared everything in a text box will whisper a new event called stop typing and back to our channel listen chain i'll listen for the stop typing event where we'll set the spam typing to empty when a user has stopped typing alright let's test our code ok as you can see as i clear out my text message the typing notification disappears and that's how the whisper function works in laravel echo alright key takeaways for this lesson http is rather slow for real-time application it is quicker to communicate with the server through websocket connections the whisper function from laravel echo allow us to send events to each other without passing through laravel the listen to whisper functions listen to ps event in a channel that's it for now and i'll see you again in the next lesson hey there sm http is rather slow and in some real-time app the delay in processing http request could be the bottleneck of the whole application so what's the alternative then the answer is something called rpc and just for quick recap rpc or remote procedure code is a websocket pattern that is pretty similar to http so the websocket client will send a request to the server to execute a function in a server and the server will send back a reply which contains the result of the functions since we're executing a remote function in the server and that's why it's called remote procedure code unfortunately laravel does not support rpc by default the websocket architecture that laravel utilizes is the pub sub pattern not the rpc to implement the rpc pattern one has to have the full control on the websocket server and thankfully for us since we're building the websocket server by using lara websocket we have full control on the server and therefore is possible for us to implement the rpc patent and furthermore laravel websocket is written in php therefore it means that we can access to all the larger components in the websocket server if you're using a websocket server that's based on other languages then you might need to build your own custom bridge to connect the websocket server to laravel okay now let's take a look at how we can implement the rpc pattern using laravel websocket if we go to its documentation on the left hand side there's a section called custom websocket handlers and that is exactly what we need to implement our pc in short we can define these websocket handlers to directly accept websocket requests in laravel all we need to do is to create a handler class that implements the message component interface the class contains a list of websocket lifecycle methods for us to customize the websocket logic on different stages of the websocket connection once we have defined the handler we simply need to go to the web php file and register the handler to a websocket route which is very similar to how we define a http request endpoint using a controller class let's create one of these handler files in our project i'll create a new folder called websockets in the app folder and a subfolder called socket handler and we'll create a new class here called update post socket handler where the main purpose is to update a post and just like what the documentation has said the socket handler should implement the message component interface now the message component interface has four methods the on open method will be code upon establishing the websocket connection on close will be code when the websocket connection is ended and on error is code when there's an error and on message is code when a websocket server receives an incoming request the first argument contains the details about a connection and a second argument is an instance of a message interface where it contains the message body of the incoming websocket request whoops seems like i have implemented the wrong interface it should be the message component interface under the wretched websocket namespace now every websocket handler will need to implement these four methods while the message method could be different from cluster class but the on open on close and on error methods should have a very similar logic for all handler classes and that means we can abstract these three methods to a base class let's create an abstract class for that and just for demonstration i'll just dump a few simple messages on each method now for the onmessage method we will need to write a logic to update a particular post let's leave it for now we will first need to register our handler in our web.php file we can easily do that by calling the websocket function on the websocket's router facade the first argument will be the route name and the second argument will be the handler class we'll go to our front-end app.js and attempt to connect to our websocket server i'll create a new function called update post and now we are connecting to our websocket server directly so we're not going to use echo instead we'll be working with the built-in browser web socket api so we'll create a new socket instance and pass in the url to our websocket update post endpoint the socket object has a few properties for us to set a few lifecycle hooks on the websocket connection we'll go ahead and set the on open function for now and when the websocket is open we'll simply console out on open and then we'll call this function after we have logged into our app and i'll comment out everything about echo for now okay let's head to our browser and test our app we will log in and we see on open in the console we have successfully established a connection with the rpc websocket server however now there's a few concerns about the security of our websocket endpoint currently our websocket route is defined as it is without any middleware applied on it it has zero protection whatsoever and that means everyone can connect this websocket endpoint without logging in i'll show you what i mean we'll go back to app.js and we'll call our update post function outside the login callback function and we'll go back to our browser and now open a new private window visit our app and we still see on open in the console without even logging in that is a big no-no we definitely don't want everyone in the world to be able to connect to our precious websocket endpoint how do we fix this well we are using the websocket protocol here so we can't really use http middleware one of the possible options is for us to define our authentication logic in the on open lifecycle hook we could access the incoming http metadata here by reading the http request property on the connection instance i'll dial and dump it here just to look at what's inside this property and i'll restart our websocket server and as you can see in the terminal we can see of the incoming details about the initial handshake and we can go ahead and use all the data here to perform our authentication logic for the websocket connection i won't be writing the authentication logic here otherwise this video will be too long for now we'll look at how can we send data to our websocket server from our javascript client but there's one thing that i'll do which is to attempt to read the app key from the incoming connection so if we look at the default websocket handler in the laravel websocket package source code we notice that in the on open function is calling a function called verify app key now the verify app key will attempt to read the app key query parameter from the incoming http request and check if it is a legitimate app key from the config file if not it will throw an error now in our own custom websocket handler we should be consistent with this approach so we'll copy and paste the verify app key function to our onbase handler encode this function on the on open lifecycle hook and now since our websocket server is checking the app key query parameter in the http request so that means in our app.js when we want to create a new websocket connection we should also pass in this app key let's restart our websocket server and go back to our browser and it's all working and now let's try to send some message to our server so in app.js upon connecting to the websocket server will try to send a payload by calling the send function on the socket object we can only transmit string data or array buffer so we'll stringify our payload by calling the json stringify function and i'll say the payload contains the id of the post that we want to update and also a payload property which contains the post attribute that we want to update i'll hard code the value for now and we'll go back to our update post socket handler and now down the message in the onmessage lifecycle hook the message object provided us a few helper functions and we can code the get payload helper method to grab the content of the message all right let's restart the server and we see an error and it says undefined property socket id so it turns out that we need to define a socket id for each of the incoming websocket connection how do we do that let's take a look at the source code of laravel websocket again in the provided socket handler class we can see that in the on open lifecycle hook it is calling another method called generate socket id in the function body it is simply generating a random number and set to the connection object let's copy and paste this function to our base handler class and our code is method in the on open hook all right let's restart our server again and refresh our browser and now our server console is no longer printing out an error instead we see our payload inside the console but it is in the form of a string to work with this json string we need to convert it into an array in php i'll call the collect and json decode function so i can work with the payload using the collection api provided by laravel and now we'll retrieve the payload and the id from the message body we'll dump the payload and id variable to check if our code is working correctly let's restart our server visit our browser again and inside our terminal and we can see that our payload and id is dom in the console exactly as what we have sent in a javascript client okay now let's update our post using these two information we will first find the existing post in our database and then we'll call the update function on the repository to update our post based on the payload once the post is updated we will create a response using the post resource class and will send the response back to the client by calling the send function on the connection instance which is represented by the from variable and now we'll go back to app.js and add the on message hook on our socket to receive the reply coming back from the websocket server okay let's restart the server and we'll go back to the browser and refresh the page and nope we're not receiving any message coming back from the server and if we go to our terminal we can see that our server did receive the request but for some reason our app is stuck in between the dom and the send function why is this happening so it turns out that in our post repository we're sending out a post updated event upon updating our post now by firing this event laravel will attempt to broadcast it to all the websocket client at the moment we are using the sync broadcast driver we are still in the middle of an rpc connection we can't instruct the server to send out another broadcast it's like someone who's buying a walking sleeping bag who wants to sleep and walk at the same time so the code will start here forever so to rescue this code we have two options one is to comment out the post updated event so our app will not attempt to broadcast another message while the rpc is still ongoing the second way is to use an asynchronous queue driver like redis for our post updated event alright let's restart our server and we go back to the browser and now we see a message event popping up in the console great however the event data is a raw http response so it might be better if we call the to json function instead of the response method in our update post socket handler alright so that's an overview on how we can implement rpc using laravel websocket and now you might be asking does that mean rpc can replace http and my short answer is yes but you need to make sure that the server has the capacity to handle all the incoming websocket connections all right key takeaways for this lesson rpc or remote procedure code is a websocket pattern that works very similarly to http following a request and reply pattern http is rather slow rpc could be a faster alternative for real-time apps laravel websockets allow us to work with the low-level websocket api using websocket handlers although it is faster we need to write a fair amount of code to handle security as it is not provided out of the box that's it for now and i'll see you again in the next lesson hey there sam when we deploy our app to the live production environment it is inevitable for us to configure our websocket server to use a ssl certificate for wss encrypted connection and it is also probably a good idea to test your development environment with self-signed certificate before you push to the live production environment now here i'm using a docker environment as an example to show you how i set up the ssl certificate if you haven't learned about docker yet this section might be a little bit confusing to you but that's okay just think of docker as a virtual machine and try to follow along with this tutorial let me know in the comments below if you want me to make a docker tutorial series i have a few docker containers here but what we need to focus now in particular is the engine x container which is our main web server and also the workspace container which is where i run our websocket server and currently i'm running a share instance inside the workspace container and i'll start laravel websocket by typing in php artisan websocket serve to configure the ssl certificate the first thing that we need to do is to supply the path to our certificate in the env file laravel websocket will read these values and attempt to read the certificate and it's key when it's trying to set up a secure websocket server so make sure that your app has read access to the certificate that you specify in this path otherwise you'll encounter an error these values have been read inside the websocket config file under the ssl key and if you are using self-signed ssl certificate you might want to disable some of the built-in authorization feature like verify ps and verify peer name otherwise you might encounter an error next we need to go to a broadcasting config file and there's a few things that we need to configure here in the option key the host will be the host of your websocket server in my case it will be the name of my docker container if you're using docker make sure that you have configured your network correctly we need to set encrypted to true and also scheme from http to https and also set use tos to true if you're using self-signed certificate like me you might also want to put in these two curl options the reason is the same as before to disable some of the authorization feature for self-signed ssl to work and now the last thing that we need to do is to configure echo let's go to bootstrap.js in addition to ws port you now also need to set a wss port and we want to send encrypted to true and also false tls to true and now it's time to test our connection and if you have edited any of your websocket server settings remember to restart your server let's go to our browser and visit our websocket dashboard i am greeted by a warning sign and that's normal because i'm using a self-signed certificate just ignore the warning it's totally safe i can guarantee you your safety and now once we're in a dashboard let's click on the connect button and oh dear we see an error in the console saying that we could not establish a connection to the websocket server and the error message is not helpful at all it did not tell us any reason whatsoever and i've spent several painful hours figuring this one out so it turns out that it's an issue with self-signed certificate we have enabled the certificate for our web server just now in our browser but we have yet to do so for our websocket server so what we need to do here is to visit the websocket url and change the protocol to https rather than wss and we're greeted by another warning page and by clicking on proceed we are enabling the certificate for our websocket server now back to the dashboard we can now connect to our websocket server problem solved if you are using a ssl certificate with a valid authority you won't be having these problems at all and that's how you configure ssl in laravel websockets alright key takeaways for this lesson to configure ssl certificate for laravel websocket we need to set the certificate path in the env file and in the broadcasting.php config file we will need to set the encrypted option to true and set scheme to https and set ustos to true for laravel echo we will need to set the wss port and encrypted the true and also false tls to true that's it for now and i'll see you again in the next lesson if you enjoy the content of this video don't forget to hit the like subscribe and the bell icon for more content to come it will really help me out thanks for support [Music] you
Info
Channel: Acadea.io
Views: 55,918
Rating: undefined out of 5
Keywords: laravel, websockets, real time, laravel websockets, advanced tutorial, echo, laravel echo, best practice, tutorial, web development
Id: AUlbN_xsdXg
Channel Id: undefined
Length: 75min 30sec (4530 seconds)
Published: Tue May 24 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.