diff --git a/README.textile b/README.textile index c6426b1..54a76ee 100644 --- a/README.textile +++ b/README.textile @@ -84,14 +84,25 @@ Please note that a more detailed introduction to GCM is located at "http://devel $ rails console >> device = Gcm::Device.create(:registration_id => "XXXXXXXXXXXXXXXXXXXXXX") >> notification = Gcm::Notification.new - >> notification.device = device + >> notification.devices << device >> notification.collapse_key = "updates_available" >> notification.delay_while_idle = true - >> notification.data = {:registration_ids => ["RegistrationID"], :data => {:message_text => "Get on cloud nine"}} + >> notification.data = {:data => {:message_text => "Get on cloud nine"}} + >> notification.notification_type = "urgent" >> notification.save +In this version you don't have to add the registration ids of the devices you're going to send the notifications. You just add them to notifications_devices relation by doing: +
+ >> notification.devices << device
+
+as it was shown in the previous example.
+
+The following Rake task can then be used to deliver urgent notifications:
+
+ $ rake gcm:notifications:deliver["urgent"]
+
-The following Rake task can then be used to deliver notifications:
+If you want to deliver every notification that wasn't delivered yet:
$ rake gcm:notifications:deliver
@@ -128,7 +139,7 @@ h2. To-Do's:
in the message object of the return json.
- Tests, tests then some more tests. These need to be implemented.
-- Implement "broadcasting" sending and processing responses to multiple registration id's within one request. Currently only one message to a single registration id is implemented.
+- Implement some sort of mechanism to update from previous versions
Released under the MIT license.
diff --git a/VERSION b/VERSION
index 7693c96..845639e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.1.3
\ No newline at end of file
+0.1.4
diff --git a/gcm_on_rails.gemspec b/gcm_on_rails.gemspec
index 5fc23ee..082e025 100644
--- a/gcm_on_rails.gemspec
+++ b/gcm_on_rails.gemspec
@@ -5,7 +5,7 @@
Gem::Specification.new do |s|
s.name = "gcm_on_rails"
- s.version = "0.1.3"
+ s.version = "0.1.4"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Dennis Ondeng"]
@@ -35,6 +35,7 @@ Gem::Specification.new do |s|
"lib/gcm_on_rails_tasks.rb",
"lib/generators/gcm_migrations_generator.rb",
"lib/generators/templates/gcm_migrations/create_gcm_devices.rb",
+ "lib/generators/templates/gcm_migrations/create_gcm_devices_notifications.rb",
"lib/generators/templates/gcm_migrations/create_gcm_notifications.rb"
]
s.homepage = "http://github.com/dondeng/gcm_on_rails"
diff --git a/lib/gcm_on_rails/app/models/gcm/device.rb b/lib/gcm_on_rails/app/models/gcm/device.rb
index 165aeaa..579624d 100644
--- a/lib/gcm_on_rails/app/models/gcm/device.rb
+++ b/lib/gcm_on_rails/app/models/gcm/device.rb
@@ -13,7 +13,7 @@ class Gcm::Device < Gcm::Base
attr_accessible :registration_id
- has_many :notifications, :class_name => 'Gcm::Notification', :dependent => :destroy
+ has_and_belongs_to_many :notifications, :class_name => 'Gcm::Notification', :join_table => :gcm_devices_notifications
validates_presence_of :registration_id
validates_uniqueness_of :registration_id
@@ -28,4 +28,4 @@ class Gcm::Device < Gcm::Base
def set_last_registered_at
self.last_registered_at = Time.now if self.last_registered_at.nil?
end
-end
\ No newline at end of file
+end
diff --git a/lib/gcm_on_rails/app/models/gcm/notification.rb b/lib/gcm_on_rails/app/models/gcm/notification.rb
index 8b144ac..4c3d8c7 100644
--- a/lib/gcm_on_rails/app/models/gcm/notification.rb
+++ b/lib/gcm_on_rails/app/models/gcm/notification.rb
@@ -5,7 +5,7 @@ class Gcm::Notification < Gcm::Base
extend ::ActionView::Helpers::TextHelper
serialize :data
- belongs_to :device, :class_name => 'Gcm::Device'
+ has_and_belongs_to_many :devices, :class_name => 'Gcm::Device', :join_table => :gcm_devices_notifications
validates_presence_of :collapse_key if :time_to_live?
class << self
@@ -28,73 +28,83 @@ class << self
# {:message=>"{\"multicast_id\":6085691036338669615,\"success\":1,\"failure\":0,\"canonical_ids\":0,\"results\":[{\"message_id\":\"0:1349723376618187%d702725e98d39af3\"}]}", :code=>200}
#
#
- def send_notifications(notifications = Gcm::Notification.all(:conditions => {:sent_at => nil}, :joins => :device, :readonly => false))
+ def send_notifications_by_type(notification_type, notifications = Gcm::Notification.all(:conditions => {:sent_at => nil, notification_type: notification_type}, :include => :devices, :readonly => false))
+ notify(notifications)
+ end
- if configatron.gcm_on_rails.delivery_format and configatron.gcm_on_rails.delivery_format == 'plain_text'
- format = "plain_text"
- else
- format = "json"
- end
+ def send_notifications(notifications = Gcm::Notification.all(:conditions => {:sent_at => nil}, :include => :devices, :readonly => false))
+ notify(notifications)
+ end
- unless notifications.nil? || notifications.empty?
- api_key = Gcm::Connection.open
- if api_key
- notifications.each do |notification|
+ private
- logger.info "notification = #{notification.inspect}"
- response = Gcm::Connection.send_notification(notification, api_key, format)
- logger.info "response = #{response.inspect}"
+ def notify notifications
- if response[:code] == 200
- if response[:message].nil?
- # TODO - Making this assumption might not be right. HTTP status code 200 does not really signify success
- # if Gcm servers returned nil for the message
- error = "success"
- elsif format == "json"
- error = ""
- message_data = JSON.parse response[:message]
- success = message_data['success']
- error = message_data['results'][0]['error'] if success == 0
- elsif format == "plain_text" #format is plain text
- message_data = response[:message]
- error = response[:message].split('=')[1]
- end
+ if configatron.gcm_on_rails.delivery_format and configatron.gcm_on_rails.delivery_format == 'plain_text'
+ format = "plain_text"
+ else
+ format = "json"
+ end
+
+ unless notifications.nil? || notifications.empty?
+ api_key = Gcm::Connection.open
+ if api_key
+ notifications.each do |notification|
+ logger.info "notification = #{notification.inspect}"
+ response = Gcm::Connection.send_notification(notification, api_key, format)
+ logger.info "response = #{response.inspect}"
- case error
- when "MissingRegistration"
- ex = Gcm::Errors::MissingRegistration.new(response[:message])
- logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
- notification.device.destroy
- when "InvalidRegistration"
- ex = Gcm::Errors::InvalidRegistration.new(response[:message])
- logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
- notification.device.destroy
- when "MismatchedSenderId"
- ex = Gcm::Errors::MismatchSenderId.new(response[:message])
- logger.warn(ex.message)
- when "NotRegistered"
- ex = Gcm::Errors::NotRegistered.new(response[:message])
- logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
- notification.device.destroy
- when "MessageTooBig"
- ex = Gcm::Errors::MessageTooBig.new(response[:message])
- logger.warn(ex.message)
- else
- notification.sent_at = Time.now
- notification.save!
+ if response[:code] == 200
+ if response[:message].nil?
+ # TODO - Making this assumption might not be right. HTTP status code 200 does not really signify success
+ # if Gcm servers returned nil for the message
+ error = "success"
+ elsif format == "json"
+ error = ""
+ message_data = JSON.parse response[:message]
+ success = message_data['success']
+ error = message_data['results'][0]['error'] if success == 0
+ elsif format == "plain_text" #format is plain text
+ message_data = response[:message]
+ error = response[:message].split('=')[1]
+ end
+
+
+ case error
+ when "MissingRegistration"
+ ex = Gcm::Errors::MissingRegistration.new(response[:message])
+ logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
+ notification.device.destroy
+ when "InvalidRegistration"
+ ex = Gcm::Errors::InvalidRegistration.new(response[:message])
+ logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
+ notification.device.destroy
+ when "MismatchedSenderId"
+ ex = Gcm::Errors::MismatchSenderId.new(response[:message])
+ logger.warn(ex.message)
+ when "NotRegistered"
+ ex = Gcm::Errors::NotRegistered.new(response[:message])
+ logger.warn("#{ex.message}, destroying gcm_device with id #{notification.device.id}")
+ notification.device.destroy
+ when "MessageTooBig"
+ ex = Gcm::Errors::MessageTooBig.new(response[:message])
+ logger.warn(ex.message)
+ else
+ #notification.sent_at = Time.now
+ notification.save!
+ end
+ elsif response[:code] == 401
+ raise Gcm::Errors::InvalidAuthToken.new(message_data)
+ elsif response[:code] == 503
+ raise Gcm::Errors::ServiceUnavailable.new(message_data)
+ elsif response[:code] == 500
+ raise Gcm::Errors::InternalServerError.new(message_data)
end
- elsif response[:code] == 401
- raise Gcm::Errors::InvalidAuthToken.new(message_data)
- elsif response[:code] == 503
- raise Gcm::Errors::ServiceUnavailable.new(message_data)
- elsif response[:code] == 500
- raise Gcm::Errors::InternalServerError.new(message_data)
- end
+ end
end
end
end
- end
end
-end
\ No newline at end of file
+end
diff --git a/lib/gcm_on_rails/libs/connection.rb b/lib/gcm_on_rails/libs/connection.rb
index c240329..bb5f6fc 100644
--- a/lib/gcm_on_rails/libs/connection.rb
+++ b/lib/gcm_on_rails/libs/connection.rb
@@ -12,13 +12,14 @@ def send_notification(notification, api_key, format)
data = notification.data.merge({:collapse_key => notification.collapse_key}) unless notification.collapse_key.nil?
data = data.merge({:delay_while_idle => notification.delay_while_idle}) unless notification.delay_while_idle.nil?
data = data.merge({:time_to_live => notification.time_to_live}) unless notification.time_to_live.nil?
+ data = data.merge({:registration_ids => notification.devices.map{ |d| d.registration_id } })
data = data.to_json
else #plain text format
headers = {"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-8",
"Authorization" => "key=#{api_key}"}
post_data = notification.data[:data].map{|k, v| "&data.#{k}=#{URI.escape(v)}".reduce{|k, v| k + v}}[0]
- extra_data = "registration_id=#{notification.data[:registration_ids][0]}"
+ extra_data = "registration_ids=#{notification.devices.map{ |d| d.registration_id }}"
extra_data = "#{extra_data}&collapse_key=#{notification.collapse_key}" unless notification.collapse_key.nil?
extra_data = "#{extra_data}&delay_while_idle=1" if notification.delay_while_idle
data = "#{extra_data}#{post_data}"
@@ -40,4 +41,4 @@ def open
end
end
end
-end
\ No newline at end of file
+end
diff --git a/lib/gcm_on_rails/tasks/gcm.rake b/lib/gcm_on_rails/tasks/gcm.rake
index 1df4faa..a645282 100644
--- a/lib/gcm_on_rails/tasks/gcm.rake
+++ b/lib/gcm_on_rails/tasks/gcm.rake
@@ -2,8 +2,13 @@ namespace :gcm do
namespace :notifications do
desc "Deliver all unsent Gcm notifications."
- task :deliver => [:environment] do
- Gcm::Notification.send_notifications
+ task :deliver, [:type] => [:environment] do |t, args|
+ if args.type.nil?
+ Gcm::Notification.send_notifications
+ else
+ Gcm::Notification.send_notifications_by_type(args.type)
+ end
end
+
end
end
diff --git a/lib/generators/gcm_migrations_generator.rb b/lib/generators/gcm_migrations_generator.rb
index a8d95a3..0b43c9e 100644
--- a/lib/generators/gcm_migrations_generator.rb
+++ b/lib/generators/gcm_migrations_generator.rb
@@ -18,7 +18,8 @@ def self.base_root
def create_migrations
templates = {
'create_gcm_devices.rb' => 'db/migrate/create_gcm_devices.rb',
- 'create_gcm_notifications.rb' => 'db/migrate/create_gcm_notifications.rb'
+ 'create_gcm_notifications.rb' => 'db/migrate/create_gcm_notifications.rb',
+ 'create_gcm_devices_notifications.rb' => 'db/migrate/create_gcm_devices_notifications.rb'
}
templates.each_pair do |name, path|
@@ -29,4 +30,4 @@ def create_migrations
end
end
end
-end # GcmMigrationsGenerator
\ No newline at end of file
+end # GcmMigrationsGenerator
diff --git a/lib/generators/templates/gcm_migrations/create_gcm_devices_notifications.rb b/lib/generators/templates/gcm_migrations/create_gcm_devices_notifications.rb
new file mode 100644
index 0000000..1abb1ff
--- /dev/null
+++ b/lib/generators/templates/gcm_migrations/create_gcm_devices_notifications.rb
@@ -0,0 +1,16 @@
+class CreateGcmDevicesNotifications < ActiveRecord::Migration # :nodoc:
+
+ def self.up
+
+ create_table :gcm_devices_notifications, :id => false do |t|
+ t.integer :device_id, :null => false
+ t.integer :notification_id, :null => false
+ end
+
+ add_index :gcm_devices_notifications, [:device_id, :notification_id], :unique => true
+ end
+
+ def self.down
+ drop_table :gcm_devices_notifications
+ end
+end
diff --git a/lib/generators/templates/gcm_migrations/create_gcm_notifications.rb b/lib/generators/templates/gcm_migrations/create_gcm_notifications.rb
index 72b49ab..fda6e58 100644
--- a/lib/generators/templates/gcm_migrations/create_gcm_notifications.rb
+++ b/lib/generators/templates/gcm_migrations/create_gcm_notifications.rb
@@ -3,19 +3,18 @@ class CreateGcmNotifications < ActiveRecord::Migration # :nodoc:
def self.up
create_table :gcm_notifications do |t|
- t.integer :device_id, :null => false
t.string :collapse_key
t.text :data
t.boolean :delay_while_idle
t.datetime :sent_at
t.integer :time_to_live
+ t.string :notification_type
t.timestamps
end
- add_index :gcm_notifications, :device_id
end
def self.down
drop_table :gcm_notifications
end
-end
\ No newline at end of file
+end