The Building of Yeww: A WebRTC ProjectChat Proof of Concepts

Posted on September 19, 2016 at 5:37 PM by Lynn Walker

Continuing with our exercise in socket.io and proof of concept (POC) tests for our web application, Yeww.

A POC, group chat from a local server, is under our belts (see yesterday’s lesson for details).

Proof of Concepts

for chat or IM

  1. Group chat among remote users with remote chat server
  2. Detect presence of other clients with remote chat server
  3. Instead of testing against a local server, we’ll test with the node.js server running on AWS.
  4. Group chat and presence when web server and chat server are hosted separately
  5. Node.js won’t run our web application, only our chat server. Our application will run on apache, or possibly IIS. Apache for now. This means the index.html page is running on a server distinct from the AWS node.js chat server. What do we have to do to make this work?
  6. Group chat and presence when client is rewritten in AngularJS.
  7. I’d like to rewrite our client-side chat code from the most recent example in AngularJS.

Today's tasks

For today we will complete the first two chat proof of concepts as listed above.

Running the application on AWS

We setup an Ubuntu server running on AWS two lessons ago, installing node.js and apache, along with mongoDb. Now we can create our group chat application on the Ubuntu server and run our web application remotely.

Connect to the remote server

In order to connect to the AWS server we need a key file, stored in the .PEM format from our first AWS session.

Open a terminal or command window in the directory where you have stored the key file and type this command:

ssh –i [ KEY_FILE_NAME ] ubuntu@[ IP_ADDRESS_AWS_SERVER ]

Create project directory and files

Type

cd dev
sudo mkdir chat
cd chat

Touch, copy & paste

sudo touch app.js
sudo touch index.html
sudo touch package.json

Nano is a text editor that comes with almost any shell. Using nano in the ssh connection we have open, we will copy text from a local text editor into nano on the Ubuntu server. Type:

sudo nano package.json

then copy and paste this code into nano in the shell window:

package.json

{
  "name": "connect",
  "version": "0.0.1",
  "private": "true",
  "dependencies": {
    "express": "^4.9.1",
    "socket.io": "^1.1.0"
  }
}

In OSX I can paste directly into nano in the terminal window. In Windows 7, right click the title bar of the command or shell window, select "Edit" in the context-menu and "Paste" in the sub-menu.

To save in nano, press [ Ctrl ]-[ O ]. To exit, [ Ctrl ] – [ X ].

Do the same with the other two files.

sudo nano app.js

app.js

var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(8000);
var nicknames = [];

app.get('/', function(req, res){
	res.sendFile(__dirname + '/index.html');
});

io.sockets.on('connection', function(socket){
	socket.on('new user', function(data, callback){
		if (nicknames.indexOf(data) != -1){
			callback(false);
		} else{
			callback(true);
			socket.nickname = data;
			nicknames.push(socket.nickname);
			updateNicknames();
		}
	});
	
	function updateNicknames(){
		io.sockets.emit('usernames', nicknames);
	}

	socket.on('send message', function(data){
		io.sockets.emit('new message', {msg: data, nick: socket.nickname});
	});
	
	socket.on('disconnect', function(data){
		if(!socket.nickname) return;
		nicknames.splice(nicknames.indexOf(socket.nickname), 1);
		updateNicknames();
	});
});

index.html

<!doctype html>
<html lang="en">
<head>
	<title>Socket.io Username Example</title>
	<style>
		#messages{ height:300px; }
		#contentWrap{ display: none; }
		#messageWrap{ float: left; border: 1px #000 solid; }
	</style>
</head>
<body>
	<div id="nickWrap">
		<p>Enter a username:</p>
		<p id="nickError"></p>
		<form id="setNick">
			<input size="35" id="nickname"></input>
			<input type="submit"></input>
		</form>
	</div>

	<div id="contentWrap">
		<div id="messageWrap">
			<div id="messages"></div>
			<form id="send-message">
				<input size="35" id="message"></input>
				<input type="submit"></input>
			</form>
		</div>
		<div id="users"></div>
	</div>
	
	<script src="http://code.jquery.com/jquery-latest.min.js"></script>
	<script src="/socket.io/socket.io.js"></script>
	<script>
		jQuery(function($){
            var socket = io('http://localhost:8000');
			var $nickForm = $('#setNick');
			var $nickError = $('#nickError');
			var $nickBox = $('#nickname');
			var $users = $('#users');
			var $messageForm = $('#send-message');
			var $messageBox = $('#message');
			var $messages = $('#messages');
			
			$nickForm.submit(function(e){
				e.preventDefault();
				socket.emit('new user', $nickBox.val(), function(data){
					if(data){
						$('#nickWrap').hide();
						$('#contentWrap').show();
					} else{
						$nickError.html('That username is already taken!  Try again.');
					}
				});
				$nickBox.val('');
			});
			
			socket.on('usernames', function(data){
				var html = '';
				for(i=0; i < data.length; i++){
					html += data[i] + '<br/>'
				}
				$users.html(html);
			});
			
			$messageForm.submit(function(e){
				e.preventDefault();
				socket.emit('send message', $messageBox.val());
				$messageBox.val('');
			});
			
			socket.on('new message', function(data){
				$messages.append('<b>' + data.nick + ': </b>' + data.msg + "<br/>");
			});
		});
	</script>
</body>
</html>

Run application

It’s time to start the server and launch a pair of browsers to see the group application in action. First we have to install the dependencies.

One-time setup

To install the dependencies automatically type:

npm install

Start server

After the dependencies have been installed type:

nodemon app.js

We have previously installed the nodemon module, an add-on to node.js that watches the main application file, app.js, and restarts the server when app.js is updated. It saves us from typing [Ctrl] - [C] and

node app.js

many times over the course of a session.

Launch browser

Open a browser and point to the ip address and port of your node server. You should see the contents of the index.html page, which will be the message “Enter a username”, a textbox input field and a submit button.

What’s wrong

That’s what I get. But when I enter a username and hit submit nothing happens. The form requesting username is still displayed. Since I’m using Firefox I open Settings - Developer tab and look at the web console. There are a series of errors, saying ERR_CONNECTION_REFUSED. I check the network panel and it shows the same information.

First key to remote socket.io application

We need to give our client socket an actual ip address, the external ip address of the node server, and not localhost. That may have worked during development on your local machine, but when the user (client) runs the web application (index.html) in their browser, localhost is relative to their computer and that’s not where the node server is located. We need to fix index.html to point to the node server.

First, change:

<script src="/socket.io/socket.io.js"></script>

to:

<script src="http://[NODE_SERVER_IP_ADDRESS]:8000/socket.io/socket.io.js"></script>

then

var socket = io('http://localhost:8000');

to

var socket = io('http://[NODE_SERVER_IP_ADDRESS]:8000');

Now we can actually connect our local browser to the nodejs server on AWS.

What was wrong

Our browser on our machine was opening a page, “index.html”, that attempted to open a websocket connection to a server at localhost. The actual server is on the AWS virtual server, so that is where the page should attempt to open a websocket connection. Now that we are pointing to the AWS virtual server we should be able to make a connection.

Refresh browser

We made changes to the index.html file, that’s the client side of our application, so refresh the browser to update our changes.

Now when we enter a username and press submit the screen is updated to show the chat controls, with our username listed next to the chat history window. You may open Chrome Developer Tools and verify that there are no errors reported in the console or network window.

Launch second browser

In order to fulfill our first two proof of concepts we need to launch a second browser that also establishes a websocket connection with our node.js server. Use a second browser type for more accurate testing results.

First two proof of concepts

There are two proof of concept items for today. We want to demonstrate group chat between two remote users and we want to demonstrate that we can detect their individual presence. This will confirm our choice of node.js and socket.io for handling our IM feature.

Communication verified

Once two remote users have logged onto the web application running on the AWS virtual server they should send messages to each other.

Success. Proof of concept supplied.

Presence verified

We see the list of both users 1) Lynn, 2) Walker, displayed in both clients. The name of user 2, “Walker”, appeared in the list on client 1 when user 2 logged in. For final confirmation, we should see user 2, “Walker” removed from the list of users displayed on client 1 when client 2 closes.

We do. Success. Second proof of concept supplied.

Conclusion

We have done a quick test with our choice of technologies for IM, node.js and socket.io, to verify that they could fulfill our needs. This was certainly not a rigorous test, we simply performed the most basic of functions, sending messages and detecting presence, to show that we can support the type of features we intend.


Previous lesson

Next lesson

Previous lesson

Next lesson