Pages Menu
TwitterRssFacebook

Posted by on May 20, 2015 in Learn Skype Web SDK

Learn Skype Web SDK Day 15 : Receiving Instant Messages

Learn Skype Web SDK Day 15 : Receiving Instant Messages

This is one post in a series of more than 30, devoted to helping you get up to speed quickly with the new Skype Web SDK. Each lesson comes with source code (in GitHub) and a working demo page so you can see what it does. Check out the full list of posts on the Skype Web SDK page.


View Demo

Once you’ve created and started a conversation using Skype for Web API, you actually don’t need to worry about how you’re going to receive IM messages. Skype for Web will make sure that you receive messages sent to the conversation. The issue instead becomes one of “how do I found out when that’s happened”.

Each conversation has a historyService object. This provides a collection of all messages in the conversation: incoming, outgoing, joining, leaving. IM messages have a specific type of message called a TextMessage. By listening for messages of type TextMessage we can pull out instant messages being sent in both directions.

Of course, you probably already know when you’re sending messages to the conversation, but having them in the historyService object means that you have one centralised place to watch to track the conversation. If you’re writing a user interface for an IM conversation, it’s much easier to use the historyService object, where messages are ordered in the order in which they happen, than it is to fake the history when sending, which risks getting the timing wrong.

The historyService contains some useful members to make retrieiving and staying up to date with the conversation easier. The activityItems collection is the actual list of conversation history items. To react everytime something is added to this collection, register a listener on activityItems.added:

conversation.historyService.activityItems.added(function (newMsg) {
   //do something with newMsg
});

Items in the activityItems collection have the following members and methods describing the conversation item. (there are others, but I’ve pulled out the interesting ones):

  • newMsg.key – a unique GUID which you can use to identify the message
  • newMsg.isRead – a boolean value. Set to false initially, but you can mark messages as read to make parsing for new messages easier if needed.
  • newMsg.direction() – either ‘Incoming’ or ‘Outgoing’ depending on the direction the message is travelling in
  • newMsg.text() – the plaintext version of the message
  • newMsg.html() – an HTML formatted version of the message, in a span tag
  • newMsg.timestamp() – timestamp of the message
  • newMsg.sender.uri – the sip address of the sender
  • newMsg.sender.person.displayName() – the display name of the sender, if it’s known. If not, the URI is shown instead.

You also have access to the entire person object (newMsg.sender.person) which you can use to subscribe to presence, get more information etc.

In the code sample below, the signed in user can send and receive instant messages with another user:

<div class="form-horizontal">
    <div class="form-group">
      <label for="username" class="col-sm-2 control-label">Username</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="username" placeholder="Email">
      </div>
    </div>
    <div class="form-group">
      <label for="password" class="col-sm-2 control-label">Password</label>
      <div class="col-sm-10">
        <input type="password" class="form-control" id="password" placeholder="Password">
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogIn">Log in</button>
      </div>
    </div>

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnLogOut">Log out</button>
      </div>
    </div>
  </div>

  <div>
    <span id="loginStatus"></span>
  </div>

  <hr/>

  <div class="form-horizontal">
    <div class="form-group">
      <label for="contact" class="col-sm-2 control-label">Start Conversation with:</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="contact" placeholder="Contact SIP Address">
      </div>
    </div>  

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnStartConversation" disabled="disabled">Start</button>
      </div>
    </div>
  </div>

  <div>
    Conversation State: <span id="lblConversationState"></span>
    <ul id='conversationText'></ul>

