Key Takeaways
- XMPP, or eXtensible Messaging and Presence Protocol, is a decentralized, open standard protocol for real-time communication, used by numerous applications for instant messaging, presence, multi-party chat, voice and video calls, and more.
- XMPP4R is a Ruby client library for XMPP, allowing developers to work with Ruby instead of generating XML, making it easier to build applications that can interact with XMPP servers.
- The tutorial demonstrates how to build a bot using XMPP and XMPP4R that responds to messages with custom or processed replies. The bot can accept new invites, process specific commands, and even parse feeds from a website to return the latest articles.
- The XMPP4R gem provides a lot of options that aren’t covered in the tutorial and is recommended for developers to try, especially for those who aim to build applications requiring real-time communication or data exchange.
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.
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