So as I suggested last time, we're going to use WebSocket to fire off a message to the users saying,
hey, your account has been deleted and we'll log them out automatically.
So to do that, we need to import a package.
And the package I'm going to use and I'm going to my Web browser is right here.
Gorilla WebSocket.
It's widely used.
It works really well.
And it takes much of the heavy lifting out of the equation when working with WebSocket.
Installation is pretty simple.
It's right here.
So let's copy that.
Go back to Visual Studio Code, open a terminal and paste that in and that should add it to our go modify.
And it did.
So now I'm going to put all of the logic for working with WebSocket right in the Web application.
So in CMD Web.
And I'll create a new new file here called Eustache Handlers for WebSocket Handlers, Dongo.
And of course, that's package.
Now, the first thing I'm going to do is set up some types because we need to communicate with the front
end.
We need to send information off to the connected client.
So the first thing I'll do is create a type which I'll call WebSocket connection, and it's a struct
and it only has one member.
And the member is a pointer to WebSocket.
And I want to make sure I get the one for gorilla right here.
Not this one x net slash websocket which works, works really well, but it would require a lot more
coding and this one takes care of a lot of the heavy lifting for us.
So we'll import that WebSocket dot com and that imported gorilla websocket for me.
So there's my first type that holds the WebSocket connection.
The second type is a payload and it defines the data that we're going to receive from the client.
Now, in all honesty, in this course, we're not going to receive any information from the client.
I'm only interested in pushing a message off to the user saying, hey, user ID X has been deleted.
But since we're writing this anyway, and at some point in the future, you might want to communicate
from the your web client, from the connected client to your server mail will set that up.
Now, it's not hurt.
So I'll create a type called W.S. Payload and it will be a struct and we're not really using it.
So it doesn't matter what I put in here, but I'll put in the things I normally put in.
So I'll put in an action which will be a string.
And in JSON I'll call that action and I'll duplicate that a few times.
I might also want to know things like what's the message they're sending me?
And in JSON, I'll call that message.
And again, we're not using these that I'll have what's the username?
And I'll export that which I'll call username.
Then I might have message type.
Which will be message underscore type.
And finally, what connection am I and that is of type WebSocket connection and in Jason, I'm not going
to send that at all.
OK, so let's format this now.
The next thing we're going to need is a variable and it's a verb.
And I'm going to call it upgrade connection.
And I'm calling it that because when you connect using WebSocket, your connection, your connection
to the Webs Web server is actually upgraded to a two way communication.
So this is a type that's equal to WebSocket DOT upgrader with the R at the end and we'll populate its
members.
So we'll say read buffer size.
Just put something that makes sense in their read buffer size and I'll make that ten, twenty four which
is fine.
That's a good default.
And write buffer size will also be ten, twenty four which makes sense and is going to cover almost
every use case.
Now this one check origin, I'll make that a function that simply returns.
It takes an argument are pointed to HDP don't request.
HTP done request, which apparently won't have to manually impart, but that's OK and it returns a ball
and it's only going to return.
True.
Now, checking your connection, let me import that again.
Let's try this again, HTP.
There we go.
So that should have imported it.
It did.
This is how you secure your websocket connections.
And since we're not actually receiving anything from the front end other than your initial connection,
we don't care about this.
So we're just going to have it return.
True.
But if you want to lock down, if you are communicating from your Web browser to the server, you're
going to want to do some actual logic in there.
But this is sufficient for our purposes.
So we have that variable.
Now, I'll put another type in here, and this is the one we are going to use for sure type was Jason
response.
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
make a string and adjacent we'll call that action and we'll duplicate that.
We'll have a message
which which will also have a JSON value of message.
And I'm also going to put in there the one that's critical in our case, user ID, and that will be
in it and in JSON will call that user underscore Edem.
So what we're going to do is we're going to when someone's user account is deleted from the user's table,
we're going to populate this with information, including the user ID, and send that off to everyone
who's connected.
And if the user ID that is sent matches the user ID that's in the session for the connected user, we'll
just log them out.
That's all we're going to do here.
OK, we also need to keep track of every client who is connected.
So we'll carry another variable, which I'll call clients and it will be equal to make a map.
And the key will be a WebSocket connection and the value will be a string.
OK, and we're also going to use a channel and will push to the channel any time we want to receive
information, for example.
So we'll create a channel, W.S. Channel for WebSocket Channel, and that's equal to make.
Can W.S. payload.
OK, that's we're going to be sent.
That's that's what the channel will take his payloads.
Now let's create a function which is a handler and it takes the receiver of appointer to application
as usual.
And this one is going to be called the WC End Point.
And because it's a handler, it takes a response writer and a pointer to a request
and also give ourselves some room here.
And the first thing you do is upgrade the connection.
So when this handler is hit, when a request comes in from JavaScript, of course, on the front end,
we need to upgrade the connection.
So I'll create a variable W.S. for WebSocket and we check for an error.
And that's a sign the value of our upgrade connection upgrade.
And it requires three parameters.
The response, Frater, the request and the third one I'm just going to set to nil because we're not
using it in this course.
And then a lot of cases you don't use it anyway.
We'll check for an error.
If error is not equal to nil, then we'll just log it.
APTA error log, print line the error and I'll return.
At this point, I don't want to go any further, but assuming we've upgraded the connection properly,
let's just write some information to the log after info log dot print line and in here I'll put format,
format, print F and I'll write client connected from percent percent s and will replace that with our
remote address.
Just so we know that someone is actually connected, we can make sure that things are working and let's
create a variable to send some information back to them.
A response of type WSJ Jason response and will set response dot message equal to.
Connected to server doesn't matter what it is, I just want to send something back and we'll write that
Jason out.
Now, in this case, I'm not going to write Jason using our own right.
Jason function gorilla WebSocket has one that writes it in exactly the format that WebSocket requires,
which is really convenient.
We'll check Finnair W.S. Dot, right.
Jason right there.
And what we're going to write is just the response.
And again, we'll check for an error.
So I'll copy this error, checking logic and paste it in here.
So now we've actually connected so let's get our connection.
Corn is a sign the value of WebSocket connection and we'll just populated with corn, W.S..
And now let's put this connection in our map in our variable clients.
So we'll say clients with the index of corn.
And I'm not going to put anything in there, but it does require something.
So I'll put an empty string in.
Now, at the next point, we actually need to run something continuously in the background to listen
for WebSocket connections.
We've made our connection here right now, but if we get any information from the front end, we have
to do something with it.
So what I'm going to do is write the code for that and call a non-existent function, which I'll write
in just a moment.
Go.
So this will run in the background as a go rooting app.
Dot, listen for W.S. and I'm going to hand it a reference to my connection.
OK, so let's write that function function with a receiver of app to application.
And this is called Listen for W.S..
And it takes one parameter, which is I'm going to call Con and it's a pointer to WebSocket connection
and it doesn't return anything.
OK, now, because I want this to run all the time because that has to be an uppercase there.
OK, so first thing, let's read the first statement and it's just a function.
And this is simply to make sure that if something goes wrong, this application doesn't die.
So we'll say if our Rickover.
Our is not equal to nil, then I'm going to say after error log, dot, print line.
Error, and then I'll tend to that format as print out.
We are pinned down here, of course, because I'm deferring a function, I have to do that.
So this will make sure that if something goes wrong, the application doesn't just crash and burn,
that we recover gracefully.
Now, let's declare a variable for what we're going to send back of our payload is equal to or is of
type W.S. payload.
And here we're just going to run a false statement that executes forever for and we'll say error is
assigned the value of conduct read.
Again, this is not the rejoicing that we wrote ourselves so many lectures ago.
This is one that's built into guerrilla websocket.
So we'll read JSON and we're going to read into Palit.
We'll check for an error if error is not equal to nil.
In this case, I don't want to do anything, so I'll just say do nothing.
Otherwise, I'm going to say payload con is equal to a pointer to Kong and I'll send it off to the channel
w chan receives pela.
OK, so we sent it off to the channel, but of course, the channel is not doing anything.
So now we need to listen to that channel and do something.
So we're going to read a function that waits for input on our channel channel and then it takes the
appropriate action based on the value of whatever action is in the WSJ in response.
OK, so here, let's write another function and this one is called.
Well, it has the receiver of Afropolitan application and this one is going to be called simply listen
to W.S. Channel, which is exactly what it does and it takes no arguments.
Let's give ourselves some room now.
We only have one action we care about, but we're still going to be sending a response if our response
is of type.
W.S. Jason response.
So there's a variable we can start in.
And again, we'll have a fuller statement that executes forever.
Now we'll get whatever was sent to that channel.
I can call it whatever I want.
I'll call it E for event.
And that is populated from W.S. Channel.
Now we'll switch based on the action and we only have one action, but nevertheless, you might be adding
more later.
And this is a simple way to handle multiple actions.
So we'll use the standard switch statement and we'll switch on IDOT action.
And our first case and our only case really is delete user.
That's what we'll be sending for the case, for the action.
OK, and a response to action is what do we want to do when we're sending a delete user action or we
get a delete user request?
We're going to say logout.
That's what we'll be telling the end user to do and response that message will be equal to your account
has been deleted and then we're going to call a function that doesn't exist yet.
We're going to broadcast this to all connected clients.
So I'll write this function in a moment, but I'll call it right now.
App DOT broadcast to all with response as what's being sent.
OK, and just to make things absolutely clear, what's going on, I'll put a default case in here and
we won't do anything at that point.
OK, so obviously the next thing we have to do is write this function broadcast to all.
So thank receiver appointed to application, broadcast to all.
And it requires one parameter response which is of type WSJ in response and it doesn't return anything.
But we need to go through our entire list of connected clients and that's easy enough because we have
that on a map.
So we'll say for client, the current client is assigned the value of range through the map of clients
and will now broadcast to every connected client.
So error is assigned the value of, again, the client variable dot.
And this has the same function that we used a little while ago.
Right, Jason?
And we're going to write a response, which I better spell right.
If error is not equal to nil, just a simple error check and we won't do too much here.
We'll just say after error log dot print line.
I'll make a print of
WebSocket error on percent X percent s, and we'll populate those two placeholders with response dot
action and whatever the error was.
Now, if there's an error in the vast majority of cases, that just means that this client has disconnected
it, closed their web browser, they lost their Internet, Internet connection, whatever it might be.
But in any case, I want to close that so well, ignore the error and close the connection close for
client dot close.
And then, of course, we want to remove that country from the map and we just use the standard method
of doing that delete from clients, the entry, the client.
OK, so there are all of the things we're going to need for two way communication between a client and
the server over Web sites.
But of course, there's one more thing to do.
We actually have to start one of these go routines in the background.
And we do that right in May not go.
So at the very bottom, after we've declared this app variable, we can now call listen to WC channel
and we want that to run in the background.
So I'll just say go app DOT, listen to us channel and that takes no parameters.
So now when we start our application, that will run in the background forever.
Of course we need to set up a route to it.
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
to the homepage.
It will be a get route, which is the norm for connecting to sockets.
And I'll go to the requests and I'll call App Dot W.S. Endpoint.
OK, so now we have a route.
We have the necessary handlers.
We have a means of upgrading our connection from a standard web connection to a WebSocket connection.
And we have a means of pushing information to the end user.
We also have a means of receiving information from the end user over the WebSocket, but we're largely
going to ignore that except for the initial connection.
But right in the next lecture will test things out and start writing some JavaScript.