messenger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Brandon Arbini / Zencoder, Inc.
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.markdown ADDED
@@ -0,0 +1,2 @@
1
+ Messenger
2
+ ========
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
data/bin/messenger ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'messenger'
7
+ require 'trollop'
8
+ require 'yaml'
9
+
10
+
11
+ #-------------------------------------
12
+ # Support
13
+ #-------------------------------------
14
+
15
+ class Hash
16
+
17
+ def symbolize_keys
18
+ inject({}) do |options, (key, value)|
19
+ options[(key.to_sym rescue key) || key] = value
20
+ options
21
+ end
22
+ end
23
+
24
+ def symbolize_keys!
25
+ self.replace(self.symbolize_keys)
26
+ end
27
+
28
+ end
29
+
30
+
31
+ #
32
+ # Configure options
33
+ #
34
+
35
+ if File.exists?(File.expand_path("~/.messenger"))
36
+ options = YAML.load_file(File.expand_path("~/.messenger")).symbolize_keys!
37
+ else
38
+ options = {}
39
+ end
40
+
41
+ trollop_options = Trollop::options do
42
+ version "Messenger #{Messenger.version} (c) Zencoder Inc. All rights reserved, etc."
43
+ banner <<-EOS
44
+ Messenger makes sending messages easy.
45
+
46
+ Usage:
47
+ script/messenger [options] <service> <message>
48
+
49
+ Where [options] are:
50
+ EOS
51
+
52
+ # Global options
53
+ opt :timeout, "The number of seconds to allow for the call", :type => Integer
54
+
55
+ # Email options
56
+ opt :from, "Who the message is from (email).", :type => String
57
+ opt :subject, "The message subject (email).", :type => String
58
+
59
+ # Jabber options
60
+ opt :jabber_id, "The jabber ID to connect as (user@example.com)", :type => String
61
+ opt :jabber_password, "The password for your jabber id", :type => String
62
+
63
+ # CLI options
64
+ opt :silent, "Don't print anything to stdout", :default => false
65
+ opt :verbose, "Print verbose output on success", :default => false
66
+ end
67
+
68
+ options.merge!(trollop_options.reject{|k,v| v.nil?})
69
+
70
+ #
71
+ # Validate input
72
+ #
73
+
74
+ if ARGV[0].nil? || ARGV[1].nil?
75
+ puts <<-EOS
76
+ Error: no service or message specified.
77
+
78
+ Usage (--help for more):
79
+
80
+ script/messenger [options] <service> <message>
81
+
82
+ EOS
83
+ exit -1
84
+ end
85
+
86
+
87
+ #
88
+ # Run Messenger
89
+ #
90
+ puts "# Sending message to #{ARGV[0]}"
91
+ begin
92
+ status, details = Messenger.send(ARGV[0], ARGV[1], options)
93
+ if !!status
94
+ puts "# Message sent successfully"
95
+ else
96
+ puts "# Message not sent"
97
+ puts "# Details:"
98
+ puts details
99
+ end
100
+ rescue => e
101
+ puts "# **Error** #{e}"
102
+ puts e.backtrace
103
+ end
@@ -0,0 +1,36 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ module Messenger
5
+
6
+ class Campfire
7
+
8
+ def self.send(url, body, options={})
9
+ begin
10
+ api_key, room, subdomain = url.match(/^campfire:\/\/([^:]+):([^@]+)@([^\.]+)/)[1,3]
11
+ rescue
12
+ raise URLError, "The URL provided is invalid"
13
+ end
14
+ response = HTTParty.post(
15
+ "http://#{subdomain}.campfirenow.com/room/#{room}/speak.json",
16
+ :basic_auth => { :username => api_key, :password => "x" },
17
+ :headers => { "Content-Type" => "application/json" },
18
+ :body => { "message" => { "body" => body } }.to_json
19
+ )
20
+ [success?(response), response]
21
+ end
22
+
23
+
24
+ private
25
+
26
+ def self.success?(response)
27
+ case response.code
28
+ when 200, 201: true
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,19 @@
1
+ require 'pony'
2
+
3
+ module Messenger
4
+
5
+ class Email
6
+
7
+ def self.send(url, message, options={})
8
+ Pony.mail(
9
+ :to => url.sub(/mailto:/, ''),
10
+ :from => options[:from],
11
+ :subject => options[:subject],
12
+ :body => message
13
+ )
14
+ [true, nil]
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,7 @@
1
+ module Messenger
2
+
3
+ class MessengerError < StandardError; end
4
+ class ProtocolError < MessengerError; end
5
+ class URLError < MessengerError; end
6
+
7
+ end
@@ -0,0 +1,68 @@
1
+ require 'xmpp4r-simple'
2
+
3
+ module Messenger
4
+
5
+ class Jabber
6
+
7
+ def self.send(url, body, options={})
8
+ recipient, host = url.sub("jabber://", "").split("/")[0,2]
9
+ jabber = ::Jabber::Simple.new(options[:jabber_id], options[:jabber_password], host)
10
+ jabber.deliver(recipient, body)
11
+ pending_messages_count = 1
12
+ until pending_messages_count == 0
13
+ pending_messages_count = jabber.send(:queue, :pending_messages).size
14
+ sleep 1
15
+ end
16
+ status = jabber.subscribed_to?(recipient)
17
+ [status, status ? nil : "Not yet authorized"]
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+
25
+ # MONKEY PATCHING
26
+ #
27
+ # xmpp4r-simple does not allow you to specify the jabber host, but we need to do that for Google Apps.
28
+
29
+ module Jabber
30
+
31
+ class Simple
32
+
33
+ def initialize(jid, password, host=nil, status=nil, status_message="Available")
34
+ @jid = jid
35
+ @password = password
36
+ @host = host
37
+ @disconnected = false
38
+ status(status, status_message)
39
+ start_deferred_delivery_thread
40
+ end
41
+
42
+ def connect!
43
+ raise ConnectionError, "Connections are disabled - use Jabber::Simple::force_connect() to reconnect." if @disconnected
44
+ # Pre-connect
45
+ @connect_mutex ||= Mutex.new
46
+
47
+ # don't try to connect if another thread is already connecting.
48
+ return if @connect_mutex.locked?
49
+
50
+ @connect_mutex.lock
51
+ disconnect!(false) if connected?
52
+
53
+ # Connect
54
+ jid = JID.new(@jid)
55
+ my_client = Client.new(@jid)
56
+ my_client.connect(@host)
57
+ my_client.auth(@password)
58
+ self.client = my_client
59
+
60
+ # Post-connect
61
+ register_default_callbacks
62
+ status(@presence, @status_message)
63
+ @connect_mutex.unlock
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,24 @@
1
+ require 'httparty'
2
+
3
+ module Messenger
4
+
5
+ class Web
6
+
7
+ def self.send(url, body, options={})
8
+ response = HTTParty.post(url, options.merge(:body => body))
9
+ [success?(response), response]
10
+ end
11
+
12
+ private
13
+
14
+ def self.success?(response)
15
+ case response.code
16
+ when 200, 201: true
17
+ else
18
+ false
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
data/lib/messenger.rb ADDED
@@ -0,0 +1,61 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'ruby-debug'
5
+ require 'messenger/errors'
6
+ require 'system_timer'
7
+
8
+
9
+ module Messenger
10
+
11
+ MESSAGER_VERSION = [0,1] unless defined?(MESSAGER_VERSION)
12
+ APP_ROOT = File.expand_path(File.dirname(__FILE__) + '/..') unless defined?(APP_ROOT)
13
+
14
+ def self.version
15
+ MESSAGER_VERSION.join(".")
16
+ end
17
+
18
+ def self.root
19
+ APP_ROOT
20
+ end
21
+
22
+
23
+ def self.send(url, message, options={})
24
+ service_handler = handler(url)
25
+ SystemTimer.timeout_after(options[:timeout] || 15) do
26
+ service_handler.send(url, message, options)
27
+ end
28
+ end
29
+
30
+
31
+ def self.protocol(url)
32
+ # TODO: More services
33
+ # sms://1231231234
34
+ # twitter://username
35
+ # aim://username
36
+ case url
37
+ when /^mailto/: :email
38
+ when /^http/: :http
39
+ when /^campfire/: :campfire
40
+ when /^jabber/: :jabber
41
+ end
42
+ end
43
+
44
+ def self.handler(url)
45
+ case protocol(url)
46
+ when :email: Email
47
+ when :http: Web
48
+ when :campfire: Campfire
49
+ when :jabber: Jabber
50
+ else
51
+ raise ProtocolError, "Malformed service URL: #{url}. Either this syntax is wrong or this service type is not yet implemented."
52
+ end
53
+ end
54
+
55
+
56
+ autoload :Email, "messenger/email"
57
+ autoload :Web, "messenger/web"
58
+ autoload :Campfire, "messenger/campfire"
59
+ autoload :Jabber, "messenger/jabber"
60
+
61
+ end
@@ -0,0 +1,35 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+ require 'httparty'
3
+
4
+ module Messenger
5
+
6
+ class CampfireTest < Test::Unit::TestCase
7
+
8
+ context "Campfire notification" do
9
+ setup do
10
+ @success_response = stub("response", :code => 200)
11
+ @failure_response = stub("response", :code => 500)
12
+ end
13
+
14
+ should "post a successful message" do
15
+ HTTParty.expects(:post).with("http://subdomain.campfirenow.com/room/room/speak.json", :basic_auth => { :username => 'api', :password => 'x' }, :body => '{"message":{"body":"content"}}', :headers => { "Content-Type" => "application/json" }).returns(@success_response)
16
+ result = Campfire.send("campfire://api:room@subdomain.campfirewnow.com", 'content')
17
+ assert_equal [true, @success_response], result
18
+ end
19
+
20
+ should "post a failed message" do
21
+ HTTParty.expects(:post).with("http://subdomain.campfirenow.com/room/room/speak.json", :basic_auth => { :username => 'api', :password => 'x' }, :body => '{"message":{"body":"content"}}', :headers => { "Content-Type" => "application/json" }).returns(@failure_response)
22
+ result = Campfire.send("campfire://api:room@subdomain.campfirewnow.com", 'content')
23
+ assert_equal [false, @failure_response], result
24
+ end
25
+
26
+ should "raise on invalid URL" do
27
+ assert_raises Messenger::URLError do
28
+ Campfire.send("campfire://missing_room@subdomain.campfirewnow.com", 'content')
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,17 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+ require 'pony'
3
+
4
+ module Messenger
5
+
6
+ class EmailTest < Test::Unit::TestCase
7
+
8
+ context "Email notification" do
9
+ should "send an email" do
10
+ Pony.expects(:mail).with(:to => "test@example.com", :body => "Test message", :from => "test@example.com", :subject => "Test")
11
+ Email.send("mailto:test@example.com", "Test message", :from => "test@example.com", :subject => "Test")
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,6 @@
1
+ require "#{File.dirname(__FILE__)}/../lib/messenger"
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ Dir["#{File.dirname(__FILE__)}/shoulda_macros/*.rb"].each {|file| require file }
@@ -0,0 +1,35 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+ require 'xmpp4r-simple'
3
+
4
+ module Messenger
5
+
6
+ class JabberTest < Test::Unit::TestCase
7
+
8
+ context "Jabber notification" do
9
+ setup do
10
+ @successful_jabber = stub("jabber", :deliver => nil, :queue => stub("queue", :size => 0), :subscribed_to? => true)
11
+ @failed_jabber = stub("jabber", :deliver => nil, :queue => stub("queue", :size => 0), :subscribed_to? => false)
12
+ end
13
+
14
+ should "send a successful jabber message" do
15
+ ::Jabber::Simple.expects(:new).with("notifier@zencoder.com", "asdfasdf", nil).returns(@successful_jabber)
16
+ result = Jabber.send("jabber://brandon@zencoder.com", "Test message", :jabber_id => "notifier@zencoder.com", :jabber_password => "asdfasdf")
17
+ assert_equal [true, nil], result
18
+ end
19
+
20
+ should "determine and set the jabber host" do
21
+ ::Jabber::Simple.expects(:new).with("notifier@zencoder.com", "asdfasdf", "host.com").returns(@successful_jabber)
22
+ result = Jabber.send("jabber://brandon@zencoder.com/host.com", "Test message", :jabber_id => "notifier@zencoder.com", :jabber_password => "asdfasdf")
23
+ assert_equal [true, nil], result
24
+ end
25
+
26
+ should "fail if the recipient is not subscribed" do
27
+ ::Jabber::Simple.expects(:new).with("notifier@zencoder.com", "asdfasdf", nil).returns(@failed_jabber)
28
+ result = Jabber.send("jabber://brandon@zencoder.com", "Test message", :jabber_id => "notifier@zencoder.com", :jabber_password => "asdfasdf")
29
+ assert_equal [false, "Not yet authorized"], result
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,23 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ module Messenger
4
+
5
+ class MessengerTest < Test::Unit::TestCase
6
+
7
+ context "Protocol/Handler" do
8
+ should "determine the proper service" do
9
+ assert_equal :email, Messenger.protocol("mailto:test@example.com")
10
+ assert_equal :http, Messenger.protocol("http://example.com")
11
+ assert_equal :http, Messenger.protocol("https://example.com")
12
+ end
13
+
14
+ should "determine the proper notification handler given a protocol" do
15
+ assert_equal Email, Messenger.handler("mailto:test@example.com")
16
+ assert_equal Web, Messenger.handler("http://example.com")
17
+ assert_equal Web, Messenger.handler("https://example.com")
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
data/test/test_web.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+ require 'httparty'
3
+
4
+ module Messenger
5
+
6
+ class WebTest < Test::Unit::TestCase
7
+
8
+ context "Web notification" do
9
+ setup do
10
+ @success_response = stub("response", :code => 200)
11
+ @failure_response = stub("response", :code => 500)
12
+ end
13
+
14
+ should "post a successful message" do
15
+ HTTParty.expects(:post).with("http://example.com", :body => '{ "key": "value" }', :headers => { "Content-Type" => "application/json" }).returns(@success_response)
16
+ result = Web.send("http://example.com", '{ "key": "value" }', :headers => { "Content-Type" => "application/json" })
17
+ assert_equal [true, @success_response], result
18
+ end
19
+
20
+ should "post a failed message" do
21
+ HTTParty.expects(:post).with("http://example.com", :body => '{ "key": "value" }', :headers => { "Content-Type" => "application/json" }).returns(@failure_response)
22
+ result = Web.send("http://example.com", '{ "key": "value" }', :headers => { "Content-Type" => "application/json" })
23
+ assert_equal [false, @failure_response], result
24
+ end
25
+ end
26
+
27
+ end
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: messenger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brandon Arbini
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-04 00:00:00 -08:00
13
+ default_executable: messenger
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: trollop
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.15"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: pony
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0.6"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: tmail
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.6
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: mime-types
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "1.16"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: httparty
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 0.5.2
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: SystemTimer
67
+ type: :runtime
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 1.1.3
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: xmpp4r
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "="
82
+ - !ruby/object:Gem::Version
83
+ version: "0.5"
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: xmpp4r-simple
87
+ type: :runtime
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.8.8
94
+ version:
95
+ - !ruby/object:Gem::Dependency
96
+ name: json_pure
97
+ type: :runtime
98
+ version_requirement:
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 1.2.0
104
+ version:
105
+ description: "Messenger: easy message sending"
106
+ email: brandon@zencoder.tv
107
+ executables:
108
+ - messenger
109
+ extensions: []
110
+
111
+ extra_rdoc_files:
112
+ - LICENSE
113
+ - README.markdown
114
+ files:
115
+ - README.markdown
116
+ - VERSION.yml
117
+ - lib/messenger.rb
118
+ - lib/messenger/campfire.rb
119
+ - lib/messenger/email.rb
120
+ - lib/messenger/errors.rb
121
+ - lib/messenger/jabber.rb
122
+ - lib/messenger/web.rb
123
+ - test/test_campfire.rb
124
+ - test/test_email.rb
125
+ - test/test_helper.rb
126
+ - test/test_jabber.rb
127
+ - test/test_messenger.rb
128
+ - test/test_web.rb
129
+ - LICENSE
130
+ has_rdoc: true
131
+ homepage: http://github.com/zencoder/messenger
132
+ licenses: []
133
+
134
+ post_install_message:
135
+ rdoc_options:
136
+ - --charset=UTF-8
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: "0"
144
+ version:
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: "0"
150
+ version:
151
+ requirements: []
152
+
153
+ rubyforge_project:
154
+ rubygems_version: 1.3.5
155
+ signing_key:
156
+ specification_version: 3
157
+ summary: "Messenger: easy message sending"
158
+ test_files:
159
+ - test/test_campfire.rb
160
+ - test/test_email.rb
161
+ - test/test_helper.rb
162
+ - test/test_jabber.rb
163
+ - test/test_messenger.rb
164
+ - test/test_web.rb