NestJS SocketIO Online Presence
#JavaScript, #LearnToCode, #CodingTips, #WebDevelopment, #Frontend, #Fullstack, #Programming, #CodeNewbie
Video Summary
AI GeneratedThis video demonstrates how to build a real-time online presence system similar to Facebook Messenger using NestJS, Socket.io, and React Native. It covers the implementation of a hybrid microservice architecture to track user activity, manage friend lists, and provide instant visual status indicators (green dots) through bi-directional WebSocket communication.
We're going to create online presence in our Facebook Messenger application.
If a friend logs in, we'll update our friends list to show a little green circle next to their name
so we can determine if we want to send a message to them or if we want to call them.
If they're offline, perhaps we'll do a push notification to their mobile device.
But to create online presence, we need to have our NestJS
microservice and we need to extend it so it's a hybrid microservice because we're going to
create a web socket connection from our client to the server. So having a hybrid microservice
that allows that HTTP connection but it also allows us to interact with other microservices
is the approach that we're going to take here. So we're going to use Socket.io and Socket.io
is the library we're going to use. It manages the socket connection for us,
which underpins the web socket connection from the client and the server. And we're going to
have that connection and the socket ID associated with that. We can make requests if we log in,
if we log out, if we go off our application so we're no longer active. We want to have all of
those triggers to the server so it sends the request so that it updates which of our friends
are online, which aren't online, if we're online, if we're not online, and propagate that to our
friends list. I would like to start off by doing a demonstration of the online presence. So in the
Android emulator we're going to log in as John at gmail.com. We log in, it makes the request to
the server and after we're loaded in we can see that we can see our friends list here. So I've
got the same name but this is John2 and John3. So if I log in as John2 on the iOS we can see that
John2 has been updated to online and John1 has also been updated to online on here.
So we can also detect whether or not the user is active. For example if I go to the home screen
they're no longer in the Facebook app and you can see that it takes off the green circle
but if they log back in we can see that the green circle appears again next to their name.
Additionally if we were to sign out we can click the sign out button and we see the green
circle disappears and if we were to type in the email address to log back in
and we log in here you can see that when this loads to log in the screen circle has been updated here.
So let's go ahead and build this out. So let's start off with NestJS. The first thing we want
to do is we want to install three libraries at nestjs slash websockets socket io and at nestjs
slash platform dash socket dot io. Now it's important that you install the right versions
and the right versions are the same versions as the nest version you're on. So I'm on version
9.0 for the nestjs common here and you can see that the nestjs platform socket io
and also the websockets are 9.0.0. So if you don't have the right versions you may get some
mismatching types and stuff like that so it's important that you get the right versions.
So let's start off with setting up the hybrid microservice. So we've already created the
presence module a very basic bare bones nestjs module here. Now we're making it a hybrid
microservice because we need to connect to it from the front end through a websocket connection
but we also want to make microservice cores to other things in our system. So because of that
we want to have a port here we want to expose a port of 6000 and we're choosing 6000 because
four and five thousand and three thousand they're already taken. So we can just go to the main ts
file here and this is in the presence module here. So we just need to await and listen to 6000 so
we can listen we can start the microservices and start this as a microservice and also listen to
it as a regular you know HTTP open port. So we connect to the microservices in the same way as
before and we can access the config service and the shared service as needed and I've also got
this app.enabled cause here so we don't get any cause issues. So with that said let's come to the
presence module and let's just go ahead and import the shared module and we can go ahead and we can
register the auth service and we can access the environment variables for the RabbitMQ auth
service. So we've already seen this before and then we can also import the cache module
from nestshares common and we're importing the cache module in here and then we're going to
register it and then we also want the presence gateway so we haven't created that yet but we
will and we're going to have that located next to the module here. So we can go ahead and import that
and then we can add it as a provider and we'll see that in just a moment. Let's just add a
quick interface here so we want this active user interface we need a way to be able to tell
if a user is logged in or not so we need to make a web socket connection with socket io so
we need the id of the user we need their socket id and we also need a flag to be able to determine
if they're active or not and then most of the work is just in this presence gateway here
so we can see that it's just a class we're exporting a class and we're calling it a
presence gateway and all it's got in it so far is a empty constructor so it needs an annotation
it needs the web socket gateway and the web socket gateway and many of these socket related
things are coming from nestshares web sockets here and we've got this cause to true so we do
have the cause enabled in the when we're instantiating the server but you know web
sockets they build up on the http protocol and just because there's a couple of extra
steps involved with web sockets compared to regular http requests we need to add in this cause true
here as well so what we want to do is we want to implement the on gateway connection and on
gateway disconnect interfaces which come with their own methods and essentially what we want
to do is because we've got the auth service you know we want to protect a few things we want to
use some of the auth service to get some user related data so we just go ahead and we inject
it and because we've declared it in the module we can inject it like this and then we can get
our auth service which is the client proxy from the nestshares microservices
and we also want to inject the cache manager and we're just going to call that cache now note in
the previous video we've set up or we showed how we could do some redis caching and we showed in
particular in memory stuff we will be doing in memory stuff for determining if they're online
or not and we're going to circle back to redis but the reason i'm not including it here is
because i was intending to use redis as a persistent data store so it can store all of
our messages so just to avoid confusion between the two types of redises you know in memory or
persistence i'm just going to use the regular in-memory cache and then i'm going to circle
back to it so i'm not sure if that's more or less confusing but hopefully it simplifies things if
you just click on this video and you watch the previous one i'll put a link here to the previous
one though if you want to check that out because we'll circle back to redis so basically what we
need here is we need this annotation the at web socket server which is of the type server
and that's coming from socket io and i probably should mention that the cache is coming from
cache manager and basically this is going to allow us to we're going to need to push stuff
from the server to the client so we're going to need access to the server and then a socket
id so the client connects to the server and they get a socket id that socket io generates
which is a unique connection and we're going to have some authorization stuff so authentication
so we need to get the json web token to secure our routes so basically we want to start off by
having this handle connection function and this comes from implementing the on gateway connection
and there's also a disconnect one for the on gateway disconnect and basically all these
functions they take the socket so basically when you connect from the client the client will
automatically sort of connect and have the socket id connection and it passes it to that so all that
heavy work is sort of done by the library itself and then we can just go ahead and handle the
connection so as mentioned we want to be able to get the json web token and we access this a little
differently to the http method or microservices methods that we've seen before because we have
this socket handshake the handshake from the client to the server and that generates some headers
and the headers more associated with that handshake they have the authorization header so
we send the request and we'll see on the front end how we attach that but essentially we're
attaching the json web token and if it's not there well then it's just null basically
so that means we can have this check now we're going to create this handle disconnect
which implements this on gateway disconnect similar function here so it takes the socket
and then we're just going to return because if they don't have the json web token
you know they're not going to be able to make the connection now they should have the json
web token if they're able to make the connection in the first place but this is just an extra check
so what we can do now is basically what i'm doing here is previously we've seen how to use
you know promises i just wanted to sort of you know show how we can do it with the observable way
and that's because when we use this auth service to send to decode the json web token so we're
calling a microservice from the auth service which gives back the user json web token type here
if we just pass in the json web token so basically this is an observable
so conventionally we just attach a dollar sign to the end to signify that so i have shown how to do
this without this way in previous videos but just wanted to mix things up a little bit so basically
what we can do is we can take the first value from the observable because i'm returning one value
and then i just got this catch on here so you can actually mix and match the
observables and the catches and stuff like that you could also use a pipe operator
to catch for things but just to simplify things i just want to get the response here which is
hopefully going to be the user json web token so basically i just check to see if we actually get
that and if there's a user associated with that otherwise we just disconnect but if so we just
use object destructuring to get that from the response and then what we can do here is because
we got the socket for this particular connection on that socket we can add some data we can add
that user data to that socket which means when we use the socket in other places we'll have access
to that user and they'll be there uniquely because it's only for the particular socket that's
connected and then what we can do is we can await this set active status so you pass in the socket
and if they're connected we're going to update their status to true and we're going to see how
that comes into play in just a moment but just to implement the disconnect handle disconnect which
also takes the socket basically what we'll do is we'll also call this active status but send
the active status to false so let's create the active status now i've just made this a private
method because i'm only going to use it within here so essentially this is a helper to these
main functions here basically it's going to take the socket and whether or not it's active which
is just a simple boolean and now that we've attached the user to the socket data we can get
that now if for whatever reason it's not there we'll just return out of the function and then
we can go ahead and construct a active user object so we get the id and then from the socket we can
get the id as well the socket id that is and then whether or not it is active or not so that's
a flag we're passing in and then what we can do is we can just set the cache and i'm just using
user whatever so if they logged in as user one they'll be user one and then you just pass in
this active user object and then if any of time this updates in the future you'll find this for
the same key that is if it does if the key doesn't exist we'll just create the first one but if the
key exists we'll just override it so that's how we use the cache to determine if they're logged in or
not and this final parameter here or this final argument zero this is the ttl time to leave
basically by default i believe you know you don't want things in the cache forever
usually it's like a five second thing so if you hit an api endpoint and then you hit it again
if there's no unique information to give back they'll cache for that long but zero it represents
infinity basically so we want this to be cached in memory indefinitely so after we've set that
we can go ahead and well now that we know that we're logged in or we're not logged in
we need to emit that to all of our friends so it's one thing to know that whether or not we're
logged in but everyone on our friends list needs to be aware of that so then they can have the
online presence updated so let's create the helper function get friends so this get friends
helper function is going to work off the particular user that made the request so if i make a request
i want to be able to get all my friends so basically we'll do this in a similar way
so we've already created this get friends function so we can just call that microservice
the auth microservice and we're expecting a bunch of friend requests back
call the command get friends if we pass in our user id so basically the friend request that we
get back you know we want the first value from the observable and then if there's any errors we'll
just go ahead and catch that i do have another video on error handling if you want to go into
more detail about that so if there is no friend request just simply return so what we need to do
here is we need to get the friends from the friend requests so the friend requests they have
they have both the creator and the receiver so what we want to do is we just want to map
through our friend request and for every friend request we can determine if the user is the creator
or not and that's dependent on if the user id that's passed in matches the creator id
so basically the friends the the details that we want
recall that both the creator and the receiver details are both there an object we don't want
our own details we just want to determine the other person's details so if the user's the creator
well we can get the receiver but if the user isn't the creator we can go ahead and get the creator
so basically we're just getting the information i think i've covered that in a previous video
but yeah so basically the constant id we want to use object destructuring to get the id first name
last name and email from those friends details and then because we're in a map here we just want
to return those particular ones so yeah again if that wasn't clear the friend requests they have a
one-to-many many-to-one sort of thing where each friend request has a foreign key associated with
a user and it has both the creator user and the receiver user so depending on if you're the creator
or the receiver depends on which part of that object you want back and essentially you just
want the opposite to what you are because if you were the creator you don't want the creator
information back because that's your information so we want the receiver information back otherwise
if we're not the creator then we want the creator's information because that will be the
corresponding friend it just comes in pairs so we just return those friends there so what we can do
now is now that we've gotten the friends we need to loop through them and we sort of need to
commit to that through a socket connection if they're active to update their details so we can
get the friends by calling that method we just created and just passing the active user id
and then we have this loop here so for f of friends or friend of friends we can go ahead
and get the user from the cache so based on their friend id you can get the user
so it's perfectly possible that the user doesn't exist in cache at the moment because they may
haven't logged in before on this particular application so if that isn't the case we just
continue to the next iteration of the loop but if they are we just cast the friend to the
user to the active user type which is going to be the friend which is why i haven't used
friend here and basically this is how it works in websocket connections we have access to the server
and we want to send something to the client so if you're on the server and you use the to method
that's sending it to the client and the way you send it to the client is through the socket id
because the client has made a connection with the server and there's a socket id associated with that
and that means the server and the client are both listening for one another so if you send it
the request to the server i'm sorry to the client from the server there's this emit method
and basically you have this tag here so on the front end we can listen for this tag from this
connection so it means that even if someone had your socket id for somehow which is pretty unlikely
but if they if there was some leak in your application they'll still need access to
right tag to be able to actually send a request because that's what you're listening to on the
front end so basically to that user if you log in to your friend you want to say well here's my id
and here's whether or not i'm active or not because when they log off for example or they
aren't active they step out of the application for example and this will still run so this can
be both true or false and they'll update in the ui respectively or not respectively
after that's done so basically we want to have another check here because this updates it for
the other person for your friend but let's say like for example your friend list if someone else
if you log in you need to be aware of other people that are already logged in for example
so basically what we can do is for your friends if they're logged in so they access the cache
and if it's active you can say well okay i can have this socket connection to myself basically
to let them know well to let myself know which of my friends are active so if the friends are
active i'll be able to get that information and i'll be able to use that to display the green dot
on both the person's friends and also the friends of the person so one of the final steps here is
well how do you do that if so that's all well and good if they connect or disconnect
because of setting the active status but what happens if they don't sign out like let's say
for example they click off the app but they don't close it we want to say that they're offline in
that case and we want to show a green circle if they're online and active so they're signed in
and they're active meaning they're on our application they're not on another application
on their phone that's why we have this annotation here so update the active status which is what
we can admit to from the front end and we'll see that in just a moment
so we just have this async update active status function it takes the socket and takes the is
active boolean if there's no user for whatever reason we just return out otherwise we can set
this active status to whatever it is and then they'll get handled in the same way
so finally i just got this note here in development because i'm setting the cache
to zero which means infinity i'm just resetting the cache you know when i start the server i just
got this note to remove this in production and we'll probably see this get changed anyway in
something like redis so yeah let's have a look at the front end and so let's work on the react native
front end so we need to install the socket.io client package to interact with the socket.io
backend that we've created here so make sure you run an npm install of that library and then we'll
start by looking at our auth context so basically what we want to do here is we need to be able to
tell if the user that's logged in is active or not and we have a boolean for that so we just come to
our auth context and add that in and then we also add it to false by default because by default
they're not logged into our application so i'm defining active as being both logged in
and on the application so basically we have this use ref that we're using and we can use ref
to get the app state which just comes from react native here and we want to say well the app state
is whatever the app state is which is the current state because react native has a way to better
determine if you're on the application or not and we're going to use that to
you know let our friends know if we're active or not so we can have a bit of state here
and by default we're going to just say app state is visible
because we're using a ref here so we want to use that and use some state off that so we
don't want to get into any issues relating to the ref state that associated with the ref
not updating so we're going to have a bit of state instead but we still need to access the ref
to get this current state so what we're going to do is we're going to have a use effect book
and essentially what we're going to do so this happens basically when the page loads or our
application when we open our application because we've got this lifecycle method equivalent to a
constructor here with no dependencies so basically what we can do is we can say okay well for the app
state that we're getting from react native we want to add an event listener and whenever it
changes we want to be aware of the next app state which is what this gives back so we'll have a
subscription here we'll have a variable here because you know we won't want any memory leaks
we want to you know undo that if we get out of the application although it's probably something
that doesn't actually fire but nevertheless if we have the app state we can set the current value
to the next app state so this doesn't work very well with refs so we have this new state here
where we can do this normally you wouldn't want to mutate things but this just makes things a
little bit easier for refs in particular and i've just copied this from the react native documentation
as well so they seem happy with that so i'll just go along with that and then you can set the app
state visible to that app state current and then basically we just have a return to clean up the
subscription and we can just remove that which is exposed by the library that we've used there so
basically all that's happening here is we're saying well we're setting the app state visible
to whatever it is so if they're on the page it'll be active if they're not on the page you'll be
inactive and then we're going to make use of that by essentially letting the rest of the application
be aware if it's active or not so we're defining active is
both the app state being visible to or that state being active which means they're on the
application and they're not on another application on their phone
but they have to be logged in as well so that's all we're doing here
so we can come to defining an interface so we've seen user details already in the previous video
just to step into that the user details is just the id first name last name email
that's what a friend is going to be but we want to also in addition to that know if they're active
or not now this is going to come from a web socket connection not the http or api or microservice
request so we're just going to amend this is active property here
so we also need to be able to make the get friend requests so we've seen that method
in the previous one but here we're just interacting with it from the front end
so basically we just want to get our friend requests by getting our friends
note that we're not this would probably be a better name to get friend requests
but the api at the moment is just get slash friends and the main reason is because
we've set up well i have previous videos in the linkedin clone series about friend requests
friends friend management going to a profile adding the friend all that sort of stuff i
didn't want to duplicate that here so if you do want to go into much more detail about that
check out that video otherwise we're just doing this simply just to have dummy friends in our
application that we can contact so we just make this api for here pretty simple so one more model
or interface that we have here is the in the people folder i've got these models here
and a friend request is just going to be the id creator and receiver so we've seen that before
and then get friends now this is a helper to change the get request
i sorry the friend request into friends so i've seen this in the back end since i got
into places it probably would have been slightly better just to give back the data but again i
didn't want to go into too much detail about the friend management stuff so i just copied that code
here so you can just copy that from the front end and copy it in here so that's just getting the
friend requests mapping through them and you know giving back all of the friends so
this leads us to friends context so basically we want a provider around our application because
we're going to need to know the friends in multiple pages for instance and stuff like that
um so we want to know if they're active or not so for example if you make a chat from the chat
screen or you want to go to the people screen and stuff like that uh we want to have that
information so we create this provider and that's just going to wrap around other um you know jsx
or tsx um dom elements so we just wrap it around the children which is just react node
just like the other providers um so we want to return the friends context which we're yet to
create um dot provider and the values we want to give back is well we want to give the friends back
um with the active state or not and we want to know if they're loading or not because if the
friends are loading well we can't really do much with the friends until they're loaded so we need
to show a loader um so what we do is we start off by and we we also need some to use the context from
auth context um because we need to know things about the current user and if they're logged in
and they face some web token and if they're active so the auth um if you look at the app here we can
see that we're going to have the auth provider and then we're also going to have the friends
provider so the friends provider can use information from the auth provider so um we can use that
context there now we're making a web socket connection we're making a connection to a
hybrid microservice um which means um and we've exposed that presence microservice hybrid
microservice i should say um so it has access to the http protocol requests or connections
uh on that port 6000 uh i'm using an emulator so for both android and ios um ios lets you just
use the localhost 6000 but android emulator doesn't so you just need to prefix the port with
this 10.0.2.2 um and if this was production then you would want to just um you know show your
production url there um so basically what we want to do is we want to use the socket io client to
um essentially um so in the friends context we want to um have the connection to the server
um so we can do this and i put this in a used memo hook um because basically we just want the
outcome of this and it's only going to be different if we you know we log out and we
log into a different user we have a new json web token um and i've just chucked the base url in
here so it didn't complain although this is constant um so essentially if you log out and log
in well okay then you need a new connection but other than that you don't need a connection
um so i'm using this used memo hook just to avoid any re-renders now i'm not actually sure i haven't
looked at the source code for socket io library it could be based on the singleton pattern for
example which only lets you have one connection um but just to ensure that and ensure we don't
get any re-renders i'm just gonna do this to avoid uh reading the source code of the library
um so basically you can just pass in the base url um and we've got these transport options so
these transport options these let you add extra headers for example so it's nested in this polling
um method oh sorry um i don't know what this is object property name uh and then extra headers
and then authorization so it's quite a bit of nesting to get there but that's just the way the
options are exposed by the socket io client so you just you know you got to follow their
documentation to do that and then because we have a authenticated route meaning we need a json web
token to make the request as we see in the back end um setup we have this friend context within
the auth context and we can make use of the json web token so then when we make the web socket
connection we'll have that json web token attached so we can securely make our connection um
so basically from here this is where we want to use the socket connection to you know receive or
give uh commands so emit basically emit means send to um so we can emit to the server this update
active status and if you're a core if you look at the visual studio code we have this subscribe
message here so from the client we can actually send a request to the server it will look for
that tag and then if the socket matches and all well is good um you know then i'll set this active
status so um we're just passing if they're active or not um and then there's also this socket on so
this sends a request to the server uh and then the server will do something um socket on is it's
waiting for something from the server um so if i look for um let's see probably this
omit status to friends for example we can see that um we have this friend active
uh command so the server can actually send information to the client as well it's not
it's bi-directional these web socket connections um so if we have the socket id
um we can emit to the front end based on this tag here if you know for this case we're sending back
uh information relating to who's online or not online so they can update so you know the front
end needs to be constantly listening to that so because there's a web socket connection between
the front and the back end when that particular event occurs um it can be identified by this tag
here and then we're getting the id of the user and whether they're active or not back um so with
that information what we can do is we can set friends so we'll need to have some state for that
um basically we're going to have all of our friends um now if there's no id associated
with the user details for whatever reason well then we'll just return the previous friends
um oh sorry um if the user id so the if the user id that you're logged in with
um if that's not equal um to the id that you get back or if that is equal it means that
it's the request is being sent to yourself and we do use that um for example if you log
in and then somebody else logs in that second person that logs in needs to be aware of the
first person that logs in so there needs to be a way to be able to determine for them to update as
well um and we do do that um but on the front end we don't have ourself in our friends list so
there's no real needs we just exit out of it um but otherwise we take the updated friends
we find the friend on the id and then we set is active to whatever um i've just renamed this
the is friend active to avoid conflict between variable names but essentially if you get
a friend that's not yourself um you want to update that friend in state on the front end
and use that and then we have this socket um emit update active status default so this is a
cleanup function so when the app closes or whatever web socket connection ends um you know because
we're storing things in cache and we just want to say well for our user that we're logged in as
we're no longer logged in and we because we've also got this like constantly listening method
here for the constantly looking for the friend active avoid any memory leaks or anything like
that we just turn that socket off um so we are creating a provider here the friends context
that so we can use in other places in the application um so we just create this interface
i call it i friends context um just so you don't clash with the name friends context here
which is essentially just an array of friends the active friends so the friends with the active
state uh and then is loading to determine if the api request is loading the friends
and then we create the context based on that type there and these are the initial states
and empty array and false then we just have a little bit of state here for the friends
and setting the friends which we've set in here um and also a bit of state for if it's loading
and the ability to set if it's loading now we actually get the friend request so we start by
using use query and we'll have a key called friend request um which is an async function
um now we're only going to call that if we're logged in of course we should be logged in by
this stage we're just having an extra check um when this react query api request is finished
or if it's failed we've set loading back to false um when it starts we set loading to true
um what we want to do is we want to await the get friend request so we saw that
friend request before and then we just want to adapt it by passing into the get friends
helper method i'll just put this underscore friends to signify that well for two things
one it doesn't clash and one it's in the private scope of this area here
um so you can just pass those friend requests and the user details in now the user details will be
defined by this stage because we're only enabling this if it's logged in um but i don't think
typescript's that smart in this particular case love typescript but um you know it doesn't know
everything um so active friends well we've got active friends array we loop through all our
friends um and then we just add this is active false here potentially this could have been done
in here as well but just to keep it same as the front and back end i've separated that
um and then we can just go ahead and set the friends and you know return the friends um
returning it so that it stays in the state if we need to access it like that although we've
got it in the context here um so yeah that's the friends context and of course we're just
giving those back so if we take a look at friends here i think previously this is very similar to
how it was on the pages um so i've gone to the people page and the chats page and i've just
copied and pasted the code and i've just used this friends here because it's very similar
it's just in one place we want to show a message and in other we don't
i've just sort of refactored that into this friends here i just copy and paste everything
um so this shouldn't look too dissimilar uh to what it was um i've just added this logout method
um to the friends which conditionally runs on if show message is not so that's not actually
you know semantic code that's just to help us log out and log in to demonstrate
um you know the application um so basically you know we just have the container loop for
all the friends and we show that um and then we have this show message prop here so that's
the only real difference here um i've also just added the loader i think it was white before
um so i've just added the color black so if i've added dark to the loader which i have here
um you know i've just done a ternary to display that because when you log in and it's a blue
background you want a white loader um so that's essentially that and also the colors i've just
added one more color here uh the green the green for the actual um you know the circle to say if
they're online or not and then i've just have this friend here this friend component here
so this is all similar uh it's just now friend we can get is active we can use destructuring from
that um so the only thing we're adding here is you know if they're active um you know show
the avatar icon um so basically i've sort of uh sort of styled this myself
uh sort of like a hybrid between using this and um hot um custom styling um but this is just the
green circle you see uh in the bottom left there so if i open this uh simulator here you can see
them online on both of them and then you got this green circle here and then if i click off click
back on see everything's working nicely still so yeah that's essentially that so that's online
presence thanks so much for watching guys we're going to use the online presence to be able to
use um chat because depending on how you if you're online or not if you're online you can use web
socket hybrid microservice um to create a chat room so that'll be exciting um but if they're
offline you can also push notifications uh and it's also similar to the calls as well if they're
online you can make the call if not maybe show a push notification or something like that
so make sure you subscribe so you can stay tuned for those exciting videos
uh and thanks so much for watching cheers

