A Step-by-Step Tutorial of Building a Simple Peer-to-Peer WebSocket App – Part 6

Peter Moskovits

In Part 1, we looked at the completed application, then reviewed the starting code in Part 2. In Part 3 we created a WebSocket connection and started sending and receiving messages in Part 4. In Part 5 we solved the problem of hearing back the echo of the same messages we were sending to the other clients.

In this part, we’ll add an image to our app. As we interact with the slider, the size of the image will change with it.

If you haven’t followed the previous steps, you can start from Task 13 by pointing your browser to the Task 12 state of the tutorial: https://jsfiddle.net/kaazing/xxbkLey9/

Task 13: Adding an image

Let’s add an img tag to our HTML code right under the slider. The HTML file is located in the top-left pane in JSFiddle. You can use any image available through a public URL. We assign an id to our image, id=”pic” that will help us reference the image in other parts of the code. In this sample, we used an image from National Geographic, but feel free to use your own image.

[sourcecode language=”javascript” light=”true” gutter=”0″]
<img id="pic" src="http://photography.nationalgeographic.com/staticfiles/NGS/Shared/StaticFiles/Photography/Images/POD/b/balcones-escarpment-523192-sw.jpg" width="600">
[/sourcecode]

Here’s the entire HTML file. Look for Task 13 in the comments to find the newly added function.

[sourcecode language=”html” highlight=”7,8,9″ wraplines=”false”]
<body onload="doConnect()">
<!– Task 1 –>
<div id="sliderDiv">
<input id="slider" type="range" min="0" max="1200" value="600" onchange="sliderChange(this.value)" />
</div>
<!– Task 1 –>
<!– Task 13 –>
<img id="pic" src="http://photography.nationalgeographic.com/staticfiles/NGS/Shared/StaticFiles/Photography/Images/POD/b/balcones-escarpment-523192-sw.jpg" width="600">
<!– Task 13 –>
<div id="logMsgs"></div>
</body>
[/sourcecode]

To see and run the updated code in JSFiddle, point your browser to the Task 13 state: https://jsfiddle.net/kaazing/cxu6kfa5/

Task 14: Adjusting the size of the image in the local browser

In this task, we’ll tell the app to adjust the size of the image in the local browser, which is the same browser where the user interacts with the slider.

Add code to the sliderChange() function that sets the width of the image to the current value of the slider. For simplicity, we use jQuery notation.

