Click here to Skip to main content
13,191,642 members (61,962 online)
Click here to Skip to main content
Add your own
alternative version

Stats

12.8K views
21 bookmarked
Posted 20 Jul 2016

Serverless HTML5 Chat with Emitter, Vue and Bootstrap

, 9 Aug 2016
Rate this:
Please Sign up or sign in to vote.
Presents a serverless real-time HTML5 chat application using emitter.io, vuejs and bootstrap.
 

Introduction

In this article I'm going to show you how to create a completely serverless chat application that you can host on your blog or website. This can serve as a good starting point if you want to develop a chat platform of your own. Below is the chat application we are going to create.

[View Live Demo]

Background

In order to transfer messages between clients, we need to rely on some external service that would allow us to dispatch events, in real-time. For this purpose we are going to use emitter.io, a scalable, affordable and simple service that also offers a nice free tier that we can use. Emitter is a cloud publish/subscribe service that uses open and standardized MQTT protocol.

Essentially, emitter.io will act as message bus allowing our javascript client (e.g. browser) to:

  1. Subscribe to a particular channel, which can be represented by a simple string.
  2. Publish messages to that channel.
  3. Store the messages published for a limited amount of time, allowing us to retrieve the data if the page is suddenly refreshed.
  4. Expire the messages after some time, allowing the system to 'forget' old conversations.
  5. Encrypt the communication through TLS/SSL so we can avoid man-in-the-middle attacks.
  6. Secure the channel using a particular emitter.io key, which can only be allowed to publish and/or subscribe to a particular channel. This allows us to simply embed the key for the chat channel into the webpage itself.

The Application DOM

Alright, let's jump right into the code. First, let's have a look in our index.html page.

<div v-for="message in messages" class="row animated bounceInRight">
   <div class="col-sm-12">
       <canvas width="80" height="80" data-jdenticon-hash="{{message.hash}}" class="img-thumbnail img-responsive img-circle"></canvas>
       <div class="panel panel-default"><div class="panel-body">{{message.text}}</div></div>
   </div>
</div>

There are several interesting points in the above code:

  1. We set a vue.js repeater property (v-for="message in messages") which allows us to repeat the inner dom for every message. Essentially, we are setting up our template for rendering our message list there.
  2. We assign a jdenticon hash (data-jdenticon-hash="{{message.hash}}") which allows the jdenticon plugin to render the identicon. Notice that the actual hash value will be data-bound by vue.js itself. That means that we would need to simply re-run jdenticon every time we receive a new message.
  3. We also set CSS class (class="row animated bounceInRight") which comes from a very nice animate.css library, allowing us to animate new messages when they appear. This is super-easy as there's pretty much nothing else to do to set this up.

Second interesting part of our HTML dom consists of a simple input section where we can submit a message:

<form v-on:submit.prevent class="col-sm-12 col-md-6 col-md-offset-3">
   <div class="input-group">
      <input type="text" class="form-control" v-model="message" placeholder="Say Something">
      <span class="input-group-btn">
          <button class="btn btn-default form-control" type="submit" v-on:click="sendMessage()">Say it! <i class="fa fa-commenting-o"></i></button>
      </span>
   </div>
   <ul class="emoji">
       <li v-for="em in emoji"><a v-on:click="append(em)" >{{em}}</a></li>
   </ul>
</form>
  1. Once again, we use vue.js to perform data-binding (v-model="message"). However, this time a two-way data binding is performed. Two way data binding mechanism implements the 'always up to date' relationship between model and view, which allows our model to retrieve the value of the text box.
  2. We also attach an 'on click' method (v-on:click="sendMessage()") to the button, allowing us to execute some javascript once the user clicks or submits the form.
  3. Finally, we print out a list of emojis, again using vue.js data binding (v-for="em in emoji") and set an 'on click' function on every link (v-on:click="append(em)").

The JavaScript Implementation

The javascript code contained in the app.js page does all the magic. 

var emitter = emitter.connect({
    secure: true
}); 

First, we need to connect to emitter service. This is done through a simple emitter.connect() function call which returns a client we can use. We also specify that we want to communication over an encrypted connection (using TLS/SSL).

emitter.on('connect', function(){
    // once we're connected, subscribe to the 'chat' channel
    console.log('emitter: connected');
    emitter.subscribe({
        key: key,
        channel: "article1",
        last: 5
    });

    jdenticon.update(".img-circle");
})
  1. Once we're connected, we are going to subscribe to the channel by calling an emitter.subscribe() function. We provide a key that I have previously generated on the emitter.io website. This key allows us to publish and subscribe to the "article1" channel. However, it won't allow publishing or subscribing to any other channel. This restricts its usage and allows us to distribute this key on the web. If we wanted, we could also specify an expiration time for the key (for example 1 day), after which the key would simply expire and not be valid. 
  2. Additionally, during the subscription we also specify last: 5 parameter, which allows us to automatically retrieve 5 last messages from the channel.
