Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ test/tmp
test/version_tmp
tmp
example/.sass-cache
.env

# YARD artifacts
.yardoc
_yardoc
doc/
doc/
49 changes: 44 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Bundler.require
run Helios::Application.new do
service :data, model: 'path/to/DataModel.xcdatamodel'
service :push_notification, apn_certificate: 'path/to/apple_push_notification.pem', apn_environment: 'development'
service :gcm, gcm_api_key: 'xxxxxxx'
service :in_app_purchase
service :passbook
end
Expand All @@ -103,6 +104,7 @@ Helios can be run as Rails middleware by adding this to the configuration block
config.middleware.use Helios::Application do
service :data, model: 'path/to/DataModel.xcdatamodel'
service :push_notification, apn_certificate: 'path/to/apple_push_notification.pem', apn_environment: 'development'
service :gcm, gcm_api_key: 'xxxxxxx'
service :in_app_purchase
service :passbook
end
Expand Down Expand Up @@ -157,15 +159,39 @@ Each entity in the specified data model will have a `Sequel::Model` subclass cre
<table>
<caption>Endpoints</caption>
<tr>
<td><tt>PUT /devices/:token</tt></td>
<td><tt>PUT /push_notification/devices/:token</tt></td>
<td>Register or update existing device for push notifications</td>
</tr>
<tr>
<td><tt>DELETE /devices/:token</tt></td>
<td><tt>DELETE /push_notification/devices/:token</tt></td>
<td>Unregister a device from receiving push notifications</td>
</tr>
<tr>
<td><tt>POST /message</tt></td>
<td><tt>POST /push_notification/message</tt></td>
<td>Send out a push notification to some devices</td>
</tr>
</table>

---

`gcm`: Adds Android push notification(Google Cloud Messaging) registration / unregistration endpoints.

**Associated Classes**

- `Rack::GCM::Device`

<table>
<caption>Endpoints</caption>
<tr>
<td><tt>PUT /gcm/devices/:token</tt></td>
<td>Register or update existing device for push notifications</td>
</tr>
<tr>
<td><tt>DELETE /gcm/devices/:token</tt></td>
<td>Unregister a device from receiving push notifications</td>
</tr>
<tr>
<td><tt>POST /gcm/message</tt></td>
<td>Send out a push notification to some devices</td>
</tr>
</table>
Expand Down Expand Up @@ -274,7 +300,13 @@ To run Helios in development mode on `localhost`, run the `server` command:

Once you have registered a device and set up your certificate, try this:

$ curl -X POST -d 'payload={"aps": {"alert":"Blastoff!"}}' http://localhost:5000/message
$ curl -X POST -d 'payload={"aps": {"alert":"Blastoff!"}}' http://localhost:5000/push-notification/message

### Testing Android Push Notifications(Google Cloud Messaging)

Once you have registered a device and set up your certificate, try this:

$ curl -X POST -d 'payload={"alert":"Blastoff!"}' http://localhost:5000/gcm/message

### Running the Helios Console

Expand Down Expand Up @@ -336,6 +368,13 @@ Now covert the p12 file to a pem file:

$ openssl pkcs12 -in cert.p12 -out apple_push_notification.pem -nodes -clcerts

## Integrating with an Android Application

### Google Cloud Messaging Registration