[sourcecode language=”javascript” light=”true”]
$(‘#pic’).width(sliderValue);
[/sourcecode]

Here’s the entire JavaScript file. Look for Task 14 in the comments to find the newly added function.

[sourcecode language=”javascript” collapse=”1″ highlight=”73,74,75″ wraplines=”false”]
// Variables you can change
//
var WEBSOCKET_URL = "wss://demos.kaazing.com/jms";
var TOPIC_NAME = "/topic/myTopic";
var IN_DEBUG_MODE = true;
var DEBUG_TO_SCREEN = true;

/*** Task 9 ***/
// Message Properties and Message Types
var MESSAGE_PROPERTIES = {
"messageType": "MESSAGE_TYPE",
"userId": "USERID",
"sliderPos": "SLIDER_POS"
};

var MESSAGE_TYPES = {
"sliderMoved": "SLIDER_MOVED"
};
/*** Task 9 ***/

/*** Task 10 ***/
var userId = Math.random(100000).toString();
/*** Task 10 ***/

// WebSocket and JMS variables
//
var connection;
var session;
var wsUrl;

// Variable for log messages
//
var screenMsg = "";

// JSFiddle-specific variables
//
var runningOnJSFiddle = (window.location.hostname === "fiddle.jshell.net");

// Used for development and debugging. All logging can be turned
// off by modifying this function.
//
var consoleLog = function(text) {
if (IN_DEBUG_MODE) {
if (runningOnJSFiddle || DEBUG_TO_SCREEN) {
// Logging to the screen
screenMsg = screenMsg + text + "<br>";
$("#logMsgs").html(screenMsg);
} else {
// Logging to the browser console
console.log(text);
}
}
};

var handleException = function(e) {
consoleLog("EXCEPTION: " + e);
};
// *** Task 6a ***
var handleTopicMessage = function(message) {
// *** Task 12 ***
if (message.getStringProperty(MESSAGE_PROPERTIES.userId) != userId) {
consoleLog("Message received: " + message.getText());
// *** Task 8b ***
$("#slider").val(message.getText());
// *** Task 8b ***
}
// *** Task 12 ***
};
// *** Task 6a ***
// *** Task 2 ***
var sliderChange = function(sliderValue) {
consoleLog("Slider changed: " + sliderValue);
// *** Task 14 ***
$("#pic").width(sliderValue);
// *** Task 14 ***
// *** Task 8a ***
doSend(session.createTextMessage(sliderValue));
// *** Task 8a ***
};
// *** Task 2 ***
// *** Task 7a ***
// Send a message to the topic.
//
var doSend = function(message) {
/*** Task 11 ***/
message.setStringProperty(MESSAGE_PROPERTIES.userId, userId);
/*** Task 11 ***/
topicProducer.send(null, message, DeliveryMode.NON_PERSISTENT, 3, 1, function() {

});
consoleLog("Message sent: " + message.getText());
};
// *** Task 7a ***
// Connecting…
//
var doConnect = function() {
// Connect to JMS, create a session and start it.
//
var jmsConnectionFactory = new JmsConnectionFactory(WEBSOCKET_URL);
try {
var connectionFuture = jmsConnectionFactory.createConnection(”, ”, function() {
if (!connectionFuture.exception) {
try {
connection = connectionFuture.getValue();
connection.setExceptionListener(handleException);

consoleLog("Connected to " + WEBSOCKET_URL);
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// *** Task 3 ***
// Creating topic
var myTopic = session.createTopic(TOPIC_NAME);
consoleLog("Topic created…");
// *** Task 3 ***
// *** Task 4 ***
// Creating topic Producer
topicProducer = session.createProducer(myTopic);
consoleLog("Topic producer created…");
// *** Task 4 ***
// *** Task 5 ***
// Creating topic Consumer
topicConsumer = session.createConsumer(myTopic);
consoleLog("Topic consumer created…");
// *** Task 5 ***
// *** Task 6b ***
topicConsumer.setMessageListener(handleTopicMessage);
// *** Task 6b ***
connection.start(function() {
// Put any callback logic here.
//
consoleLog("JMS session created");
// *** Task 7b ***
doSend(session.createTextMessage("Hello world…"));
// *** Task 7b ***
});
} catch (e) {
handleException(e);
}
} else {
handleException(connectionFuture.exception);
}
});
} catch (e) {
handleException(e);
}
};
[/sourcecode]

To see and run the updated code in JSFiddle, point your browser to the Task 14 state: https://jsfiddle.net/kaazing/vjL2kotw/

Task 15: Adjusting the image size upon the receipt of a message

In this task, we’ll tell the app to adjust the size of our image every time a new message arrives. The app will also adjust the image size in all the participating (subscribed) remote browsers.

Let’s add the following line to the handleTopicMessage() function:

[sourcecode language=”javascript” light=”true” gutter=”0″]
$(‘#pic’).width(message.getText());
[/sourcecode]

Here’s the entire JavaScript file. Look for Task 15 in the comments to find the newly added function.

[sourcecode language=”javascript” collapse=”1″ highlight=”66,67,68″ wraplines=”false”]
// Variables you can change
//
var WEBSOCKET_URL = "wss://demos.kaazing.com/jms";
var TOPIC_NAME = "/topic/myTopic";
var IN_DEBUG_MODE = true;
var DEBUG_TO_SCREEN = true;

/*** Task 9 ***/
// Message Properties and Message Types
var MESSAGE_PROPERTIES = {
"messageType": "MESSAGE_TYPE",
"userId": "USERID",
"sliderPos": "SLIDER_POS"
};

var MESSAGE_TYPES = {
"sliderMoved": "SLIDER_MOVED"
};
/*** Task 9 ***/

/*** Task 10 ***/
var userId = Math.random(100000).toString();
/*** Task 10 ***/

// WebSocket and JMS variables
//
var connection;
var session;
var wsUrl;

// Variable for log messages
//
var screenMsg = "";

// JSFiddle-specific variables
//
var runningOnJSFiddle = (window.location.hostname === "fiddle.jshell.net");

// Used for development and debugging. All logging can be turned
// off by modifying this function.
//
var consoleLog = function(text) {
if (IN_DEBUG_MODE) {
if (runningOnJSFiddle || DEBUG_TO_SCREEN) {
// Logging to the screen
screenMsg = screenMsg + text + "<br>";
$("#logMsgs").html(screenMsg);
} else {
// Logging to the browser console
console.log(text);
}
}
};

var handleException = function(e) {
consoleLog("EXCEPTION: " + e);
};
// *** Task 6a ***
var handleTopicMessage = function(message) {
// *** Task 12 ***
if (message.getStringProperty(MESSAGE_PROPERTIES.userId) != userId) {
consoleLog("Message received: " + message.getText());
// *** Task 8b ***
$("#slider").val(message.getText());
// *** Task 8b ***
// *** Task 15 ***
$("#pic").width(message.getText());
// *** Task 15 ***
}
// *** Task 12 ***
};
// *** Task 6a ***
// *** Task 2 ***
var sliderChange = function(sliderValue) {
consoleLog("Slider changed: " + sliderValue);
// *** Task 14 ***
$("#pic").width(sliderValue);
// *** Task 14 ***
// *** Task 8a ***
doSend(session.createTextMessage(sliderValue));
// *** Task 8a ***
};
// *** Task 2 ***
// *** Task 7a ***
// Send a message to the topic.
//
var doSend = function(message) {
/*** Task 11 ***/
message.setStringProperty(MESSAGE_PROPERTIES.userId, userId);
/*** Task 11 ***/
topicProducer.send(null, message, DeliveryMode.NON_PERSISTENT, 3, 1, function() {

});
consoleLog("Message sent: " + message.getText());
};
// *** Task 7a ***
// Connecting…
//
var doConnect = function() {
// Connect to JMS, create a session and start it.
//
var jmsConnectionFactory = new JmsConnectionFactory(WEBSOCKET_URL);
try {
var connectionFuture = jmsConnectionFactory.createConnection(”, ”, function() {
if (!connectionFuture.exception) {
try {
connection = connectionFuture.getValue();
connection.setExceptionListener(handleException);

consoleLog("Connected to " + WEBSOCKET_URL);
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// *** Task 3 ***
// Creating topic
var myTopic = session.createTopic(TOPIC_NAME);
consoleLog("Topic created…");
// *** Task 3 ***
// *** Task 4 ***
// Creating topic Producer
topicProducer = session.createProducer(myTopic);
consoleLog("Topic producer created…");
// *** Task 4 ***
// *** Task 5 ***
// Creating topic Consumer
topicConsumer = session.createConsumer(myTopic);
consoleLog("Topic consumer created…");
// *** Task 5 ***
// *** Task 6b ***
topicConsumer.setMessageListener(handleTopicMessage);
// *** Task 6b ***
connection.start(function() {
// Put any callback logic here.
//
consoleLog("JMS session created");
// *** Task 7b ***
doSend(session.createTextMessage("Hello world…"));
// *** Task 7b ***
});
} catch (e) {
handleException(e);
}
} else {
handleException(connectionFuture.exception);
}
});
} catch (e) {
handleException(e);
}
};
[/sourcecode]

Run your application again. Now, you’ll see an image in the bottom right pane, under your slider. As you’re adjusting the slider, the size of the image changes both in the local browser, as well as in the remote browsers.

To see and run the updated code in JSFiddle, point your browser to the Task 15 state: https://jsfiddle.net/kaazing/o540uypq/.

In Part 7, we’ll discuss how to deal with accumulating messages when the slider is moved quickly.