emitter.on('message', function(msg){

    // log that we've received a message
    console.log('emitter: received ' + msg.asString() );

    // If we have already 5 messages, remove the oldest one (first)
    if (vue.$data.messages.length >= 5){
        vue.$data.messages.shift();
    }

    // Push the message we've received and update an identicon once it's there
    vue.$data.messages.push(msg.asObject());
    setTimeout(function(){ 
        jdenticon.update(".img-circle");
    },5);
});
  1. Once a message is received, we are going to parse the message as JSON by calling msg.asObject() function and push the message into our vuejs array (vue.$data.messages.push(msg.asObject())). 
  2. We remove the very first message, so we can keep our UI short and nice.
  3. We need to wait a little bit for data-binding to execute, hence we schedule a jdenticon update at some later stage.
var vue = new Vue({
    el: '#app',
    data: {
        messages: [],
        message: '',
        emoji: [
            "😀", "😬", "😁", "😂", "😃", "😄", "😅", "😆", "😇", "😉", "😊",
            "🙂", "😋", "😌", "😍", "😘", "😗", "😙", "😚", "😜", "😝", "😛", 
            "😎", "😏", "😶", "😐", "😑", "😒", "😳", "😞", "😟", "😠", "😡",
            "😔", "😕", "🙁", "☹", "😣", "😖", "😫", "😩", "😤", "😮", "😱",
            "😨", "😰", "😯", "😦", "😧", "😢", "😥", "😪", "😓", "😭", "😵", 
            "😲", "😷"
        ]
    },
    methods: {
        sendMessage: function () {
            var message = this.$data.message;
            this.$data.message = '';

            // publish a message to the chat channel
            console.log('emitter: publishing');
            emitter.publish({
                key: key,
                channel: "article1/" + getPersistentVisitorId(),
                ttl: 1200,
                message: JSON.stringify({
                    name: 'test',
                    hash: getPersistentVisitorId(),
                    text: message,
                    date: new Date()
                })
            });
        },

        append: function(emoji) {
            this.$data.message += ' ' + emoji + ' ';
        }
    }
});

The last part, shown above, is our actual view model (vue.js). This part is pretty straightforward as it declares some data to bind and a couple of methods to execute.

  1. messages is our message array to display.
  2. message contains our input text from the text box.
  3. emoji contains a list of nice emoji characters. Interestingly enough, Emojis are supported on all operating systems: iOS, Android, OS X, Windows and Windows Phone and we have used some characters that can be simply copied and pasted (see http://getemoji.com).

Most interestingly, sendMessage method publishes a message to emitter service, on the article1 channel. We have specified that a message should be automatically expired after 1200 seconds to allow the service to 'forget' old messages. When publishing, we also pass a hash value for our visitor (some kind of unique value) that would allow the remote clients to generate an appropriate avatar.

History

  • 09/08/2016 - Clarified some things.
  • 22/07/2016 - Fixed some typos.
  • 20/07/2016 - Initial article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Kel_
Chief Technology Officer Misakai Ltd.
Ireland Ireland
Roman Atachiants, Ph.D. is the architect behind emitter.io service, a real-time, low-latency publish/subscribe service for IoT, Gaming. He is a software engineer and scientist with extensive experience in different computer science domains, programming languages/principles/patterns & frameworks.

His main expertise consists of C# and .NET platform, game technologies, cloud, human-computer interaction, big data and artificial intelligence. He has an extensive programming knowledge and R&D expertise.



You may also be interested in...

Comments and Discussions

 
QuestionNumber of messages Pin
Member 102116188-Dec-16 4:55
memberMember 102116188-Dec-16 4:55 
AnswerRe: Number of messages Pin
Kel_11-Dec-16 12:37
memberKel_11-Dec-16 12:37 
QuestionList of available chatter Pin
ssaallmmaann28-Nov-16 19:34
memberssaallmmaann28-Nov-16 19:34 
QuestionDoes emitter have a server? Pin
Dewey20-Jul-16 9:52
memberDewey20-Jul-16 9:52 
AnswerRe: Does emitter have a server? Pin
Kel_20-Jul-16 10:28
memberKel_20-Jul-16 10:28 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.171017.2 | Last Updated 9 Aug 2016
Article Copyright 2016 by Kel_
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid