pk-merb_messenger 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README +270 -0
- data/Rakefile +51 -0
- data/TODO +9 -0
- data/lib/merb_messenger.rb +43 -0
- data/lib/merb_messenger/merbtasks.rb +6 -0
- data/lib/merb_messenger/messaging_controller.rb +106 -0
- data/lib/merb_messenger/messaging_mixin.rb +7 -0
- data/lib/merb_messenger/transports/growl.rb +32 -0
- data/lib/merb_messenger/transports/mailfactory.rb +92 -0
- data/lib/merb_messenger/transports/xmpp4r.rb +45 -0
- metadata +76 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Michael Klishin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,270 @@
|
|
1
|
+
merb_messenger
|
2
|
+
==============
|
3
|
+
|
4
|
+
A plugin for the Merb framework that provides
|
5
|
+
messaging and notifications functionality.
|
6
|
+
|
7
|
+
The goal is to create a simple transport agnostic
|
8
|
+
library that can be used for Jabber, Growl, HTTP,
|
9
|
+
mail and other notifications with minimal effort
|
10
|
+
in web controllers.
|
11
|
+
|
12
|
+
Actors
|
13
|
+
==============
|
14
|
+
|
15
|
+
Core actors of this library are messaging controllers
|
16
|
+
and transports. Messaging controllers are called
|
17
|
+
from web controllers that handle incoming requests,
|
18
|
+
render message templates, do messaging-related
|
19
|
+
filtering and pass the result to transports to deliver.
|
20
|
+
|
21
|
+
Note that messaging controllers share rendering and
|
22
|
+
filtering code with Merb core's AbstractController so
|
23
|
+
no wheel is invented.
|
24
|
+
|
25
|
+
Transports and possible use cases
|
26
|
+
=====================================
|
27
|
+
|
28
|
+
What transports do is up to specific implementation:
|
29
|
+
|
30
|
+
* Jabber transport will deliver messages over XMPP
|
31
|
+
* AMQP transport will talk to AMQP broker like RabbitMQ or ZeroMQ
|
32
|
+
* mail transport will use SMTP or sendmail to send emails
|
33
|
+
* HTTP POST transport will post data over HTTP ("web hooks")
|
34
|
+
* Specific HTTP transport may post to Facebook, Twitter, LiveJournal or whatever it may be
|
35
|
+
* IRC transport will flood some IRC channel.
|
36
|
+
* SMS transport will deliver SMS one way or another
|
37
|
+
* XMP-RPC transport will call some WS-* deathstars
|
38
|
+
* Some futuristic crazy transport will send Rubinius VM bytecode
|
39
|
+
over the wire to be executed on the other end
|
40
|
+
|
41
|
+
|
42
|
+
How to use this prototype
|
43
|
+
==============================
|
44
|
+
|
45
|
+
Messaging controllers are used from web controllers
|
46
|
+
(that handle requests) and can render templates,
|
47
|
+
have filters and all that. Transports can be used
|
48
|
+
directly in models and not supposed to render
|
49
|
+
(at least at this point in evolution of merb messenger).
|
50
|
+
|
51
|
+
Transports must be required explicitly at this point. Do it
|
52
|
+
in init.rb or add config/messengers.rb and load it from init.rb,
|
53
|
+
and require transport file there. This is because otherwise
|
54
|
+
lazy loading can only be accomplished using Kernel#autoload
|
55
|
+
which some people do not like (for instance, it is not thread
|
56
|
+
safe in MRI).
|
57
|
+
|
58
|
+
Say we have a group journal/blog and we want to be notified
|
59
|
+
on updates using Jabber. Our web controller action may
|
60
|
+
look like this:
|
61
|
+
|
62
|
+
class Entries < Application
|
63
|
+
def create(entry)
|
64
|
+
@entry = Entry.new(entry)
|
65
|
+
if @entry.save
|
66
|
+
run_later do
|
67
|
+
JournalMessenger.dispatch(:create, self, :entry => @entry)
|
68
|
+
end
|
69
|
+
redirect url(:entries)
|
70
|
+
else
|
71
|
+
@entries = Entry.all
|
72
|
+
render :index
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
As you can see, messaging controller is explicitly called from web controller
|
78
|
+
using dispatch method. That method takes an action as a symbol, web controller
|
79
|
+
instance (to have access to request parameters and session) and a Hash of extra
|
80
|
+
options you'd like to pass to it.
|
81
|
+
|
82
|
+
Now lets look at our messenger:
|
83
|
+
|
84
|
+
class JournalMessenger < Merb::MessagingController
|
85
|
+
delivery_options :lan_growl,
|
86
|
+
:notification => "journal notification",
|
87
|
+
:title => "New journal entry posted"
|
88
|
+
|
89
|
+
delivery_options :remote,
|
90
|
+
:title => "New journal entry posted",
|
91
|
+
:to => ["app.notifications@jabber.org"],
|
92
|
+
:message_type => :chat
|
93
|
+
|
94
|
+
def create(options)
|
95
|
+
# render the template in app/messengers/views/journal/create.text.erb
|
96
|
+
body = render(:index)
|
97
|
+
|
98
|
+
# deliver using XMPP
|
99
|
+
# transport is called :remote
|
100
|
+
# in the application
|
101
|
+
deliver :remote, :body => body
|
102
|
+
# deliver using Growl transport
|
103
|
+
# that is called :lan_growl across
|
104
|
+
# the app
|
105
|
+
deliver :lan_growl, :body => body
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Every messenger action takes a hash of options that includes web controller
|
110
|
+
parameters and additional options you passed on dispatch.
|
111
|
+
|
112
|
+
Every messenger uses +deliver+ method to deliver notifications instantly
|
113
|
+
and (in the future) +queue+ method to stack a notification in a queue to
|
114
|
+
be delivered later. Queueing functionality will be 100% ORM agnostic.
|
115
|
+
|
116
|
+
This plugin is all about connecting your web controllers and transports.
|
117
|
+
It supposed to be generic. Because message transports are very
|
118
|
+
different, it's up to particular transport what
|
119
|
+
options delivery and queue methods would take.
|
120
|
+
|
121
|
+
To eliminate the need to constantly duplicate some common options (like "from",
|
122
|
+
"title" and similar), Merb messenger lets you set them up messenger-wide:
|
123
|
+
|
124
|
+
delivery_options :remote,
|
125
|
+
:title => "Journal event",
|
126
|
+
:to => ["app.notifications@jabber.org"],
|
127
|
+
:message_type => :chat
|
128
|
+
|
129
|
+
Above we say that all messages that go via transport called "remote"
|
130
|
+
(that is XMPP transport in this example) use title "Journal event",
|
131
|
+
delivered to "app.notifications@jabber.org" and use message type
|
132
|
+
"chat".
|
133
|
+
|
134
|
+
+deliver+ method's options are merged with class-wide delivery options
|
135
|
+
before they are passed on to transport. Obviously, former take
|
136
|
+
precedence over the latter.
|
137
|
+
|
138
|
+
Implementing transports
|
139
|
+
========================
|
140
|
+
|
141
|
+
Transport API is simple and may be as little work as implementing a
|
142
|
+
single method, deliver. Some transports that need to establish connection and
|
143
|
+
handle disconnection may add a few more methods: connect, reconnect, disconnect.
|
144
|
+
Those providing queuing functionality may add queue method that acts as deliver
|
145
|
+
but does not do immediate delivery.
|
146
|
+
|
147
|
+
Here is a Jabber transport implementation that uses xmpp4r:
|
148
|
+
require 'xmpp4r/client'
|
149
|
+
|
150
|
+
module Merb
|
151
|
+
module Messenger
|
152
|
+
class Xmpp4rTransport
|
153
|
+
include ::Jabber
|
154
|
+
|
155
|
+
class_inheritable_accessor :_default_delivery_options
|
156
|
+
self._default_delivery_options = Mash.new(:message_type => :chat)
|
157
|
+
|
158
|
+
def self.delivery_options(options)
|
159
|
+
self._default_delivery_options = options
|
160
|
+
end
|
161
|
+
|
162
|
+
attr_reader :transport
|
163
|
+
|
164
|
+
def initialize(options)
|
165
|
+
@transport = Client.new(options[:jid])
|
166
|
+
@transport.connect
|
167
|
+
|
168
|
+
@transport.auth(options[:password])
|
169
|
+
end
|
170
|
+
|
171
|
+
def connect
|
172
|
+
self.transport.connect
|
173
|
+
end
|
174
|
+
|
175
|
+
def disconnect
|
176
|
+
self.transport.close
|
177
|
+
end
|
178
|
+
|
179
|
+
def deliver(options = {})
|
180
|
+
options = _default_delivery_options.merge(options)
|
181
|
+
|
182
|
+
m = Message.new(options[:to], options[:body])
|
183
|
+
|
184
|
+
m.set_subject(options[:subject]) if options[:subject]
|
185
|
+
m.set_subject(options[:id]) if options[:id]
|
186
|
+
m.set_type(options[:message_type] || :normal)
|
187
|
+
|
188
|
+
self.transport.send(m)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
Setting transports up
|
196
|
+
=======================
|
197
|
+
|
198
|
+
Transports are usually set up before Merb loads your application
|
199
|
+
classes, but it's obviously neither a requirement, nor a convention.
|
200
|
+
It just makes messaging classes loaded before code that uses them loads.
|
201
|
+
|
202
|
+
To set up a transport you use
|
203
|
+
Merb::Messenger.setup_transport method that takes transport name
|
204
|
+
(can be anything, pick how you'd like to address that transport in your
|
205
|
+
application), transport type alias (:growl, :xmpp4r, can be anything people
|
206
|
+
already written transports for) and a Hash of options.
|
207
|
+
|
208
|
+
Since transports are so different by nature (Growl has host, port, password,
|
209
|
+
notifications list and application name options, XMPP usually has jid, server,
|
210
|
+
port, SASL/TLS options and password, smpt transport would have SMTP server
|
211
|
+
settings, sendmail would have a sendmail path, etc), possible options are
|
212
|
+
up to transport authors.
|
213
|
+
|
214
|
+
Merb::BootLoader.before_app_loads do
|
215
|
+
Merb::Messenger.setup_transport(:lan_growl, :growl, {
|
216
|
+
:application => "merbpack",
|
217
|
+
:notifications => ["journal_notification"]
|
218
|
+
})
|
219
|
+
end
|
220
|
+
|
221
|
+
You can use transports directly if you need to. For instance,
|
222
|
+
you can set up a Jabber transport that's gonna notify you
|
223
|
+
when Merb worker is shut down or restarted. This way you
|
224
|
+
can be notified on crashes and application deployments.
|
225
|
+
|
226
|
+
Here is an example:
|
227
|
+
|
228
|
+
Merb::BootLoader.after_app_loads do
|
229
|
+
im = Merb::MessagingController.message_transport :lan_growl
|
230
|
+
|
231
|
+
im.deliver({
|
232
|
+
:title => "MerbPack presence",
|
233
|
+
:body => "MerbPack agent is back online",
|
234
|
+
:notification => "presence notification"
|
235
|
+
})
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
Merb::BootLoader.before_master_shutdown do
|
240
|
+
Merb.logger.info "MerbPack agent is going offline..."
|
241
|
+
im = Merb::MessagingController.message_transport :lan_growl
|
242
|
+
|
243
|
+
im.deliver({
|
244
|
+
:title => "MerbPack presence",
|
245
|
+
:body => "MerbPack agent is about to shut down",
|
246
|
+
:notification => "presence notification"
|
247
|
+
})
|
248
|
+
end
|
249
|
+
|
250
|
+
Merb::BootLoader.before_worker_shutdown do
|
251
|
+
Merb.logger.info "Shutting down worker..."
|
252
|
+
|
253
|
+
Merb::MessagingController.message_transport(:remote).disconnect
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
Here we use two transports named :lan_growl and :remote. First uses
|
258
|
+
Growl transport in local area network, and second is a Jabber transport
|
259
|
+
that sends XMPP notifications.
|
260
|
+
|
261
|
+
We use them to notify people when application goes down and comes back
|
262
|
+
up online.
|
263
|
+
|
264
|
+
The Future
|
265
|
+
===================
|
266
|
+
|
267
|
+
Merb messenger will be part of Merb 1.1 in early 2009. The Holy Grails of
|
268
|
+
this plugin is to provide simple generic interface for messaging of all
|
269
|
+
kinds: from Jabber and mail notifications to talking to AMQP brokers
|
270
|
+
like RabbitMQ or ZeroMQ, doing "web hooks" and so forth.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
require 'merb-core'
|
5
|
+
require 'merb-core/tasks/merb'
|
6
|
+
|
7
|
+
GEM_NAME = "merb_messenger"
|
8
|
+
GEM_VERSION = "0.0.1"
|
9
|
+
AUTHOR = "Michael Klishin"
|
10
|
+
EMAIL = "michael@novemberain.com"
|
11
|
+
HOMEPAGE = "http://merbivore.com/"
|
12
|
+
SUMMARY = "Merb plugin that provides messaging/notifications functionality: from email and XMPP to AMPQ and beyond."
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.rubyforge_project = 'merb'
|
16
|
+
s.name = GEM_NAME
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = false
|
20
|
+
s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = SUMMARY
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
s.add_dependency('merb-core', '>= 1.1')
|
27
|
+
s.require_path = 'lib'
|
28
|
+
s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
33
|
+
pkg.gem_spec = spec
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "install the plugin as a gem"
|
37
|
+
task :install do
|
38
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "Uninstall the gem"
|
42
|
+
task :uninstall do
|
43
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Create a gemspec file"
|
47
|
+
task :gemspec do
|
48
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
49
|
+
file.puts spec.to_ruby
|
50
|
+
end
|
51
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
* Finally put spec suite I have online.
|
2
|
+
* Add more spec examples.
|
3
|
+
* Add event more spec examples.
|
4
|
+
* F*cking spec examples!!
|
5
|
+
* Mail transport.
|
6
|
+
* HTTP transport (should use Tony Arcieri's FastHTTP library).
|
7
|
+
* Queueing functionality for existing transports.
|
8
|
+
* AMQP integration.
|
9
|
+
* Extensions for RPC, WS-* deathstars and the rest of existing ecosystem.
|
@@ -0,0 +1,43 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
# make sure we're running inside Merb
|
4
|
+
if defined?(Merb::Plugins)
|
5
|
+
# Register path for messengers under app/messengers
|
6
|
+
Merb.push_path(:messenger, Merb.root / "app"/ "messengers")
|
7
|
+
|
8
|
+
require "merb_messenger/messaging_controller"
|
9
|
+
require "merb_messenger/messaging_mixin"
|
10
|
+
|
11
|
+
module Merb
|
12
|
+
module Messenger
|
13
|
+
@@test_deliveries = Hash.new([])
|
14
|
+
|
15
|
+
def self.clean_test_deliveries!
|
16
|
+
@@test_deliveries = Hash.new([])
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.test_deliveries
|
20
|
+
@@test_deliveries
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup_transport(name, type, options)
|
24
|
+
begin
|
25
|
+
# Try to load custom Transports from project/merb/merb_messenger/transports
|
26
|
+
require Merb.root / 'merb' / 'merb_messenger' / 'transports' / type.to_s
|
27
|
+
rescue LoadError => e
|
28
|
+
# Try to load bundled Transports
|
29
|
+
require "merb_messenger/transports/#{type.to_s}"
|
30
|
+
end
|
31
|
+
|
32
|
+
::Merb::MessagingController.message_transport(name, type, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
module_function :setup_transport
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Merb::Plugins.config[:merb_messenger] = {
|
40
|
+
}
|
41
|
+
|
42
|
+
Merb::Plugins.add_rakefiles "merb_messenger/merbtasks"
|
43
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Merb
|
2
|
+
class MessagingController < AbstractController
|
3
|
+
#include Merb::Messenger::Transport
|
4
|
+
|
5
|
+
attr_reader :params, :web_controller
|
6
|
+
|
7
|
+
class_inheritable_accessor :_message_transports, :_default_delivery_options
|
8
|
+
|
9
|
+
self._message_transports = Mash.new
|
10
|
+
self._default_delivery_options = Mash.new
|
11
|
+
|
12
|
+
cattr_accessor :_subclasses
|
13
|
+
self._subclasses = Set.new
|
14
|
+
|
15
|
+
|
16
|
+
render_options :format => :text
|
17
|
+
|
18
|
+
def self.subclasses_list
|
19
|
+
_subclasses
|
20
|
+
end
|
21
|
+
|
22
|
+
def _template_location(action, type = :text, controller = controller_name)
|
23
|
+
"#{controller}/#{action}.#{type}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def _absolute_template_location(template, type)
|
27
|
+
template.match(/\.#{type.to_s.escape_regexp}$/) ? template : "#{template}.#{type}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.inherited(klass)
|
31
|
+
_subclasses << klass.to_s
|
32
|
+
super
|
33
|
+
|
34
|
+
klass._template_root ||= Merb.dir_for(:messenger) / "views"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def self.dispatch(message, web_controller, options = {}, msg_options = {})
|
39
|
+
self.new(web_controller, options).__send__(message, msg_options)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.message_transport(name = :default, type = nil, options = nil)
|
43
|
+
return self._message_transports[name] if type.blank?
|
44
|
+
|
45
|
+
klass = Merb::Messenger.const_get("#{type.to_s.camel_case}Transport")
|
46
|
+
t = klass.new(options)
|
47
|
+
self._message_transports[name] = t
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.delivery_options(name = :default, value = nil)
|
51
|
+
return self._default_delivery_options[name] unless value
|
52
|
+
self._default_delivery_options[name] = value
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
def initialize(web_controller, opts = {})
|
58
|
+
@web_controller = web_controller
|
59
|
+
@params = Mash.new(@web_controller.params.dup)
|
60
|
+
|
61
|
+
@params.merge!(opts) unless opts.blank?
|
62
|
+
super
|
63
|
+
|
64
|
+
@content_type = @web_controller.content_type
|
65
|
+
end
|
66
|
+
|
67
|
+
def transport
|
68
|
+
self.class._transport
|
69
|
+
end
|
70
|
+
|
71
|
+
def deliver(client = :default, options = {})
|
72
|
+
opts = (self._default_delivery_options[client] || {}).
|
73
|
+
merge(self.params).
|
74
|
+
merge(options)
|
75
|
+
|
76
|
+
[opts[:to]].flatten.each do |to|
|
77
|
+
self._message_transports[client].deliver(opts.merge(:to => to))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def session
|
82
|
+
self.web_controller.request.session rescue {}
|
83
|
+
end
|
84
|
+
|
85
|
+
def request
|
86
|
+
self.web_controller.request
|
87
|
+
end
|
88
|
+
|
89
|
+
# Mimic the behavior of absolute_url in AbstractController
|
90
|
+
# but use @web_controller.request
|
91
|
+
def url(name, *args)
|
92
|
+
return web_controller.url(name, *args) if web_controller
|
93
|
+
super
|
94
|
+
end
|
95
|
+
|
96
|
+
alias_method :relative_url, :url
|
97
|
+
|
98
|
+
# Mimic the behavior of absolute_url in AbstractController
|
99
|
+
# but use @web_controller.request
|
100
|
+
def absolute_url(name, *args)
|
101
|
+
return web_controller.absolute_url(name, *args) if web_controller
|
102
|
+
super
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'ruby-growl'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
module Messenger
|
5
|
+
class GrowlTransport
|
6
|
+
class_inheritable_accessor :_default_delivery_options
|
7
|
+
self._default_delivery_options = Mash.new
|
8
|
+
|
9
|
+
def self.delivery_options(options)
|
10
|
+
self._default_delivery_options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :transport
|
14
|
+
|
15
|
+
def initialize(options)
|
16
|
+
@transport = ::Growl.new(options[:host], options[:application], options[:notifications])
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect
|
20
|
+
end
|
21
|
+
|
22
|
+
def disconnect
|
23
|
+
end
|
24
|
+
|
25
|
+
def deliver(options = {})
|
26
|
+
options = _default_delivery_options.merge(options)
|
27
|
+
|
28
|
+
self.transport.notify(options[:notification], options[:title], options[:body])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Merb
|
2
|
+
module Messenger
|
3
|
+
class MailTransport
|
4
|
+
attr_reader :delivery_strategy, :composition_strategy
|
5
|
+
|
6
|
+
class_inheritable_accessor :_default_delivery_options
|
7
|
+
self._default_delivery_options = Mash.new(:message_type => :chat)
|
8
|
+
|
9
|
+
def self.delivery_options(options)
|
10
|
+
self._default_delivery_options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
@delivery_strategy = options[:deliver_with] || :sendmail
|
15
|
+
@composition_strategy = options[:compose_with] || :mailfactory
|
16
|
+
end
|
17
|
+
|
18
|
+
def deliver(options = {})
|
19
|
+
options = _default_delivery_options.merge(options)
|
20
|
+
|
21
|
+
email = case self.composition_strategy
|
22
|
+
when :mailfactory then compose_with_mailfactory(options)
|
23
|
+
when :tmail then compose_with_tmail(options)
|
24
|
+
when Proc then self.composition_strategy.call(options)
|
25
|
+
when Class then compose_with_custom_strategy(options)
|
26
|
+
else
|
27
|
+
self.send "compose_with_#{self.composition_strategy}"
|
28
|
+
end
|
29
|
+
|
30
|
+
case self.delivery_strategy
|
31
|
+
when :sendmail, :send_mail then deliver_with_sendmail(email, options)
|
32
|
+
when :smtp, :netsmtp, :net_smtp then deliver_with_smtp(email, options)
|
33
|
+
when Proc then self.delivery_strategy.call(email, options)
|
34
|
+
when Class then deliver_with_custom_strategy(email, options)
|
35
|
+
else
|
36
|
+
self.send "deliver_with_#{self.delivery_strategy}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def compose_with_mailfactory(options)
|
43
|
+
email = MailFactory.new
|
44
|
+
email.from = options[:from]
|
45
|
+
|
46
|
+
[options[:reply_to] || []].flatten.each do |address|
|
47
|
+
email.add_header "Reply-To", address
|
48
|
+
end
|
49
|
+
[options[:to] || []].flatten.each do |address|
|
50
|
+
email.add_header "To", address
|
51
|
+
end
|
52
|
+
[options[:cc] || []].flatten.each do |address|
|
53
|
+
email.add_header "Cc", address
|
54
|
+
end
|
55
|
+
|
56
|
+
email.subject = options[:subject] if options[:subject]
|
57
|
+
email.text = options[:text] if options[:text]
|
58
|
+
email.html = options[:html] if options[:html]
|
59
|
+
|
60
|
+
email
|
61
|
+
end
|
62
|
+
|
63
|
+
def compose_with_tmail(options)
|
64
|
+
# TODO
|
65
|
+
end
|
66
|
+
|
67
|
+
def compose_with_custom_strategy(options)
|
68
|
+
# TODO
|
69
|
+
end
|
70
|
+
|
71
|
+
def deliver_with_sendmail(email, options)
|
72
|
+
if Merb.testing?
|
73
|
+
Merb::Messenger.test_deliveries[:email].push email
|
74
|
+
else
|
75
|
+
recepients = [options[:to] || []].flatten.join(',')
|
76
|
+
Merb.logger.info! "Sending email with sendmail #{recepients}"
|
77
|
+
IO.popen("sendmail #{recepients}", 'w+') do |sendmail|
|
78
|
+
sendmail.puts email.to_s
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end # deliver_with_sendmail
|
82
|
+
|
83
|
+
def deliver_with_smtp(email, options)
|
84
|
+
# TODO
|
85
|
+
end
|
86
|
+
|
87
|
+
def deliver_with_custom_strategy(email, options)
|
88
|
+
# TODO
|
89
|
+
end # deliver_with_custom_strategy
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'xmpp4r/client'
|
2
|
+
|
3
|
+
module Merb
|
4
|
+
module Messenger
|
5
|
+
class Xmpp4rTransport
|
6
|
+
include ::Jabber
|
7
|
+
|
8
|
+
class_inheritable_accessor :_default_delivery_options
|
9
|
+
self._default_delivery_options = Mash.new(:message_type => :chat)
|
10
|
+
|
11
|
+
def self.delivery_options(options)
|
12
|
+
self._default_delivery_options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :transport
|
16
|
+
|
17
|
+
def initialize(options)
|
18
|
+
@transport = Client.new(options[:jid])
|
19
|
+
@transport.connect
|
20
|
+
|
21
|
+
@transport.auth(options[:password])
|
22
|
+
end
|
23
|
+
|
24
|
+
def connect
|
25
|
+
self.transport.connect
|
26
|
+
end
|
27
|
+
|
28
|
+
def disconnect
|
29
|
+
self.transport.close
|
30
|
+
end
|
31
|
+
|
32
|
+
def deliver(options = {})
|
33
|
+
options = _default_delivery_options.merge(options)
|
34
|
+
|
35
|
+
m = Message.new(options[:to], options[:body])
|
36
|
+
|
37
|
+
m.set_subject(options[:subject]) if options[:subject]
|
38
|
+
m.set_subject(options[:id]) if options[:id]
|
39
|
+
m.set_type(options[:message_type] || :normal)
|
40
|
+
|
41
|
+
self.transport.send(m)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pk-merb_messenger
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Klishin
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-15 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: merb-core
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "1.1"
|
24
|
+
version:
|
25
|
+
description: "Merb plugin that provides messaging/notifications functionality: from email and XMPP to AMPQ and beyond."
|
26
|
+
email: michael@novemberain.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- LICENSE
|
34
|
+
- TODO
|
35
|
+
files:
|
36
|
+
- LICENSE
|
37
|
+
- README
|
38
|
+
- Rakefile
|
39
|
+
- TODO
|
40
|
+
- lib/merb_messenger
|
41
|
+
- lib/merb_messenger/merbtasks.rb
|
42
|
+
- lib/merb_messenger/messaging_controller.rb
|
43
|
+
- lib/merb_messenger/messaging_mixin.rb
|
44
|
+
- lib/merb_messenger/transports
|
45
|
+
- lib/merb_messenger/transports/growl.rb
|
46
|
+
- lib/merb_messenger/transports/mailfactory.rb
|
47
|
+
- lib/merb_messenger/transports/xmpp4r.rb
|
48
|
+
- lib/merb_messenger.rb
|
49
|
+
has_rdoc: false
|
50
|
+
homepage: http://merbivore.com/
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
version:
|
68
|
+
requirements: []
|
69
|
+
|
70
|
+
rubyforge_project: merb
|
71
|
+
rubygems_version: 1.2.0
|
72
|
+
signing_key:
|
73
|
+
specification_version: 3
|
74
|
+
summary: "Merb plugin that provides messaging/notifications functionality: from email and XMPP to AMPQ and beyond."
|
75
|
+
test_files: []
|
76
|
+
|