Looking at XMPP and the XMPP4R Gem

Share this article

XMPP
XMPP Official Logo

XMPP is “an open, XML-inspired protocol for near-real-time, extensible instant messaging and presence information.” — Wikipedia

The Extensible Messaging and Presence Protocol (XMPP) is an open technology for real-time communication, which powers a wide range of applications including instant messaging, presence, multi-party chat, voice and video calls, collaboration, lightweight middleware, content syndication, and generalized routing of XML data. — xmpp.org

The eXtensible Messaging and Presence Protocol, also known as Jabber (the protocol was originally named Jabber and was developed by the Jabber open-source community) is a protocol to exchange messages between 2 entities. Those messages are transmitted over the wire in the XML format. It’s used by Jabber, Google Talk, Google Wave, Pidgin, Kopete, and all sorts of open source instant messaging applications.

Advantages of XMPP

Decentralized

The XMPP network is decentralized in nature. There is no master or central server. Any one can own or run a XMPP Server.

Open Standards

The Internet Engineering Task Force has formalized XMPP as an approved instant messaging and presence technology under the name of XMPP (the latest specifications are RFC 6120 and RFC 6121). No royalties are required to implement support of these specifications and their development is not tied to a single vendor.

Stable and Secure

XMPP has been in effect since 1999 and many applications have used this protocol since. Since XMPP servers can be isolated or hosted on a private network behind secure firewalls, it is very secure.

Flexible

One of the main advantage of this protocol is its flexiblilty. Custom functionality can be built on top of XMPP very easily. The flexible nature of the protocol makes it the perfect choice for writing IM-bots, chat clients etc., as it will automatically work with all the IM services XMPP has to offer.

XMPP4R – Ruby Client Library for XMPP

XMPP4R is a Ruby wrapper over the standard XML that XMPP/Jabber/Ejabberd uses, thus allowing us to work with Ruby rather than generate XML.

Installation

gem install xmpp4r
    or
sudo gem install xmpp4r

XMPP Server

Ejabberd is a Jabber/XMPP server built using Erlang and is open-source. Another popular alternative for Ejabberd is Openfire. Installation instructions for ejabbered can be found here. We wont be using a XMPP Server like ejabbered or Openfire in this example, instead opting for a Google account, which is easy and convenient.

XMPP Bot

Building a Bot is an ideal way to introduce the XMPP protocol and the Ruby Wrapper for XMPP – XMPP4R. As such, I will be building a bot that responds to our messages and replies with custom messages or results.

Install Gems/Libraries Required

gem install xmpp4r

Connecting to the Jabber Server

require 'xmpp4r'
require 'xmpp4r/client'
include Jabber

class Bot

  attr_reader :client

  def initialize jabber_id
    @jabber_id = jabber_id
    @jabber_password = ENV['jabber_password']
  end

  def connect
    jid = JID.new(@jabber_id)
    @client = Client.new jid
    @client.connect
    @client.auth @jabber_password
    @client.send(Presence.new.set_type(:available))
    puts "Hurray...!!  Connected..!!"
  end
end

Bot.new('neo@codingarena.in').connect

The above code illustrates how to connect to our Jabber server, or in our case, Google’s servers. The Jabber ID is provided when instantiating a new Bot instance and the password is retrieved from an environment variable. The connect method creates a new object of the Jabber client, connects to the server, and authenticates using the password specified. Also the presence is set to ‘available’. Other options that can be passed are :busy, :invisible.

Sending and Receiving Messages

Sending a message is as simple as follows:

message = Message.new("manu@codingarena.in", "Hello... Manu?")
message.type=:chat
@client.send(message)

The add_method_callback method can be used for recieving and processing the messages that our bot receives.

@client.add_message_callback do |message|
  unless message.body.nil? && message.type != :error
    puts "Received message: #{message.body}"
    #Echo the received message back to the sender.
    reply = Message.new(message.from, message.body)
    reply.type = message.type
    @client.send(reply)
  end
end

Accepting New Invites

def roster
  @roster ||= Roster::Helper.new(@client)
end

def process_invite
  roster.add_subscription_request_callback do |_, presence|
    inviter = JID::new(presence.from)
    roster.accept_subscription(inviter)
    invite(JID::new(inviter))
  end
end

Roster is our bot’s contact list. Whenever a new user adds our bot and sends an invite, the roster_add_subscription_request_callback gets triggered, which would automatically accept the new invite.

Teach our bot some commands

Having built a simple and basic bot using XMPP, we will now try to process the messages received by our bot and play around little bit.

How about we ask our bot some questions or commands and see if it responds to our message with custom or processed replies? The message received by out chat bot could be processed so that it will reply to some specific commands. For example, our bot will process ‘Help’ to return all the commands that our bot knows or ‘Time’ to reply with the current time.

@client.add_message_callback do |message|
  unless message.body.nil? && message.type != :error
    reply = case message.body
      when "Time" then reply(message, "Current time is #{Time.now}")
      when "Help" then reply(message, "Available commands are: 'Time', 'Help', 'Latest sitepoint articles.")
      when "Latest sitepoint articles" then latest_sitepoint_articles(message)
      else reply(message, "You said: #{message.body}")
    end
  end
end

def reply message, reply_content
  reply_message = Message.new(message.from, reply_content)
  reply_message.type = message.type
  @client.send reply_message
end

def latest_sitepoint_articles message
  feeds = SitepointFeedParser.get_feeds
  feeds.items.each do |item|
    reply(message, item.link)
  end
end

class SitepointFeedParser
  URL = 'https://www.sitepoint.com/feed/'
  class << self
    def get_feeds
      open(URL) do |rss|
        @feeds = RSS::Parser.parse(rss)
      end
      @feeds
    end
  end
end

When a user sends ‘Latest sitepoint articles’ our bot would parse the feeds from sitepoint.com and return the links to the latest articles. The RSS module is used for parsing the feeds, which are iterated over and each link is sent back to the user.

Daemonize the Bot

require 'rubygems'
require 'daemons'

Daemons.run('bot.rb',
  {
    app_name: 'myIMBot',
    monitor: true,
    log_output: false
  }
)

Using the daemons gem, we run our bot as a daemon. It also gives us options to start, restart, and stop the daemon using ruby im.rb start, ruby im.rb restart, and ruby im.rb stop, respectively. We can get the current status of the daemon using ruby im.rb status.

Also, monit gives us options for monitoring the daemon. The output of the daemon can be logged if log_output is set to true.

Putting It All Together

require 'xmpp4r'
require 'xmpp4r/client'
require 'xmpp4r/roster'
require 'rss'
require 'open-uri'
include Jabber

class Bot

  attr_reader :client

  def initialize jabber_id
    @jabber_id = jabber_id
    @jabber_password = ENV['jabber_password']
  end

  def connect
    jid = JID.new(@jabber_id)
    @client = Client.new jid
    @client.connect
    @client.auth @jabber_password
    @client.send(Presence.new.set_type(:available))
    puts "Hurray...!!  Connected..!!"
    on_message
  end

  private
  def on_message
    mainthread = Thread.current
    @client.add_message_callback do |message|
      unless message.body.nil? && message.type != :error
        reply = case message.body
          when "Time" then reply(message, "Current time is #{Time.now}")
          when "Help" then reply(message, "Available commands are: 'Time', 'Help'.")
          when "Latest sitepoint articles" then latest_sitepoint_articles(message)
          else reply(message, "You said: #{message.body}")
        end
      end
    end
    Thread.stop
    @client.close
  end

  def reply message, reply_content
    reply_message = Message.new(message.from, reply_content)
    reply_message.type = message.type
    @client.send reply_message
  end

  def latest_sitepoint_articles message
    feeds = SitepointFeedParser.get_feeds
    feeds.items.each do |item|
      reply(message, item.link)
    end
  end

end

class SitepointFeedParser

  URL = 'https://www.sitepoint.com/feed/'
  class << self
    def get_feeds
      open(URL) do |rss|
        @feeds = RSS::Parser.parse(rss)
      end
      @feeds
    end
  end

end

@bot = Bot.new 'manusajith@gmail.com'
@bot.connect

The code can be found here.

Conclusion

If you havent tried the XMPP or XMPP4R, I would recommend you to give it a shot. XMPP4R has a lot of other options that aren’t covered in this tutorial. Please check the official website for more details.

PS: I am one of the current maintainers of xmpp4r, if you have any questions, just give me a shout. Also, if you find any bugs/issues, please report them. Thanks in advance.

Frequently Asked Questions about XMPP and XMPP4r Gem

What is XMPP and why is it important?

XMPP stands for Extensible Messaging and Presence Protocol. It is an open-source protocol that allows for real-time communication and data exchange over the internet. It is important because it provides a standardized way for applications to communicate with each other, making it easier for developers to build applications that can interact with each other in real-time. It is widely used in instant messaging, presence information, and contact list maintenance.

How does XMPP4r gem work?

XMPP4r is a Ruby library for the XMPP protocol. It provides a simple and intuitive interface for developers to interact with XMPP servers. It handles the low-level details of the protocol, allowing developers to focus on the logic of their applications. It supports a wide range of XMPP features, including messaging, presence, and roster management.

What are the alternatives to XMPP?

There are several alternatives to XMPP, including MQTT, AMQP, and STOMP. These protocols also provide real-time communication capabilities, but they have different features and use cases. For example, MQTT is designed for lightweight and low-power scenarios, while AMQP provides more advanced messaging features.

How does XMPP compare to its alternatives?

XMPP is known for its simplicity and flexibility. It is easy to use and can be extended to support a wide range of applications. However, it may not be as efficient as some of its alternatives in certain scenarios. For example, MQTT is more efficient in terms of bandwidth usage, while AMQP provides more reliable message delivery.

How can I use XMPP in my application?

To use XMPP in your application, you need to have an XMPP server and a client library that supports XMPP. The server handles the communication between clients, while the client library allows your application to interact with the server. There are many XMPP servers and client libraries available, including XMPP4r for Ruby.

What is the role of XMPP in instant messaging?

XMPP is the backbone of many instant messaging systems. It provides the necessary features for real-time communication, including message exchange, presence information, and contact list maintenance. It also supports multi-user chat, offline messages, and other advanced features.

Can I use XMPP for other applications besides instant messaging?

Yes, XMPP is not limited to instant messaging. It can be used for any application that requires real-time communication or data exchange. This includes gaming, social networking, collaboration tools, and more.

Is XMPP secure?

XMPP supports a variety of security features, including SSL/TLS encryption, SASL authentication, and access control. However, the security of an XMPP system also depends on the configuration of the server and the client software.

How can I extend XMPP?

XMPP is designed to be extensible. You can extend it by defining new XML namespaces and adding them to the protocol. There are also many existing extensions, known as XEPs, that you can use.

What is the future of XMPP?

XMPP continues to be a popular choice for real-time communication. It is being used in a growing number of applications, and new extensions are being developed to support new use cases. With its open-source nature and active community, XMPP is expected to remain a key player in the field of real-time communication.

Manu AjithManu Ajith
View Author

Tech Entrepreneur. Writes Elixir, Ruby, Go for a living. Into functional paradigms DDD/CQRS/EventSourcing architecture these days. @manusajith on the interwebs. Lazy blogger who scribbles at Til.Codes

Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week