WEBVTT 00:01.230 --> 00:06.870 So as I suggested last time, we're going to use WebSocket to fire off a message to the users saying, 00:06.870 --> 00:10.800 hey, your account has been deleted and we'll log them out automatically. 00:11.670 --> 00:13.890 So to do that, we need to import a package. 00:13.890 --> 00:17.610 And the package I'm going to use and I'm going to my Web browser is right here. 00:17.700 --> 00:18.930 Gorilla WebSocket. 00:18.930 --> 00:20.100 It's widely used. 00:20.100 --> 00:21.000 It works really well. 00:21.000 --> 00:25.560 And it takes much of the heavy lifting out of the equation when working with WebSocket. 00:25.650 --> 00:27.110 Installation is pretty simple. 00:27.120 --> 00:27.810 It's right here. 00:27.810 --> 00:28.830 So let's copy that. 00:30.390 --> 00:39.480 Go back to Visual Studio Code, open a terminal and paste that in and that should add it to our go modify. 00:39.630 --> 00:40.230 And it did. 00:41.070 --> 00:48.800 So now I'm going to put all of the logic for working with WebSocket right in the Web application. 00:48.810 --> 00:50.310 So in CMD Web. 00:50.310 --> 00:58.500 And I'll create a new new file here called Eustache Handlers for WebSocket Handlers, Dongo. 01:00.000 --> 01:01.060 And of course, that's package. 01:02.940 --> 01:09.120 Now, the first thing I'm going to do is set up some types because we need to communicate with the front 01:09.120 --> 01:09.450 end. 01:10.410 --> 01:13.340 We need to send information off to the connected client. 01:13.350 --> 01:21.330 So the first thing I'll do is create a type which I'll call WebSocket connection, and it's a struct 01:21.480 --> 01:22.740 and it only has one member. 01:22.980 --> 01:26.250 And the member is a pointer to WebSocket. 01:27.000 --> 01:29.640 And I want to make sure I get the one for gorilla right here. 01:29.670 --> 01:36.060 Not this one x net slash websocket which works, works really well, but it would require a lot more 01:36.060 --> 01:39.030 coding and this one takes care of a lot of the heavy lifting for us. 01:39.060 --> 01:45.310 So we'll import that WebSocket dot com and that imported gorilla websocket for me. 01:45.390 --> 01:48.410 So there's my first type that holds the WebSocket connection. 01:49.920 --> 01:55.490 The second type is a payload and it defines the data that we're going to receive from the client. 01:56.100 --> 02:00.390 Now, in all honesty, in this course, we're not going to receive any information from the client. 02:00.390 --> 02:06.540 I'm only interested in pushing a message off to the user saying, hey, user ID X has been deleted. 02:07.320 --> 02:12.150 But since we're writing this anyway, and at some point in the future, you might want to communicate 02:12.150 --> 02:16.620 from the your web client, from the connected client to your server mail will set that up. 02:16.620 --> 02:17.640 Now, it's not hurt. 02:18.210 --> 02:24.600 So I'll create a type called W.S. Payload and it will be a struct and we're not really using it. 02:24.600 --> 02:27.810 So it doesn't matter what I put in here, but I'll put in the things I normally put in. 02:28.410 --> 02:30.840 So I'll put in an action which will be a string. 02:30.990 --> 02:36.870 And in JSON I'll call that action and I'll duplicate that a few times. 02:38.190 --> 02:42.450 I might also want to know things like what's the message they're sending me? 02:42.750 --> 02:44.730 And in JSON, I'll call that message. 02:45.360 --> 02:49.680 And again, we're not using these that I'll have what's the username? 02:50.250 --> 02:54.420 And I'll export that which I'll call username. 02:57.900 --> 02:59.460 Then I might have message type. 03:03.270 --> 03:05.880 Which will be message underscore type. 03:08.510 --> 03:16.010 And finally, what connection am I and that is of type WebSocket connection and in Jason, I'm not going 03:16.010 --> 03:16.670 to send that at all. 03:17.840 --> 03:22.400 OK, so let's format this now. 03:22.400 --> 03:25.820 The next thing we're going to need is a variable and it's a verb. 03:26.060 --> 03:28.250 And I'm going to call it upgrade connection. 03:30.530 --> 03:36.950 And I'm calling it that because when you connect using WebSocket, your connection, your connection 03:36.950 --> 03:41.280 to the Webs Web server is actually upgraded to a two way communication. 03:41.300 --> 03:52.070 So this is a type that's equal to WebSocket DOT upgrader with the R at the end and we'll populate its 03:52.070 --> 03:52.520 members. 03:53.960 --> 03:55.630 So we'll say read buffer size. 03:56.010 --> 04:03.950 Just put something that makes sense in their read buffer size and I'll make that ten, twenty four which 04:03.950 --> 04:04.400 is fine. 04:04.680 --> 04:05.660 That's a good default. 04:06.200 --> 04:12.080 And write buffer size will also be ten, twenty four which makes sense and is going to cover almost 04:12.080 --> 04:12.920 every use case. 04:13.820 --> 04:20.510 Now this one check origin, I'll make that a function that simply returns. 04:20.510 --> 04:23.660 It takes an argument are pointed to HDP don't request. 04:27.240 --> 04:35.790 HTP done request, which apparently won't have to manually impart, but that's OK and it returns a ball 04:36.390 --> 04:37.950 and it's only going to return. 04:38.160 --> 04:38.590 True. 04:39.340 --> 04:42.790 Now, checking your connection, let me import that again. 04:42.810 --> 04:44.550 Let's try this again, HTP. 04:46.230 --> 04:46.680 There we go. 04:48.000 --> 04:49.780 So that should have imported it. 04:49.960 --> 04:50.350 It did. 04:51.240 --> 04:53.720 This is how you secure your websocket connections. 04:53.730 --> 04:57.840 And since we're not actually receiving anything from the front end other than your initial connection, 04:57.840 --> 04:58.800 we don't care about this. 04:58.860 --> 04:59.970 So we're just going to have it return. 04:59.970 --> 05:00.320 True. 05:01.050 --> 05:05.550 But if you want to lock down, if you are communicating from your Web browser to the server, you're 05:05.550 --> 05:07.460 going to want to do some actual logic in there. 05:07.470 --> 05:09.230 But this is sufficient for our purposes. 05:09.270 --> 05:10.190 So we have that variable. 05:12.180 --> 05:18.420 Now, I'll put another type in here, and this is the one we are going to use for sure type was Jason 05:18.420 --> 05:19.190 response. 05:19.320 --> 05:24.930 This is what we're going to send to the end user and it's a struct and we'll have an action which will 05:24.930 --> 05:30.150 make a string and adjacent we'll call that action and we'll duplicate that. 05:30.870 --> 05:31.800 We'll have a message 05:35.130 --> 05:38.460 which which will also have a JSON value of message. 05:39.780 --> 05:46.020 And I'm also going to put in there the one that's critical in our case, user ID, and that will be 05:46.020 --> 05:52.540 in it and in JSON will call that user underscore Edem. 05:54.810 --> 06:01.680 So what we're going to do is we're going to when someone's user account is deleted from the user's table, 06:02.100 --> 06:07.080 we're going to populate this with information, including the user ID, and send that off to everyone 06:07.080 --> 06:07.740 who's connected. 06:08.610 --> 06:14.640 And if the user ID that is sent matches the user ID that's in the session for the connected user, we'll 06:14.640 --> 06:15.450 just log them out. 06:15.550 --> 06:16.590 That's all we're going to do here. 06:16.930 --> 06:22.050 OK, we also need to keep track of every client who is connected. 06:22.170 --> 06:28.350 So we'll carry another variable, which I'll call clients and it will be equal to make a map. 06:28.920 --> 06:34.430 And the key will be a WebSocket connection and the value will be a string. 06:35.010 --> 06:41.520 OK, and we're also going to use a channel and will push to the channel any time we want to receive 06:41.520 --> 06:42.800 information, for example. 06:43.560 --> 06:49.470 So we'll create a channel, W.S. Channel for WebSocket Channel, and that's equal to make. 06:49.950 --> 06:52.860 Can W.S. payload. 06:54.210 --> 06:55.450 OK, that's we're going to be sent. 06:55.470 --> 06:57.990 That's that's what the channel will take his payloads. 06:58.620 --> 07:06.930 Now let's create a function which is a handler and it takes the receiver of appointer to application 07:06.930 --> 07:07.620 as usual. 07:08.490 --> 07:11.160 And this one is going to be called the WC End Point. 07:14.320 --> 07:20.160 And because it's a handler, it takes a response writer and a pointer to a request 07:22.890 --> 07:24.540 and also give ourselves some room here. 07:27.360 --> 07:30.210 And the first thing you do is upgrade the connection. 07:30.480 --> 07:35.970 So when this handler is hit, when a request comes in from JavaScript, of course, on the front end, 07:36.210 --> 07:37.530 we need to upgrade the connection. 07:37.530 --> 07:42.270 So I'll create a variable W.S. for WebSocket and we check for an error. 07:42.280 --> 07:47.640 And that's a sign the value of our upgrade connection upgrade. 07:47.910 --> 07:49.740 And it requires three parameters. 07:49.950 --> 07:55.740 The response, Frater, the request and the third one I'm just going to set to nil because we're not 07:55.740 --> 07:56.940 using it in this course. 07:56.940 --> 07:58.770 And then a lot of cases you don't use it anyway. 07:58.890 --> 07:59.640 We'll check for an error. 08:00.300 --> 08:03.180 If error is not equal to nil, then we'll just log it. 08:03.630 --> 08:09.870 APTA error log, print line the error and I'll return. 08:09.870 --> 08:15.180 At this point, I don't want to go any further, but assuming we've upgraded the connection properly, 08:15.330 --> 08:25.300 let's just write some information to the log after info log dot print line and in here I'll put format, 08:25.350 --> 08:35.730 format, print F and I'll write client connected from percent percent s and will replace that with our 08:35.970 --> 08:36.750 remote address. 08:38.430 --> 08:43.320 Just so we know that someone is actually connected, we can make sure that things are working and let's 08:43.320 --> 08:45.540 create a variable to send some information back to them. 08:45.700 --> 08:53.700 A response of type WSJ Jason response and will set response dot message equal to. 08:57.500 --> 09:05.330 Connected to server doesn't matter what it is, I just want to send something back and we'll write that 09:05.330 --> 09:05.960 Jason out. 09:06.290 --> 09:08.650 Now, in this case, I'm not going to write Jason using our own right. 09:08.660 --> 09:14.900 Jason function gorilla WebSocket has one that writes it in exactly the format that WebSocket requires, 09:14.900 --> 09:16.100 which is really convenient. 09:16.250 --> 09:20.480 We'll check Finnair W.S. Dot, right. 09:20.480 --> 09:22.730 Jason right there. 09:24.350 --> 09:26.200 And what we're going to write is just the response. 09:27.320 --> 09:28.550 And again, we'll check for an error. 09:28.550 --> 09:33.690 So I'll copy this error, checking logic and paste it in here. 09:36.800 --> 09:39.990 So now we've actually connected so let's get our connection. 09:41.210 --> 09:49.790 Corn is a sign the value of WebSocket connection and we'll just populated with corn, W.S.. 09:51.560 --> 09:56.210 And now let's put this connection in our map in our variable clients. 09:56.210 --> 09:59.510 So we'll say clients with the index of corn. 10:00.860 --> 10:03.380 And I'm not going to put anything in there, but it does require something. 10:03.390 --> 10:04.490 So I'll put an empty string in. 10:04.880 --> 10:10.880 Now, at the next point, we actually need to run something continuously in the background to listen 10:10.880 --> 10:12.480 for WebSocket connections. 10:12.860 --> 10:17.210 We've made our connection here right now, but if we get any information from the front end, we have 10:17.210 --> 10:18.020 to do something with it. 10:18.680 --> 10:23.660 So what I'm going to do is write the code for that and call a non-existent function, which I'll write 10:23.660 --> 10:24.320 in just a moment. 10:24.560 --> 10:25.160 Go. 10:25.190 --> 10:28.160 So this will run in the background as a go rooting app. 10:28.160 --> 10:34.640 Dot, listen for W.S. and I'm going to hand it a reference to my connection. 10:35.180 --> 10:42.260 OK, so let's write that function function with a receiver of app to application. 10:44.030 --> 10:47.300 And this is called Listen for W.S.. 10:47.300 --> 10:53.210 And it takes one parameter, which is I'm going to call Con and it's a pointer to WebSocket connection 10:54.110 --> 10:55.280 and it doesn't return anything. 10:55.490 --> 11:03.270 OK, now, because I want this to run all the time because that has to be an uppercase there. 11:04.010 --> 11:08.480 OK, so first thing, let's read the first statement and it's just a function. 11:10.370 --> 11:14.860 And this is simply to make sure that if something goes wrong, this application doesn't die. 11:14.900 --> 11:18.950 So we'll say if our Rickover. 11:21.390 --> 11:28.860 Our is not equal to nil, then I'm going to say after error log, dot, print line. 11:33.780 --> 11:39.000 Error, and then I'll tend to that format as print out. 11:44.050 --> 11:51.490 We are pinned down here, of course, because I'm deferring a function, I have to do that. 11:52.480 --> 11:56.260 So this will make sure that if something goes wrong, the application doesn't just crash and burn, 11:56.260 --> 11:57.550 that we recover gracefully. 11:58.390 --> 12:03.910 Now, let's declare a variable for what we're going to send back of our payload is equal to or is of 12:03.910 --> 12:06.330 type W.S. payload. 12:08.410 --> 12:14.950 And here we're just going to run a false statement that executes forever for and we'll say error is 12:14.950 --> 12:17.800 assigned the value of conduct read. 12:18.610 --> 12:24.050 Again, this is not the rejoicing that we wrote ourselves so many lectures ago. 12:24.070 --> 12:26.110 This is one that's built into guerrilla websocket. 12:26.260 --> 12:30.550 So we'll read JSON and we're going to read into Palit. 12:32.950 --> 12:35.960 We'll check for an error if error is not equal to nil. 12:35.980 --> 12:38.680 In this case, I don't want to do anything, so I'll just say do nothing. 12:40.750 --> 12:53.020 Otherwise, I'm going to say payload con is equal to a pointer to Kong and I'll send it off to the channel 12:53.870 --> 12:58.500 w chan receives pela. 12:59.980 --> 13:04.280 OK, so we sent it off to the channel, but of course, the channel is not doing anything. 13:04.390 --> 13:08.790 So now we need to listen to that channel and do something. 13:09.130 --> 13:14.410 So we're going to read a function that waits for input on our channel channel and then it takes the 13:14.410 --> 13:20.050 appropriate action based on the value of whatever action is in the WSJ in response. 13:20.200 --> 13:25.810 OK, so here, let's write another function and this one is called. 13:26.050 --> 13:32.410 Well, it has the receiver of Afropolitan application and this one is going to be called simply listen 13:32.410 --> 13:37.480 to W.S. Channel, which is exactly what it does and it takes no arguments. 13:38.750 --> 13:40.300 Let's give ourselves some room now. 13:40.300 --> 13:44.890 We only have one action we care about, but we're still going to be sending a response if our response 13:45.520 --> 13:46.210 is of type. 13:46.220 --> 13:48.100 W.S. Jason response. 13:49.030 --> 13:50.530 So there's a variable we can start in. 13:50.710 --> 13:53.070 And again, we'll have a fuller statement that executes forever. 13:54.850 --> 13:57.190 Now we'll get whatever was sent to that channel. 13:57.220 --> 13:58.420 I can call it whatever I want. 13:58.420 --> 14:01.210 I'll call it E for event. 14:02.320 --> 14:05.240 And that is populated from W.S. Channel. 14:06.970 --> 14:11.470 Now we'll switch based on the action and we only have one action, but nevertheless, you might be adding 14:11.470 --> 14:11.980 more later. 14:11.980 --> 14:14.200 And this is a simple way to handle multiple actions. 14:14.680 --> 14:18.070 So we'll use the standard switch statement and we'll switch on IDOT action. 14:20.020 --> 14:24.130 And our first case and our only case really is delete user. 14:26.360 --> 14:29.120 That's what we'll be sending for the case, for the action. 14:29.240 --> 14:35.980 OK, and a response to action is what do we want to do when we're sending a delete user action or we 14:35.980 --> 14:37.630 get a delete user request? 14:37.630 --> 14:38.800 We're going to say logout. 14:41.220 --> 14:50.520 That's what we'll be telling the end user to do and response that message will be equal to your account 14:50.730 --> 14:57.410 has been deleted and then we're going to call a function that doesn't exist yet. 14:57.420 --> 15:00.140 We're going to broadcast this to all connected clients. 15:00.180 --> 15:03.390 So I'll write this function in a moment, but I'll call it right now. 15:03.570 --> 15:11.430 App DOT broadcast to all with response as what's being sent. 15:11.860 --> 15:19.290 OK, and just to make things absolutely clear, what's going on, I'll put a default case in here and 15:19.290 --> 15:20.460 we won't do anything at that point. 15:20.670 --> 15:26.130 OK, so obviously the next thing we have to do is write this function broadcast to all. 15:26.280 --> 15:31.830 So thank receiver appointed to application, broadcast to all. 15:32.970 --> 15:42.630 And it requires one parameter response which is of type WSJ in response and it doesn't return anything. 15:43.530 --> 15:48.930 But we need to go through our entire list of connected clients and that's easy enough because we have 15:48.930 --> 15:49.530 that on a map. 15:49.530 --> 15:56.040 So we'll say for client, the current client is assigned the value of range through the map of clients 15:59.100 --> 16:04.050 and will now broadcast to every connected client. 16:05.970 --> 16:12.230 So error is assigned the value of, again, the client variable dot. 16:13.050 --> 16:16.170 And this has the same function that we used a little while ago. 16:16.500 --> 16:17.160 Right, Jason? 16:19.170 --> 16:22.800 And we're going to write a response, which I better spell right. 16:25.560 --> 16:30.330 If error is not equal to nil, just a simple error check and we won't do too much here. 16:30.780 --> 16:34.020 We'll just say after error log dot print line. 16:37.100 --> 16:38.060 I'll make a print of 16:41.030 --> 16:48.840 WebSocket error on percent X percent s, and we'll populate those two placeholders with response dot 16:48.860 --> 16:51.770 action and whatever the error was. 16:52.640 --> 16:58.220 Now, if there's an error in the vast majority of cases, that just means that this client has disconnected 16:58.220 --> 17:02.050 it, closed their web browser, they lost their Internet, Internet connection, whatever it might be. 17:02.480 --> 17:08.720 But in any case, I want to close that so well, ignore the error and close the connection close for 17:08.720 --> 17:11.300 client dot close. 17:12.830 --> 17:16.820 And then, of course, we want to remove that country from the map and we just use the standard method 17:16.820 --> 17:20.720 of doing that delete from clients, the entry, the client. 17:21.540 --> 17:29.750 OK, so there are all of the things we're going to need for two way communication between a client and 17:29.750 --> 17:31.490 the server over Web sites. 17:32.090 --> 17:33.530 But of course, there's one more thing to do. 17:33.540 --> 17:36.650 We actually have to start one of these go routines in the background. 17:36.650 --> 17:38.800 And we do that right in May not go. 17:40.070 --> 17:48.650 So at the very bottom, after we've declared this app variable, we can now call listen to WC channel 17:48.650 --> 17:50.120 and we want that to run in the background. 17:50.120 --> 17:57.210 So I'll just say go app DOT, listen to us channel and that takes no parameters. 17:57.500 --> 18:01.220 So now when we start our application, that will run in the background forever. 18:01.370 --> 18:03.270 Of course we need to set up a route to it. 18:03.290 --> 18:08.690 So let's go to our roots and we'll set up a simple route right here and I'll put it after the route 18:08.690 --> 18:09.520 to the homepage. 18:09.680 --> 18:14.210 It will be a get route, which is the norm for connecting to sockets. 18:14.510 --> 18:22.010 And I'll go to the requests and I'll call App Dot W.S. Endpoint. 18:22.760 --> 18:24.980 OK, so now we have a route. 18:25.040 --> 18:26.660 We have the necessary handlers. 18:26.660 --> 18:31.310 We have a means of upgrading our connection from a standard web connection to a WebSocket connection. 18:31.460 --> 18:34.370 And we have a means of pushing information to the end user. 18:34.400 --> 18:39.680 We also have a means of receiving information from the end user over the WebSocket, but we're largely 18:39.680 --> 18:42.200 going to ignore that except for the initial connection. 18:43.430 --> 18:47.510 But right in the next lecture will test things out and start writing some JavaScript.