Basic NodeJs chat app for Openfire using Strophe.js as client library

kunal pal
Viithiisys
Published in
8 min readFeb 22, 2018
Chat application in Node.js

In Today time web application feels incomplete without chat support. So it is quite important to include a simple chatting interface to your web application which involves one on one human interaction for success of your idea. I am sharing some of my experience which I went through in building a chat system for my web application. This project is built in NodeJs and I used Openfire for my chat server which uses XMPP protocol. So lets quickly get our hands dirty.
To start first make sure you have installed openfire on your system.For installation and configuration of Openfire checkout this link. Openfire by default runs on port 9090. After Openfire is installed check if it is working properly by going to the following link in your browser. http://127.0.0.1:9090 and you will be presented with the admin login screen. Login to the admin screen by entering username and password which will be created while you were configuring your openfire server.
First, create a directory structure something like this:

package.json file will be made after initialization as node Project

To create new user, get all users,create chat room and all the other things we are going to use. Then we will use rest API plugin provided by openfire, install this plugin by going in the plugin area in openfire and search for it.

Constructing the Server

Now First go to server directory and run the following command.

user@user:~$ npm init

This will initialize the node Project and create the package.json file in the server directory.
Now we will create the server at port 3000, this server will provide us a route for creating a new user in openfire. From the frontend, we make registered user login to openfire using its JID and Password.
I assume you have basic understanding about the flow of a NodeJs Project.
For this tutorial, we are going to use the Jquery library so we can make the Ajax request to the API’s.

server/server.js

var Hapi = require('hapi');
var requestPromise = require('minimal-request-promise');
var server = new Hapi.Server({
app: {
name: 'Chat_App'
}
});
server.connection({
port: 3000, // You can choose different port number
routes: { cors: true } // allowing cross origin resource sharing
});
server.route(
{ // this is the root route or default route
method: 'GET',
path: '/',
handler: function (req, reply) {
reply('<h1>hello</h1>')
}
}
);
server.start((err) => {
if (err) {
console.log("error server connect",err)
// throw err;
} else {
// this message will print on console if connection was successful
console.log("Server listening at port:3000")
}
})

Now we need a route so we can create user in Openfire by hitting on that route from our Ajax call.

