speedy_gcm 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in speedy_gcm.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem "shoulda"
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Amro Mousa, (c) 2011 Brandon Keene, (c) 2012 Sandeep Ghael, (c) 2012 Keith Ballinger
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.md ADDED
@@ -0,0 +1,80 @@
1
+ # Speedy GCM
2
+
3
+ Speedy GCM sends push notifications to Android devices via Google's [GCM](http://developer.android.com/guide/google/gcm/index.html) (Google Cloud Messaging for Android).
4
+
5
+ Pull requests are welcome!
6
+
7
+ # What is this GCM gem more awesome?
8
+
9
+ - Simple Ruby implementation.
10
+ - No dependencies.
11
+ - Implemented against the JSON based service for GCM. If you need text/plain support look elsewhere.
12
+ - Validation of your message options.
13
+ - Test coverage
14
+ - Simple way to test your android client from the command line
15
+
16
+
17
+ ##Installation
18
+
19
+ $ gem install speedy_gcm
20
+
21
+
22
+ ##Requirements
23
+
24
+ An Android device running 2.2 or newer, its registration token, and a Google account registered for gcm.
25
+
26
+ Also, make sure 'net/http' and 'net/https' are available:
27
+
28
+ require "net/http"
29
+ require "net/https"
30
+
31
+ The 'shoulda' gem is required for testing:
32
+
33
+ $ gem install 'shoulda'
34
+
35
+ ##Compatibility
36
+
37
+ Speedy_GCM will work with Rails 3.x & Ruby 1.9x. It has not been tested on previous versions or Rails or Ruby, and may or may not work with those versions.
38
+
39
+
40
+ ##Usage
41
+
42
+ For a Rails app, a good place to put the following would be in config/initializers/speedy_gcm.rb :
43
+
44
+ GCM_API_KEY = "YOUR API KEY"
45
+
46
+ SpeedyGCM::API.set_account(GCM_API_KEY)
47
+
48
+ Then, where you want to make a GCM call in your code, create an message_options hash and pass it to send_notification():
49
+
50
+ message_options = {
51
+ :registration_ids => [<array of registration ids>],
52
+ # optional parameters below. Read the docs here: http://developer.android.com/guide/google/gcm/gcm.html#send-msg
53
+ :collapse_key => "foobar",
54
+ :data => { :score => "3x1" },
55
+ :delay_while_idle => false,
56
+ :time_to_live => 1
57
+ }
58
+
59
+ response = SpeedyGCM::API.send_notification(message_options)
60
+
61
+ puts response[:code] # some http response code like 200
62
+ puts response[:data] # usually nil is returned
63
+
64
+ Note: there are blocking calls in both .set_account() and .send_notification(). You should use an async queue like [Sidekiq](https://github.com/mperham/sidekiq) to ensure a non-blocking code path in your application code, particularly for the .send_notification() call.
65
+
66
+
67
+ ##Testing
68
+
69
+ To test, first fill out these variables in test/test_speedy_gcm.rb:
70
+
71
+ GCM_API_KEY = "TODO - Fill in with your GCM API Key"
72
+ TEST_PHONE_GCM_REGISTRATION_ID = "TODO - Fill in with some valid GCM Registration ID"
73
+
74
+ then run:
75
+
76
+ $ ruby test/test_speedy_gcm.rb
77
+
78
+ ##Copyrights
79
+
80
+ * See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,3 @@
1
+ module SpeedyGCM
2
+ VERSION = "0.9.0"
3
+ end
data/lib/speedy_gcm.rb ADDED
@@ -0,0 +1,85 @@
1
+ require "speedy_gcm/version"
2
+
3
+ module SpeedyGCM
4
+
5
+ # message_options
6
+ #
7
+ # :registration_ids
8
+ # A string array with the list of devices (registration IDs) receiving the message. It must contain at least 1 and at most 1000 registration IDs. To send a multicast message, you must use JSON. For sending a single message to a single device, you could use a JSON object with just 1 registration id, or plain text (see below). Required.
9
+ #
10
+ # :collapse_key
11
+ # An arbitrary string (such as "Updates Available") that is used to collapse a group of like messages when the device is offline, so that only the last message gets sent to the client. This is intended to avoid sending too many messages to the phone when it comes back online. Note that since there is no guarantee of the order in which messages get sent, the "last" message may not actually be the last message sent by the application server. See Advanced Topics for more discussion of this topic. Optional, unless you are using the time_to_live parameter—in that case, you must also specify a collapse_key.
12
+ #
13
+ # :data
14
+ # A JSON object whose fields represents the key-value pairs of the message's payload data. If present, the payload data it will be included in the Intent as application data, with the key being the extra's name. For instance, "data":{"score":"3x1"} would result in an intent extra named score whose value is the string 3x1. There is no limit on the number of key/value pairs, though there is a limit on the total size of the message (4kb). The values could be any JSON object, but we recommend using strings, since the values will be converted to strings in the GCM server anyway. If you want to include objects or other non-string data types (such as integers or booleans), you have to do the conversion to string yourself. Also note that the key cannot be a reserved word (from or any word starting with google.). To complicate things slightly, there are some reserved words (such as collapse_key) that are technically allowed in payload data. However, if the request also contains the word, the value in the request will overwrite the value in the payload data. Hence using words that are defined as field names in this table is not recommended, even in cases where they are technically allowed. Optional.
15
+ #
16
+ # :delay_while_idle
17
+ # If included, indicates that the message should not be sent immediately if the device is idle. The server will wait for the device to become active, and then only the last message for each collapse_key value will be sent. Optional. The default value is false, and must be a JSON boolean.
18
+ #
19
+ # :time_to_live
20
+ # How long (in seconds) the message should be kept on GCM storage if the device is offline. Optional (default time-to-live is 4 weeks, and must be set as a JSON number). If you use this parameter, you must also specify a collapse_key.
21
+
22
+ class API
23
+ PUSH_URL = 'https://android.googleapis.com/gcm/send'
24
+
25
+ class << self
26
+
27
+ def set_account(api_key)
28
+ @api_key = api_key
29
+ end
30
+
31
+ def send_notification(message_opts)
32
+ headers = { "Content-Type" => "application/json",
33
+ "Authorization" => "key=#{@api_key}" }
34
+
35
+ # validate the message options
36
+ message_validation(message_opts)
37
+
38
+ url = URI.parse PUSH_URL
39
+ http = Net::HTTP.new(url.host, url.port)
40
+ http.use_ssl = true
41
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
42
+
43
+ resp, dat = http.post(url.path, message_opts.to_json, headers)
44
+
45
+ return {:code => resp.code.to_i, :message => dat }
46
+ end
47
+
48
+ private
49
+ def message_validation(message_opts)
50
+ # check if message_opts has required info
51
+ raise ArgumentError, "registration_ids is a required param of the GCM message" unless message_opts.has_key? :registration_ids
52
+
53
+ # if you use the delay_while_idle is an included parameter, it must be a boolean
54
+ if message_opts.has_key? :delay_while_idle
55
+ raise ArgumentError, "if you include the delay_while_idle parameter, it must be a boolean" unless ( [true, false].include? message_opts[:delay_while_idle])
56
+ end
57
+
58
+ # if you use the time_to_live parameter, you must also include a collapse_key
59
+ if (message_opts.has_key? :time_to_live) and (!message_opts.has_key? :collapse_key)
60
+ raise ArgumentError, "if you use the time_to_live parameter, you must also include a collapse_key"
61
+ end
62
+
63
+ # if you use the time_to_live parameter, it should be an integer
64
+ if message_opts.has_key? :time_to_live
65
+ raise ArgumentError, "if you use the time_to_live parameter, it should be an integer" unless (message_opts[:time_to_live].is_a? Integer)
66
+ end
67
+
68
+ # registration_ids must contain at least 1 and at most 1000 registration IDs
69
+ registration_ids = message_opts[:registration_ids]
70
+ if (registration_ids.length < 1) or (registration_ids.length > 1000)
71
+ raise ArgumentError, "registration_ids must contain at least 1 and at most 1000 registration IDs"
72
+ end
73
+
74
+ message_opts_json = message_opts.to_json
75
+
76
+ if (message_opts_json.to_s.bytesize > 4096)
77
+ # data must be less than 4kb in length
78
+ raise StandardError, "the size of the message is over 4kb"
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "speedy_gcm/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "speedy_gcm"
7
+ s.version = SpeedyGCM::VERSION
8
+ s.authors = ["Sandeep Ghael"]
9
+ s.email = ["sghael@ravidapp.com"]
10
+ s.homepage = "https://github.com/sghael/speedy_gcm"
11
+ s.summary = %q{Speedy GCM is an intelligent gem for sending push notifications to Android devices via GCM.}
12
+ s.description = %q{Speedy GCM efficiently sends push notifications to Android devices via GCM (Google Cloud Messaging).}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
15
+ require 'speedy_gcm'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,178 @@
1
+ current_dir = File.expand_path(File.dirname(__FILE__))
2
+ require File.join(current_dir, 'helper')
3
+
4
+ require 'json'
5
+ require "net/http"
6
+ require "net/https"
7
+
8
+ class TestSpeedyGCM < Test::Unit::TestCase
9
+
10
+ GCM_API_KEY = "TODO - Fill in with your GCM API Key"
11
+ TEST_PHONE_GCM_REGISTRATION_ID = "TODO - Fill in with some GCM Registration ID"
12
+
13
+ should "not raise an error if the API key is valid" do
14
+ assert_nothing_raised do
15
+ SpeedyGCM::API.set_account(GCM_API_KEY)
16
+ end
17
+ end
18
+
19
+ should "raise an error if the api key is not provided" do
20
+ assert_raise(ArgumentError) do
21
+ SpeedyGCM::API.set_account()
22
+ end
23
+ end
24
+
25
+ should "raise an error if the registration_ids are not provided" do
26
+ SpeedyGCM::API.set_account(GCM_API_KEY)
27
+
28
+ assert_raise(ArgumentError) do
29
+ message_options = {}
30
+ # message_options.merge!({ :registration_ids => [1,2] })
31
+ message_options.merge!({ :collapse_key => "foobar" })
32
+ message_options.merge!({ :data => { :score => "3x1" } })
33
+ message_options.merge!({ :delay_while_idle => true })
34
+ message_options.merge!({ :time_to_live => 1 })
35
+
36
+ response = SpeedyGCM::API.send_notification(message_options)
37
+ end
38
+ end
39
+
40
+ should "raise an error if the time_to_live is provided but collapse_key is not" do
41
+ SpeedyGCM::API.set_account(GCM_API_KEY)
42
+
43
+ assert_raise(ArgumentError) do
44
+ message_options = {}
45
+ message_options.merge!({ :registration_ids => [1,2] })
46
+ # message_options.merge!({ :collapse_key => "foobar" })
47
+ message_options.merge!({ :data => { :score => "3x1" } })
48
+ message_options.merge!({ :delay_while_idle => true })
49
+ message_options.merge!({ :time_to_live => 1 })
50
+
51
+ response = SpeedyGCM::API.send_notification(message_options)
52
+ end
53
+ end
54
+
55
+ should "raise an error if the time_to_live is provided but it is not an integer" do
56
+ SpeedyGCM::API.set_account(GCM_API_KEY)
57
+
58
+ assert_raise(ArgumentError) do
59
+ message_options = {}
60
+ message_options.merge!({ :registration_ids => [1,2] })
61
+ message_options.merge!({ :collapse_key => "foobar" })
62
+ message_options.merge!({ :data => { :score => "3x1" } })
63
+ message_options.merge!({ :time_to_live => "a" })
64
+
65
+ response = SpeedyGCM::API.send_notification(message_options)
66
+ end
67
+
68
+ assert_nothing_raised do
69
+ message_options = {}
70
+ message_options.merge!({ :registration_ids => [1,2] })
71
+ message_options.merge!({ :collapse_key => "foobar" })
72
+ message_options.merge!({ :data => { :score => "3x1" } })
73
+ message_options.merge!({ :time_to_live => 1 })
74
+
75
+ response = SpeedyGCM::API.send_notification(message_options)
76
+ end
77
+ end
78
+
79
+ should "check that delay_while_idle is a boolean if provided" do
80
+ SpeedyGCM::API.set_account(GCM_API_KEY)
81
+
82
+ assert_raise(ArgumentError) do
83
+ message_options = {}
84
+ message_options.merge!({ :registration_ids => [1,2] })
85
+ message_options.merge!({ :collapse_key => "foobar" })
86
+ message_options.merge!({ :data => { :score => "3x1" } })
87
+ message_options.merge!({ :delay_while_idle => nil })
88
+ message_options.merge!({ :time_to_live => 1 })
89
+
90
+ response = SpeedyGCM::API.send_notification(message_options)
91
+ end
92
+
93
+ assert_nothing_raised do
94
+ message_options = {}
95
+ message_options.merge!({ :registration_ids => [1,2] })
96
+ message_options.merge!({ :collapse_key => "foobar" })
97
+ message_options.merge!({ :data => { :score => "3x1" } })
98
+ message_options.merge!({ :delay_while_idle => true })
99
+ message_options.merge!({ :time_to_live => 1 })
100
+
101
+ response = SpeedyGCM::API.send_notification(message_options)
102
+ end
103
+
104
+ assert_nothing_raised do
105
+ message_options = {}
106
+ message_options.merge!({ :registration_ids => [1,2] })
107
+ message_options.merge!({ :collapse_key => "foobar" })
108
+ message_options.merge!({ :data => { :score => "3x1" } })
109
+ message_options.merge!({ :delay_while_idle => false })
110
+ message_options.merge!({ :time_to_live => 1 })
111
+
112
+ response = SpeedyGCM::API.send_notification(message_options)
113
+ end
114
+ end
115
+
116
+ should "raise error if registration_ids contain no registration IDs" do
117
+ SpeedyGCM::API.set_account(GCM_API_KEY)
118
+
119
+ assert_raise(ArgumentError) do
120
+ message_options = {}
121
+ message_options.merge!({ :registration_ids => [] })
122
+ message_options.merge!({ :collapse_key => "foobar" })
123
+ message_options.merge!({ :data => { :score => "3x1" } })
124
+ message_options.merge!({ :time_to_live => 1 })
125
+
126
+ response = SpeedyGCM::API.send_notification(message_options)
127
+ end
128
+ end
129
+
130
+ should "raise error if registration_ids contains more than 1000 registration IDs" do
131
+ assert_raise(ArgumentError) do
132
+ SpeedyGCM::API.set_account(GCM_API_KEY)
133
+
134
+ reg_ids = *(1..1001)
135
+
136
+ message_options = {}
137
+ message_options.merge!({ :registration_ids => reg_ids })
138
+ message_options.merge!({ :collapse_key => "foobar" })
139
+ message_options.merge!({ :data => { :score => "3x1" } })
140
+ message_options.merge!({ :time_to_live => 1 })
141
+
142
+ response = SpeedyGCM::API.send_notification(message_options)
143
+ end
144
+ end
145
+
146
+ should "not raise an error if a send notification call succeeds" do
147
+ assert_nothing_raised do
148
+ SpeedyGCM::API.set_account(GCM_API_KEY)
149
+
150
+ message_options = {}
151
+ message_options.merge!({ :registration_ids => [1] })
152
+ message_options.merge!({ :collapse_key => "foobar" })
153
+ message_options.merge!({ :data => { :score => "3x1" } })
154
+ message_options.merge!({ :time_to_live => 1 })
155
+
156
+ response = SpeedyGCM::API.send_notification(message_options)
157
+ end
158
+ end
159
+
160
+ should "not raise an error and send a message with a success response" do
161
+ assert_nothing_raised do
162
+ SpeedyGCM::API.set_account(GCM_API_KEY)
163
+
164
+ message_options = {}
165
+ message_options.merge!({ :registration_ids => [TEST_PHONE_GCM_REGISTRATION_ID] })
166
+ message_options.merge!({ :collapse_key => Time.now.to_s })
167
+ message_options.merge!({ :data => { :vmr_id => "3" } })
168
+
169
+ response = SpeedyGCM::API.send_notification(message_options)
170
+
171
+ assert response[:code].eql? 200
172
+
173
+ # puts response[:code]
174
+ # puts response[:message]
175
+ end
176
+ end
177
+
178
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: speedy_gcm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sandeep Ghael
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-01 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Speedy GCM efficiently sends push notifications to Android devices via
15
+ GCM (Google Cloud Messaging).
16
+ email:
17
+ - sghael@ravidapp.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - lib/speedy_gcm.rb
28
+ - lib/speedy_gcm/version.rb
29
+ - speedy_gcm.gemspec
30
+ - test/helper.rb
31
+ - test/test_speedy_gcm.rb
32
+ homepage: https://github.com/sghael/speedy_gcm
33
+ licenses: []
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.24
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Speedy GCM is an intelligent gem for sending push notifications to Android
56
+ devices via GCM.
57
+ test_files:
58
+ - test/helper.rb
59
+ - test/test_speedy_gcm.rb