<hr/>

  <div class="form-horizontal">
    <div class="form-group">
      <label for="message" class="col-sm-2 control-label">Send Message:</label>
      <div class="col-sm-10">
        <input type="email" class="form-control" id="message" placeholder="Message to send">
      </div>
    </div>  

    <div class="form-group">
      <div class="col-sm-offset-2 col-sm-10">
        <button class="btn btn-default" id="btnSendIM" disabled="disabled">Send IM</button>
      </div>
    </div>
  </div>
  <div id="footer"></div>
  
  <!-- This is not needed for the samples to run, but adds standard headers and footers to the samples, to display title, instructions, about etc.
       If you're taking this code and using it yourself, you can remove this.-->
   <script type="text/javascript" src="../../assets/layoutcodesample-min.js"></script>
  
  <script type="text/javascript">

  <!-- These variables are only needed for laying out the code sample, they are not part of the sample code. -->
  var pageTitle = 'Receiving Instant Messages';
  var blogPostLocation = "http://thoughtstuff.co.uk";
  var githubLocation = "http://github.com";
 

   var client;
  $(function () {
    'use strict';

	Skype.initialize({
            apiKey: 'SWX-BUILD-SDK',
        }, function (api) {
            client = new api.application();           
			
		// whenever client.state changes, display its value
		client.signInManager.state.changed(function (state) {
		$('#loginStatus').text("Login State: " + state);
		});
	
        }, function (err) {
            alert('Error loading Skype Web SDK: ' + err);
        }); 

    $('#btnLogIn').click(function () {

        // start signing in
        client.signInManager.signIn({
          username: $('#username').val(),
          password: $('#password').val()
        }).then(function () {
            //log in worked!
            alert('Logged in!');
            $('#btnStartConversation').prop('disabled', false);
            
          }, function (error) {
            //Something went wrong.
            alert(error);
          });
      });

    $('#btnLogOut').click(function () {
        // start signing out
        client.signInManager.signOut()
        .then(function () {
               //log out worked!
               alert('Logged out!');
               $('#btnStartConversation').prop('disabled', true);
               $('#btnSendIM').prop('disabled', true);
             }, function (error) {
                //Something went wrong.
                alert(error);
              });
      });

    $('#btnStartConversation').click(function () {
      StartConversation($('#contact').val());
    });

        $('#btnSendIM').click(function () {
      conversation.chatService.sendMessage($('#message').val());
    });

  function StartConversation (contactSIP) {
  //first, get the person to start a conversation with. Assume one person.
  var person;
  GetContactFromName(contactSIP).then(function (results) {
    results.forEach(function (result) {
    person = result.result;          
  });

 //create the conversation object
 conversation = client.conversationsManager.createConversation();

 //add the person to the conversation by creating a conversation participant object
 var convParticipant = conversation.createParticipant(person);
 conversation.participants.add(convParticipant);

 //add the newly created conversation to the ConversationManager list
 client.conversationsManager.conversations.add(conversation);

//register for the conversation state changing to connected.
  conversation.chatService.state.changed(function(newState){
  $('#lblConversationState').text(newState);
  if (newState == 'Connected') {
    $('#btnSendIM').prop('disabled', false); //safe to send IMs now
  }
  });

//register for new messages added to the historyService object
  conversation.historyService.activityItems.added(function (newMsg){
    if (newMsg.type() == 'TextMessage')
    {
         var direction;
         if (newMsg.direction() == 'Incoming') 
            direction = "<--";          
         else
         {
            direction = "-->";          
          }

         $("#conversationText").append('<li><b>' + direction + '</b>&amp;nbsp; ' + newMsg.sender.displayName() + ' : ' + newMsg.text() + '</li>');  
    }
  });
 
 conversation.chatService.start();
});

}

function GetContactFromName(contactSIP)
{
 var query = client.personsAndGroupsManager.createPersonSearchQuery();
 query.text(contactSIP);
 query.limit(1);
 return query.getMore();          
}

});

</script>

Demo Online

You can try this code out against your own Skype for Business environment by going to the demo page. From here you can also download the code from GitHub if you want to host it locally, or take it and use it in your next project.

Disclaimer: This is sample code, intended to inform and educate. It is not production-ready and is lacking key components such as error handling. You use it entirely at your own risk. You should fully understand the effects, limitations and risks of the code before executing, and understand the implications of any set-up steps. By using these code examples you are using the Skype Web SDK, so you should read the Skype Software License Terms to which you are agreeing.

Good to Know

Written by Tom Morgan

Tom is a Microsoft Teams Platform developer and Microsoft MVP who has been blogging for over a decade. Find out more.
Buy the book: Building and Developing Apps & Bots for Microsoft Teams. Now available to purchase online with free updates.

Post a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.