🚨 Shai-Hulud Strikes Again:834 Packages Compromised.Technical Analysis →
Socket
Book a DemoInstallSign in
Socket

pk-merb_messenger

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pk-merb_messenger

bundlerRubygems
Version
0.0.1
Version published
Maintainers
1
Created
Source

merb_messenger

A plugin for the Merb framework that provides messaging and notifications functionality.

The goal is to create a simple transport agnostic library that can be used for Jabber, Growl, HTTP, mail and other notifications with minimal effort in web controllers.

Actors

Core actors of this library are messaging controllers and transports. Messaging controllers are called from web controllers that handle incoming requests, render message templates, do messaging-related filtering and pass the result to transports to deliver.

Note that messaging controllers share rendering and filtering code with Merb core's AbstractController so no wheel is invented.

Transports and possible use cases

What transports do is up to specific implementation:

  • Jabber transport will deliver messages over XMPP
  • AMQP transport will talk to AMQP broker like RabbitMQ or ZeroMQ
  • mail transport will use SMTP or sendmail to send emails
  • HTTP POST transport will post data over HTTP ("web hooks")
  • Specific HTTP transport may post to Facebook, Twitter, LiveJournal or whatever it may be
  • IRC transport will flood some IRC channel.
  • SMS transport will deliver SMS one way or another
  • XMP-RPC transport will call some WS-* deathstars
  • Some futuristic crazy transport will send Rubinius VM bytecode over the wire to be executed on the other end

How to use this prototype

Messaging controllers are used from web controllers (that handle requests) and can render templates, have filters and all that. Transports can be used directly in models and not supposed to render (at least at this point in evolution of merb messenger).

Transports must be required explicitly at this point. Do it in init.rb or add config/messengers.rb and load it from init.rb, and require transport file there. This is because otherwise lazy loading can only be accomplished using Kernel#autoload which some people do not like (for instance, it is not thread safe in MRI).

Say we have a group journal/blog and we want to be notified on updates using Jabber. Our web controller action may look like this:

class Entries < Application def create(entry) @entry = Entry.new(entry) if @entry.save run_later do JournalMessenger.dispatch(:create, self, :entry => @entry) end redirect url(:entries) else @entries = Entry.all render :index end end end

As you can see, messaging controller is explicitly called from web controller using dispatch method. That method takes an action as a symbol, web controller instance (to have access to request parameters and session) and a Hash of extra options you'd like to pass to it.

Now lets look at our messenger:

class JournalMessenger < Merb::MessagingController delivery_options :lan_growl, :notification => "journal notification", :title => "New journal entry posted"

delivery_options :remote, :title => "New journal entry posted", :to => ["app.notifications@jabber.org"], :message_type => :chat

def create(options) # render the template in app/messengers/views/journal/create.text.erb body = render(:index)

# deliver using XMPP
# transport is called :remote
# in the application
deliver :remote,    :body => body
# deliver using Growl transport
# that is called :lan_growl across
# the app
deliver :lan_growl, :body => body

end end

Every messenger action takes a hash of options that includes web controller parameters and additional options you passed on dispatch.

Every messenger uses +deliver+ method to deliver notifications instantly and (in the future) +queue+ method to stack a notification in a queue to be delivered later. Queueing functionality will be 100% ORM agnostic.

This plugin is all about connecting your web controllers and transports. It supposed to be generic. Because message transports are very different, it's up to particular transport what options delivery and queue methods would take.

To eliminate the need to constantly duplicate some common options (like "from", "title" and similar), Merb messenger lets you set them up messenger-wide:

delivery_options :remote, :title => "Journal event", :to => ["app.notifications@jabber.org"], :message_type => :chat

Above we say that all messages that go via transport called "remote" (that is XMPP transport in this example) use title "Journal event", delivered to "app.notifications@jabber.org" and use message type "chat".

+deliver+ method's options are merged with class-wide delivery options before they are passed on to transport. Obviously, former take precedence over the latter.

Implementing transports

Transport API is simple and may be as little work as implementing a single method, deliver. Some transports that need to establish connection and handle disconnection may add a few more methods: connect, reconnect, disconnect. Those providing queuing functionality may add queue method that acts as deliver but does not do immediate delivery.

Here is a Jabber transport implementation that uses xmpp4r: require 'xmpp4r/client'

module Merb module Messenger class Xmpp4rTransport include ::Jabber

  class_inheritable_accessor :_default_delivery_options
  self._default_delivery_options = Mash.new(:message_type => :chat)

  def self.delivery_options(options)
    self._default_delivery_options = options
  end

  attr_reader :transport

  def initialize(options)
    @transport = Client.new(options[:jid])
    @transport.connect
    
    @transport.auth(options[:password])
  end

  def connect
    self.transport.connect
  end

  def disconnect
    self.transport.close
  end

  def deliver(options = {})
    options = _default_delivery_options.merge(options)
    
    m = Message.new(options[:to], options[:body])
    
    m.set_subject(options[:subject]) if options[:subject]
    m.set_subject(options[:id])      if options[:id]
    m.set_type(options[:message_type] || :normal)
    
    self.transport.send(m)
  end
end

end end

Setting transports up

Transports are usually set up before Merb loads your application classes, but it's obviously neither a requirement, nor a convention. It just makes messaging classes loaded before code that uses them loads.

To set up a transport you use Merb::Messenger.setup_transport method that takes transport name (can be anything, pick how you'd like to address that transport in your application), transport type alias (:growl, :xmpp4r, can be anything people already written transports for) and a Hash of options.

Since transports are so different by nature (Growl has host, port, password, notifications list and application name options, XMPP usually has jid, server, port, SASL/TLS options and password, smpt transport would have SMTP server settings, sendmail would have a sendmail path, etc), possible options are up to transport authors.

Merb::BootLoader.before_app_loads do Merb::Messenger.setup_transport(:lan_growl, :growl, { :application => "merbpack", :notifications => ["journal_notification"] }) end

You can use transports directly if you need to. For instance, you can set up a Jabber transport that's gonna notify you when Merb worker is shut down or restarted. This way you can be notified on crashes and application deployments.

Here is an example:

Merb::BootLoader.after_app_loads do im = Merb::MessagingController.message_transport :lan_growl

im.deliver({ :title => "MerbPack presence", :body => "MerbPack agent is back online", :notification => "presence notification" }) end

Merb::BootLoader.before_master_shutdown do Merb.logger.info "MerbPack agent is going offline..." im = Merb::MessagingController.message_transport :lan_growl

im.deliver({ :title => "MerbPack presence", :body => "MerbPack agent is about to shut down", :notification => "presence notification" }) end

Merb::BootLoader.before_worker_shutdown do Merb.logger.info "Shutting down worker..."

Merb::MessagingController.message_transport(:remote).disconnect end

Here we use two transports named :lan_growl and :remote. First uses Growl transport in local area network, and second is a Jabber transport that sends XMPP notifications.

We use them to notify people when application goes down and comes back up online.

The Future

Merb messenger will be part of Merb 1.1 in early 2009. The Holy Grails of this plugin is to provide simple generic interface for messaging of all kinds: from Jabber and mail notifications to talking to AMQP brokers like RabbitMQ or ZeroMQ, doing "web hooks" and so forth.

FAQs

Package last updated on 10 Aug 2014

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts