It has taken alot of persistance to get my persisting data to work!
Redis has been on my to do list for about 3 weeks and despite following a series of different tutorials, reading docs and generally just trying to immerse myself in it in hopes that something might click, today is the first day I feel like I am beginning to (very weekly get a handle on it).
A continued source of frustration for me is JavaScript’s logic. As much as we try, JavaScript and I can’t get on the same page. I ask it “How can I tell you to print a list before it even exists?” and it replies something along the lines of “error index.js 64”, which I have come to understand means(in this context): “Why are you trying to print that list there, you fool! You know it has to happen on connection! Just put it where it needs to go!” And then we fight. And since I am petty these arguments tend to end with me smashing the keys of my keyboard like an enraged monster.
Although, I am not nearly strong enough to Hulk Smash anything, it does end it anger and frustration. This issue only gets magnified when we start doing more complex things and is something that I need to be conscious of while learning and practicing. Through the help of Gavin Umha, Tomek Niewiarowski, and Code School I am beginning to have a better grasp on the importance of placement of commands in order to make something work.
So my goal: Create lists of history for the messages to be stored in Redis and printed out when a new user connects.
In order to be able to understand how lists work, it is important to know that Redis works in key-value pairs. This means that we can set a property to be a certain value.
For example: I think the best song ever is Annie Lennox’s “Walking on Broken Glass” , so I can set the property “bestSong” to “Walking on Broken Glass”.
Note: the “set” command in Redis is very similar to creating a new variable in JavaScript. This means that the property name can be set by you and the song can be set by you. However, in order to access that variable later you have to use the property name you have set. (This should be intuitive but for me, it continues to be an issue).
By setting the property “bestSong”, we have now stored the value! But its useless stored if we don’t ever use it… that’s just hoarding! So next we need to be able to access it. Redis has to get the key from the client and log it.
One thing that is great about Redis is that it can do more complex things than a simple key-value pairing. For my chat I want to be able to create a history log, so when a new user connects, they can see what people are talking about. This allows the new user can jump into the conversation without having to bother the current users to get them up to speed.
So I want to add persistence to the live-chat which can be done by using lpush. This will mainly be done in the chat index.js file:
Boxed in blue is the code we will be focusing on. io.on is the server listening for connection and what code follows is what happens when a connection is made.
lpush is similar to the ‘set’ except it is for multiple sets of data. lpush allows you to insert variables into one key so that you can access them all at once. In this case, we want to create all the messages to be remembered as a variable ‘history’ (this could be any variable you choose as long as you are consistent). One problem that I consistently have is where commands should be put but once I know it seems simple, so I will try and explain it as much as I can.
We want to push the incoming messages into a list as they come in. So this command should happen at when we listen for incoming messages.
We can just add the lpush command in here by asking the client to push the message variable to the key we’ve labeled ‘history’. Just like in sets, we create the key in the command.
Now we have the messages logged in a key called ‘history’. But just like set and get, we need to use a command to retrieve the messages that we have stored. This command is lrange. lrange returns the specified items from our key (in this case our key is ‘history’). We want the history to be printed whenever a new user connects on. We also want to ask the new client their name before we give them the juicy details of the previous conversation. So we should put the lrange command in the join function like so:
I know this is confusing because it doesn't make sense to emit a history before any messages have been sent. It seemed like a philosophical chicken/egg conundrum. JavaScript, however, assures me it isn’t. Despite a series of screaming matches, I have come to be understanding of JavaScript's point of view. There is no history until the messages are sent, and once they become history, then we can start emitting them to new clients. Regardless of whether there is history to be sent or not, the time at which we want to send it is when a new client connects.
So it is agreed, we will add our lrange command into the 'join' function. Once again, lrange returns the specified items we have stored in our key ‘history’. This means we must specify which items we want our lrange to return. First, just like ‘set/get’ we have to specify what the lrange command is retrieving:
Note: In this example we ask to return all the elements in the list using (0, -1), but we could choose to only return certain elements such as (0, 3) which would be the first 4 elements saved in the history key.
Now we need to log it to our console and emit it to the newly connected user. We use the socket.emit command rather than the socket.broadcast.emit because the broadcast command sends the message to everyone except the newly connected socket (and that is silly because we want it to go only to the newly connected socket!).
Perfect! We’re almost done. We just need to add a small script to the index.html file so that it prints on the client side.
So we need to create a listener for when the socket is on to listen for history. And if there are no messages yet, then there is no history, and we wont return anything. When there are messages stored, we want to return them in a list at the top of the page.
Now we have persistence in our chat! However there are still issues with this. For my next blog I will focus on:
Printing only the last 10 messages (newly logged in users don't need the history from the dawn of time, just to get the gist of the conversation)
comments powered by Disqus