See more detail [Google Cloud Messaging Tutorial](http://developer.android.com/google/gcm/gs.html)


## Coming Attractions

There's still a lot to do to make Helios even better. Here are some ideas that are at the top of the list:
Expand All @@ -346,7 +385,7 @@ There's still a lot to do to make Helios even better. Here are some ideas that a
- Better RubyMotion integration
- Support for multiple schema definitions (not just Core Data)
- Send push notifications from the UI
- Support for additional platforms (Android, WP7)
- Support for additional platforms (WP7)

---

Expand Down
1 change: 1 addition & 0 deletions example/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ source "https://rubygems.org"
gem 'helios', path: File.join(__FILE__, "../..")
gem 'unicorn'
gem 'pg'
gem 'thin'
5 changes: 3 additions & 2 deletions example/config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ Bundler.require

app = Helios::Application.new do
service :data, model: Dir['*.xcdatamodel*'].first, only: [:create, :read]
service :push_notification, frontend: false
service :push_notification, frontend: true
service :gcm, gcm_api_key: ENV['GCM_API_KEY']
service :in_app_purchase
service :passbook
service :newsstand, storage: ({
Expand Down Expand Up @@ -33,4 +34,4 @@ end
# }
# end

run app
run app
2 changes: 2 additions & 0 deletions helios.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Gem::Specification.new do |s|
s.add_dependency "rails-database-url", "~> 1.0"
s.add_dependency "fog", "~> 1.10"
s.add_dependency "houston", "~> 0.2"
s.add_dependency "rack-gcm", "~> 0.0.2"
s.add_dependency "sanjose", "~> 0.0.3"

s.add_development_dependency "rake"
s.add_development_dependency "rspec"
Expand Down
1 change: 1 addition & 0 deletions lib/helios/backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ def constantize(identifier)
require 'helios/backend/passbook'
require 'helios/backend/push-notification'
require 'helios/backend/newsstand'
require 'helios/backend/gcm'
106 changes: 106 additions & 0 deletions lib/helios/backend/gcm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
require 'rack/gcm'

require 'sinatra/base'
require 'sinatra/param'

require 'sanjose'

class Helios::Backend::Gcm < Sinatra::Base
helpers Sinatra::Param
attr_reader :gcm_api_key

def initialize(app, options = {}, &block)
super(Rack::GCM.new)

@api_key = options[:gcm_api_key] || ENV['GCM_API_KEY']
end

before do
content_type :json
end

get '/devices/?' do
param :q, String

devices = ::Rack::GCM::Device.dataset
devices = devices.filter("tsv @@ to_tsquery('english', ?)", "#{params[:q]}:*") if params[:q] and not params[:q].empty?

if params[:page] or params[:per_page]
param :page, Integer, default: 1, min: 1
param :per_page, Integer, default: 100, in: (1..100)

{
devices: devices.limit(params[:per_page], (params[:page] - 1) * params[:per_page]),
page: params[:page],
total: devices.count
}.to_json
else
param :limit, Integer, default: 100, in: (1..100)
param :offset, Integer, default: 0, min: 0

{
devices: devices.limit(params[:limit], params[:offset])
}.to_json
end
end

get '/devices/:token/?' do
record = ::Rack::GCM::Device.find(token: params[:token])

if record
{device: record}.to_json
else
status 404
end
end

head '/message' do
status 503 and return unless client

status 204
end

post '/message' do
status 503 and return unless client

param :payload, String, empty: false
param :tokens, Array, empty: false

tokens = params[:tokens] || ::Rack::GCM::Device.all.collect(&:token)

options = JSON.parse(params[:payload])
puts tokens.inspect
puts options

# Create a notification that alerts a message to the user.
notification = Sanjose::Notification.new(devices: tokens)
notification.data = options

begin
results = client.push(notification)

status 204
rescue => error
status 500

{error: error}.to_json
end

status 200
end

private

def client
begin
return nil unless api_key

client = Sanjose::Client.new
client.gcm_api_key = api_key

return client
rescue
return nil
end
end
end
53 changes: 31 additions & 22 deletions lib/helios/frontend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,31 @@ class Frontend < Sinatra::Base
serve '/fonts', from: '/fonts'

js :application, '/javascripts/application.js', [
'javascripts/vendor/jquery.js',
'javascripts/vendor/jquery/jquery.ui.widget.js',
'javascripts/vendor/jquery/jquery.fileupload.js',
'javascripts/vendor/jquery/jquery.fileupload-ui.js',
'javascripts/vendor/underscore.js',
'javascripts/vendor/backbone.js',
'javascripts/vendor/backbone.paginator.js',
'javascripts/vendor/backbone.datagrid.js',
'javascripts/vendor/codemirror.js',
'javascripts/vendor/codemirror.javascript.js',
'javascripts/vendor/foundation.js',
'javascripts/vendor/foundation/foundation.dropdown.js',
'javascripts/vendor/foundation/foundation.reveal.js',
'javascripts/vendor/date.js',
'javascripts/vendor/linkheaders.js',
'javascripts/helios.js',
'javascripts/helios/models.js',
'javascripts/helios/collections.js',
'javascripts/helios/templates.js',
'javascripts/helios/views.js',
'javascripts/helios/router.js',
'/javascripts/vendor/jquery.js',
'/javascripts/vendor/jquery/jquery.ui.widget.js',
'/javascripts/vendor/jquery/jquery.fileupload.js',
'/javascripts/vendor/jquery/jquery.fileupload-ui.js',
'/javascripts/vendor/underscore.js',
'/javascripts/vendor/backbone.js',
'/javascripts/vendor/backbone.paginator.js',
'/javascripts/vendor/backbone.datagrid.js',
'/javascripts/vendor/codemirror.js',
'/javascripts/vendor/codemirror.javascript.js',
'/javascripts/vendor/foundation.js',
'/javascripts/vendor/foundation/foundation.dropdown.js',
'/javascripts/vendor/foundation/foundation.reveal.js',
'/javascripts/vendor/date.js',
'/javascripts/vendor/linkheaders.js',
'/javascripts/helios.js',
'/javascripts/helios/models.js',
'/javascripts/helios/collections.js',
'/javascripts/helios/templates.js',
'/javascripts/helios/views.js',
'/javascripts/helios/router.js',
]

css :application, '/stylesheets/application.css', [
'stylesheets/screen.css'
'/stylesheets/screen.css'
]
end

Expand All @@ -64,3 +64,12 @@ class Frontend < Sinatra::Base
end
end
end


# Workaround for Sinatra::Assetpack bug
# See https://github.com/helios-framework/helios/issues/68
class Sinatra::AssetPack::Package
def to_production_html(path_prefix, options={})
to_development_html(path_prefix, options)
end
end
2 changes: 2 additions & 0 deletions lib/helios/frontend/javascripts/helios.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ $ ->
Helios.services['newsstand'] = href
when "Helios::Backend::PushNotification"
Helios.services['push-notification'] = href
when "Helios::Backend::Gcm"
Helios.services['gcm'] = href
when "Helios::Backend::Passbook"
Helios.services['passbook'] = href

Expand Down
1 change: 0 additions & 1 deletion lib/helios/frontend/javascripts/helios/collections.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ class Helios.Collections.Devices extends Helios.Collection
comparator: (device) ->
device.get('token')


class Helios.Collections.Receipts extends Helios.Collection
model: Helios.Models.Receipt

Expand Down
7 changes: 7 additions & 0 deletions lib/helios/frontend/javascripts/helios/router.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Helios.Routers.Root extends Backbone.Router
routes:
'': 'index'
'data': 'data'
'gcm': 'gcm'
'push-notification': 'push_notification'
'in-app-purchase': 'in_app_purchase'
'passbook': 'passbook'
Expand All @@ -25,6 +26,12 @@ class Helios.Routers.Root extends Backbone.Router
Helios.entities.fetch(type: 'OPTIONS')
@views.entities.render()

gcm: ->
@android_devices ?= new Helios.Collections.Devices
@android_devices.paginator_core.url = Helios.services['gcm'] + '/devices'
@views.andoid_devices ?= new Helios.Views.AndroidDevices(collection: @android_devices)
@views.andoid_devices.render()

push_notification: ->
@devices ?= new Helios.Collections.Devices
@devices.paginator_core.url = Helios.services['push-notification'] + '/devices'
Expand Down
29 changes: 29 additions & 0 deletions lib/helios/frontend/javascripts/helios/views.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,35 @@ class Helios.Views.Devices extends Backbone.View
@collection.query = $(e.target).val()
@collection.fetch()

class Helios.Views.AndroidDevices extends Backbone.View
template: JST['gcm/devices']
el: "[role='main']"

events:
'keyup form.filter input': 'filter'

initialize: ->
@datagrid = new Backbone.Datagrid({
collection: @collection,
columns: @collection.fields,
paginated: true,
perPage: 20
})

render: =>
@$el.html(@template())

# @composeView ?= new Helios.Views.Compose()
# @composeView.render()
@$el.find("#datagrid").html(@datagrid.el)

@

filter: (e) ->
e.preventDefault()
@collection.query = $(e.target).val()
@collection.fetch()

class Helios.Views.Compose extends Backbone.View
template: JST['push-notification/compose']
el: "#compose-modal"
Expand Down
Loading