server.route(
{
method:'POST',
path: '/api/createUser',
handler: function (req, reply){
//This object will get pass in REST Api call for user creation
objToSave = {
//as method is POST, data will be in Payload of Request object
username: req.payload.username,
password: req.payload.password
}
options = {
headers: {
'Authorization': 'Secret-Key',
//See the description below for more on Secret-key
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(objToSave)
};
requestPromise.post('http://localhost:9090/plugins/restapi/v1/users', options)
//This url will be same for you also.
.then(function(response) {
reply(response);
})
.catch(function(error) {
// Deal with the error
console.log(options);
console.log(error);
reply(error);
})
}
}
);

The Secret-Key in the above code will be available in Openfire- server>server settings>REST API. Put this value of Secret Key in code.

Now start the server by going to root directory of the project and type the following command.

user@user:~$ node server/server.js

You will see a message of server listening on port 3000 on console.

Constructing the Client

Here we are going to make the frontend of our chat app. I will not discuss the CSS code but only the important part of JS and HTML file.

client/index.js

The code below shows how we are calling the route created by our node server. We are using AJAX request to hit the route given by node server. Here the username and password are provided by you. Actually, the values for these fields are taken as input from the user and in HTML page and then sent as data in along with AJAX request. Actually this data is passed as JSON to the Rest API call of Openfire for creating a user. You must be thinking why only username and password is sent for creating the user. In reality, there are also other fields but these two are mandatory so you can pass another field also. For complete usage of Rest API read the official documentation.

var signup = function() {
$.ajax({
type: "POST",
// This url will be defined by you. Here I chosen route //url as /api/createUser
url: "http://localhost:3000/api/createUser",
ContentType: 'application/json',
dataType: 'json',
data: {
// These username and password I am getting from HTML form
username: $('#userName').get(0).value,
password: $('#passWord').get(0).value
},
success: function(data) {
alert("User created Successfully");
console.log('succes: ' + data);
}
})
}

client/index.html

In this HTML file include the latest Jquery, latest bootstrap and don’t forget to include index.js. In this page, we are going to let the user choose if he is a new user or already has an account on openfire. If he is a new user he will signup by filling the appropriate fields and this will work through by making ajax call written in the index.js file. If he is not a new user then he will click on the login button and he will be redirected to the chatpage.html.

client/chatpage.html

Now we need a space from where we can log in and type our messages and ultimately able to do chat. For this, we are going to use the StropheJs library and we will use RawGit to make our JavaScript to use the stropheJs library. This HTML file provides a frontend for our chatting instance. This file will include the latest bootstrap and Jquery along with this it will also include strophe.min.js and strophe.muc.js in the script Tag, strophe.min.js provides a library for establishing the connection to openfire and strophe.muc.js is for handling chatRoom activities. I include the links in the names of these libraries which you can directly include in the script tag in the HTML file.
Rest part of this HTML file will contain simple HTML elements for construction of the interface.

client/chatpage.js

This Javascript file contains core handling part of our chat app. In this, we see how strophe library is used for connection establishment and how chat is initiated. By default http-bind port is 7070. If you get some error checkout the same in openfire settings. First few lines of this file are-

var server = 'localhost';
var BOSH_SERVICE = 'http://127.0.0.1:7070/http-bind/';
var connection = null; // initializing connection with NULL

Now, this file contains some function defined inside strophe library but before jumping towards that we are going to see the Javascript which is taking value from the front end and providing functions for functionality implementation.

$(document).ready(function() {
// Here jid and pass are will be entered by user from frontend
$('#jid').get(0).value = "user@localhost";
$('#pass').get(0).value = "userpassword";
$('#connect').bind('click', function() {
var url = BOSH_SERVICE;
connection = new Strophe.Connection(url);
connection.rawInput = rawInput;
connection.rawOutput = rawOutput;
var button = $('#connect').get(0);
if (button.value == 'connect') {
button.value = 'disconnect';
connection.connect($('#jid').get(0).value, $('#pass').get(0).value, onConnect);
} else {
button.value = 'connect';
connection.disconnect();
}
});
$('#send').bind('click', function() {
var msg = $('#message').val();
sendMessage(msg);
});

Now see the functions which are making the chat possible. The function below will tell the connection status:

function onConnect(status) {
if (status == Strophe.Status.CONNECTING) {
log('connecting..');
} else if (status == Strophe.Status.CONNFAIL) {
log('failed to connect.');
$('#connect').get(0).value = 'connect';
} else if (status == Strophe.Status.DISCONNECTING) {
log('disconnecting..');
} else if (status == Strophe.Status.DISCONNECTED) {
log('disconnected.');
$('#connect').get(0).value = 'connect';
} else if (status == Strophe.Status.CONNECTED) {
log('connected.');
$('#to').get(0).value = connection.jid; // full JID
// set presence
connection.send($pres());
// set handlers
connection.addHandler(onMessage, null, 'message', null, null, null);
connection.addHandler(onSubscriptionRequest, null, "presence", "subscribe");
connection.addHandler(onPresence, null, "presence");
listRooms();
}
}

The function below will tell the connection status:

function onMessage(message) {
var to = message.getAttribute('to');
var from = message.getAttribute('from');
var type = message.getAttribute('type');
var elems = message.getElementsByTagName('body');
if (type == "chat" && elems.length > 0) {
var body = elems[0];
log('Got a message for you from ' + from + ': ' + Strophe.getText(body));
}
// we should return true to keep the handler alive.
return true;
}

And now the next function will be used to send the message:

function sendMessage(message) {
log('Send a message to ' + $('#to').get(0).value + ': ' + message);
var m = $message({
to: $('#to').get(0).value,
from: $('#jid').get(0).value,
type: 'chat'
}).c("body").t(message);
connection.send(m);
}

To start a real time chat we need to open the two instances of the index.html in the browser and once presented with the login screen login with two different JID’s and Password.

Some Errors I faced while Developement

  1. Very first error I faced while trying to login to the openfire server.

I tried to login with the username and password which I entered during openfire configuration process but it kept showing me the invalid username and password error. But when I entered the Username which I used during configuration and password as root, then it worked for me.

2. The second error I faced was when I tried to create the user in openfire using Rest API. The error was because I was passing the space in name of the user and it was showing me error Invalid Jid. So be sure you are passing proper name format to the API include only the alphabets and numbers.

3. While doing AJAX call I am retrieving data in the query object while the method type was the post so I was getting the blank object. so do make sure to use the payload when retrieving data from the POST request and use query when retrieving data from the GET request.

In this blog I shared the most needed for a basic understanding of a chat app based on openfire. The project i discussed was the one with basic functionalities but if you want to customise your personal chat app then you can add many more things to it like getting all username, creating chatroom, getting all chatRoom names etc. For more information about this see the official documentation of Rest API plug-in. Apart from connection establishment, sending and receiving messages Strophe provides much more like sending status, room handling etc. You can check out full functionality of this in the source code available on my GitHub.

If You have any suggestions or queries related to this project you can comment below or ping me on Linkedin.

--

--