Giter VIP home page Giter VIP logo

hapi-socketio-redis-chat-example's Introduction

Hapi.js Socket.io Redis Chat Example

Build Status Test Coverage by codecov.io Code Climate Dependency Status devDependency Status

A basic chat application built with Hapi.js Socket.io and Redis Publish/Subscribe

Try it: https://hapi-chat.herokuapp.com/

hapi-chat-screenshot

Why?

Node.js Chat Apps are practically the "Hello World" of real-time apps. If you Google for "node.js chat example" you will see thousands of results! But ... 90% of the examples use Express.js, 95% use MongoDB to store data/messages and 100% have zero tests. So, this example is for the the people who prefer to have examples that are fully explained (including tests).

As with all our examples we have a suite of tests.

What?

Real-Time Chat is an integral part of any communications system.
Building a (basic) chat system is easy with Socket.io.

This example app shows you how to use Socket.io with Hapi.js and Redis for a Horizontally Scalable chat capable of hundrededs of thousands of concurrent clients.

How?

We are using the following components to build our chat app:

  1. Hapi.js (node.js web framework) - If you haven't used Hapi.js before, checkout our introductory tutorial: https://github.com/dwyl/learn-hapi

Why Redis?

Socket.io only handles distributing messages, if people disconnect from the chat they will miss any subsequent messages and when anyone connects there will see no history ... so we need a place to store messages for retrieval.

Top 3 reasons why Redis is the clear choice for storing chat messages.

  1. Speed - Redis is much faster than MongoDB, CouchDB or PostgreSQL
  2. Simple - pushing messages onto a list (set) is the simplest possible way to store a chat history. Given that we can store up to 512Mb per chat and stream chat history to new clients (low http overhead) its an incredibly simple setup!
  3. Scalable Publish/Subscribe ("pattern") means we can scale out (add more node.js/socket.io servers when you need to serve more clients) Redis can already handle an order of magnitude more than other NoSQL Databases, so your most likely "bottleneck" is node (nuts, hey!?)

Publish / Subscribe ...?

The Publish Subscribe "Pattern" is (still) the simple_st_ way of scaling software applications. If you are new to this idea, see: https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern

Mobile First

Given the simplicity of the UI, the chat app is mobile-first by default.

If anyone has time to Pull Request a few CSS media queries to make the UI even better on mobile devices, we would massively appreciate the contribution!

Returning Visitor

We use cookies to store the person's name on the client. If the person clears cookies (or uses private browsing / incognito mode) they will be asked for their name each time they open the chat window. (this is pretty standard).

ย How Many Recent Messages Should we Cache?

At present we are caching all the messages in Redis. But a less RAM-hungry way to scale the app would be to store only the 50-100 most recent chat messages in Redis (RAM) and the remaining history in a cheaper on-disk storage e.g. ElasticSearch (which would also enable searchability)

Data Model

Data Model we have used is incredibly simple. It translates to an array of objects:

var chat =  [
  '{"m":"Hi everyone!","t":1436263590869,"n":"Steve"}',
    '{"m":"Hi Steve! Welcome to Hapi Chat!","t":1436263599489,"n":"Foxy"}',
    '{"m":"Hapi Chat lets you chat with your friends!","t":1436263613141,"n":"Oprah"}',
    '{"m":"Cool! How does it scale?","t":1436263620853,"n":"Steve"}',
    '{"m":"Funny you should ask! It scales nicely because it uses Hapi.js and Redis!","t":1436263639989,"n":"Chroma"}',
    '{"m":"Sweet! ","t":1436263645610,"n":"Steve"}',
    '{"m":"Hello","t":1436264664835,"n":"Timmy"}',
    '{"m":"Hi!","t":1436267152379,"n":"Timmy"}',
    '{"m":"lkjlkjlk","t":1436270948402,"n":"dd"}',
    '{"m":"Big fan of the little notifications at the top when a person joins","t":1436273109909,"n":"iteles"}'
]

We use single letters for field keys:

  • m for message.
  • n for name of the person who wrote the message
  • t for timestamp the message was received by the node server (to avoid time-zone issues);

Run it! (it's easy!)

Locally (on your own machine)

Try running the app! (Its as easy as 1, 2, 3!)

1. Clone the Repository

git clone https://github.com/dwyl/hapi-socketio-redis-chat-example.git
cd hapi-socketio-redis-chat-example

2. Install Redis (if you don't already have it!)

If you haven't already got an instance of Redis running on your machine, Our Redis tutorial has instructions:

https://github.com/dwyl/learn-redis#installation

3. Install the Dependencies and Start the Server

Install the dependencies and start the app with:

npm install && npm start

Now visit: http://127.0.0.1:8000 (in your browser)

Running the Tests (Locally)

To successfully run the tests you need to have an environment variable for RedisCloud (this is because we like to know that our code works on both "local" and in a "production" environment...)

E.g:

export REDISCLOUD_URL=redis://rediscloud:[email protected]:12345

Given that our tests include checks for RedisCloud, you will need to have internet access to run them ...

Running the Elm version

At dwyl we really like Elm and Tachyons and they're part of our core technology stack, so as well as the standard Javascript/HTML/CSS front end we've made one in Elm so you can see what goes into a chat app in Elm as well.

You'll need Elm installed on your machine to run it so make sure you have that.

If you've never done Elm before we recommend starting with our learn-elm-architecture tutorial, and then moving onto learn-elm, and once you're done with them come here and check out how the chat app works!

To run the Elm version go into your terminal and run:

npm run start-elm

this script runs elm-make when it runs, so will prompt you to install all of the elm-stuff when you first run it, then go to localhost:8000/elm (make sure you're not running the server already!).

If you're interested in the code go into elm/src/Main.elm, it's commented all the way through so that you can understand everything. (if anything is unclear, let us know!)

We also have tests!

npm run test-elm

Elm doesn't currently have a coverage tool but we try to make sure all of our logic is tested. If you haven't tested your Elm code before, start now!

Heroku (deploying to Heroku)

Are you new to deploying apps to Heroku? (Message us we can talk/walk you through it...!)

Background Reading

HitCount

hapi-socketio-redis-chat-example's People

Contributors

badboy avatar besarthoxhaj avatar claireinez avatar filwisher avatar finnhodgkin avatar hdrdavies avatar iteles avatar jackpandas avatar mijothy avatar nelsonic avatar rjmk avatar sericaia avatar shivang44 avatar simonlab avatar sohilpandya avatar tsop14 avatar yurm04 avatar zooeymiller avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hapi-socketio-redis-chat-example's Issues

Test hanging

When the repo is downloaded, and you run npm run test, the 3rd test in server.js hangs.

We found it could be resolved by JSON.stringifying the res.payload

Re-structure CSS

Currently it's not a great example of how things are done at dwyl.

current-css-at-hapi-chat

script injection is possible

this could help

function sanitise(txt) {
  if(txt.indexOf("<") > -1 || txt.indexOf(">") > -1) {
    txt = txt.replace(/</g, "&lt").replace(/>/g, "&gt");
  }
  return txt;
}

Latest message must be displayed on load

The window should be scrolled down to the very bottom of the messages when it loads so that the latest messages are always visible and people can scroll up if they want to see past conversations.

Currently the very top of the message history is displayed when the app loads - i.e. The first message entered into the chat, in this case "First message ever written to my local chat"
hapi-socketio-redis-chat-example-scrolled-to-top-on-load

You have to manually scroll all the way down to get to the last message when this should happen automatically on load:
hapi-socketio-redis-chat-example-scrolled-to-bottom-manually

How about with node.cluster?

Are you guys wondering to implement it on this project?
Does anyone implemented a HapiJS Chat with Socket.io and Redis?

Additional feature ideas

  1. Authenticating the application with Github / Google / Facebook
  2. Make rooms
    • Display rooms to join
  3. Display list of users on side of channel or room
  4. Custom notifications
    • Sounds
    • Notifications from other rooms
  5. Uploading files
  6. Markdown friendly / Custom text (e.g. bold, italics)
  7. Emojis
  8. Monetise chatrooms
  9. Private chatrooms
  10. Video chat
  11. Sound messages
  12. Random chat (chatroulette)

Body element must be height of window at all times

When the window is resized, the body must continue to be the same height as the window.
If it is not, the content (messages) will be allowed to increase in height when the window is made thinner, which will cause the messages to hide behind the messages input form as per #8.

Last comment, "And this is the last message" can no longer be seen when window is made smaller:
content-hidden-on-window-resize

Add .env to .gitignore file

unfortunately pushed an env file, but realised that the gitignore did not contain any means to ignore it.

can we please add it to the master. Thanks.

Rooms

Hi, guys, I am wondering what would be the best practice to add rooms to this chat. And how to handle the room from the client to the handler?
Thank you.

instead of io.emit on.message we should redis.subscribe on each node.js server for horizontal scalability

At present we have:

socket.on('message', function (msg) {
    redisClient.HGET("people", socket.client.conn.id, function (err, name) {
            if (err) {
                console.log(err);
            }
            var obj = { // store each message as a JSON object
                m: msg,
                t: new Date().getTime(),
                n: name
            }
            var str = JSON.stringify(obj)
            redisClient.RPUSH("chat", str);
            io.emit('message', str);
    })
});

We should de-couple the io.emit('message, str) from the socket.on('message' ...

CSS | 'Send' button disappears with smaller width windows

When a window width is reduced, the 'Send' button disappears.

Essentially it gets wrapped to the next line but the div height pushes it off the screen - you can see it at the very bottom of the screen in the screenshot below.
hapi-chat-css-width-issue-on-send-button

Heroku / Redis Cloud

Hello,

I believe you have used Redis Cloud add-on in Heroku.
I can get 30mb storage free on Heroku but need to put in my bank card details, have you heard of any issues with this before?

Is Redis Cloud add-on in Heroku still the best approach for hosting an app with Redis? My project is very similar to your chat app.

Long name causes horizontal scroll

  1. I was thinking, I could add a style to cause the word to break, preventing horizontal scroll.
  2. It might also be worthwhile adding a max-length to the name - but that might be a bit more involved.

Shall I submit a pull request with 1?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.