lib/ass.rb in ass-0.0.15 vs lib/ass.rb in ass-0.0.17
- old
+ new
@@ -1,7 +1,6 @@
-#!/usr/bin/env ruby
-# -*- coding: utf-8 -*-
+#encoding: utf-8
require 'rubygems'
require 'sinatra'
require 'sequel'
require 'socket'
@@ -10,11 +9,18 @@
require 'rufus/scheduler'
require 'eventmachine'
require 'sinatra/base'
require 'yaml'
require 'uri-handler'
+require 'net/http'
require 'active_support'
+require 'json'
+require 'digest/sha2'
+require 'will_paginate'
+require 'will_paginate/sequel' # or data_mapper/sequel
+require 'uri'
+require 'sinatra/reloader' if development?
############################################################
## Initilization Setup
############################################################
LIBDIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
@@ -43,10 +49,12 @@
$port = config['port'] || 4567
$mode = config['mode'] || env
$VERSION = File.open("#{ROOTDIR}/VERSION", "rb").read
$apps = config['apps'] || []
$log = config['log'] || 'off'
+$user = config['user'] || 'admin'
+$pass = config['pass'] || 'pass'
############################################################
## Certificate Key Setup
############################################################
@@ -69,29 +77,29 @@
return true
end
unless check_cert then
html = <<-END
-1: please provide certificate key pem file under current directory, name should be: appid_dev.pem for development and appid_prod.pem for production
+1: please provide certificate key pem file under current directory, name should be: appid_development.pem for development and appid_production.pem for production
2: edit your ass.yml under current directory
3: run ass
4: iOS Client: in AppDelegate file, didRegisterForRemoteNotificationsWithDeviceToken method should access url below:
-END
+ END
$apps.each { |app|
html << "'#{app}'s registration url: http://serverIP:#{$port}/v1/apps/#{app}/DeviceToken"
}
- html << "5: Server: cron should access 'curl http://localhost:#{$port}/v1/app/push/{messages}/{pid}' to send push message"
+ html << "5: Server: cron should access 'curl http://localhost:#{$port}/v1/app/push/{messages}/{pid}' to send push message"
puts html
exit
else
html = <<-END
#{'*'*80}
Apple Service Server(#{$VERSION}) is Running ...
Push Notification Service: Enabled
Mode: #{$mode}
Port: #{$port}
-END
+ END
html << "#{'*'*80}"
html << "Cron Job: '#{Dir.pwd}/#{$cron}' script is running every #{$timer} #{($timer == 1) ? 'minute' : 'minutes'} " unless "#{$timer}".to_i == 0
html << "\n"
html << "access http://localhost:#{$port}/ for more information"
html << "\n"
@@ -108,25 +116,43 @@
$DB.create_table :tokens do
primary_key :id
String :app, :unique => false, :null => false
String :token, :unique => false, :null => false, :size => 100
+ Time :created_at
index [:app, :token]
end
$DB.create_table :pushes do
primary_key :id
String :pid, :unique => true, :null => false, :size => 100
- index :pid
+ String :app, :unique => true, :null => false, :size => 30
+ String :message, :unique => false, :null => false, :size => 107
+ Time :created_at
+ index [:pid, :message]
end
else
$DB = Sequel.connect("sqlite://#{Dir.pwd}/ass.db")
end
-Token = $DB[:tokens]
-Push = $DB[:pushes]
+WillPaginate.per_page = 10
+# Token = $DB[:tokens]
+# Push = $DB[:pushes]
+
+class Token < Sequel::Model
+ Sequel.extension :pagination
+
+ # here is your code
+end
+
+class Push < Sequel::Model
+ Sequel.extension :pagination
+
+ # here is your code
+end
+
############################################################
## Timer Job Setup
############################################################
scheduler = Rufus::Scheduler.start_new
@@ -140,21 +166,33 @@
############################################################
## Apple Service Server based on Sinatra
############################################################
class App < Sinatra::Base
-
+
set :root, File.expand_path('../../', __FILE__)
set :port, "#{$port}".to_i
set :public_folder, File.dirname(__FILE__) + '/../public'
- set :views, File.dirname(__FILE__) + '/../views'
+ set :views, File.dirname(__FILE__) + '/../views'
+ def authorized?
+ @auth ||= Rack::Auth::Basic::Request.new(request.env)
+ @auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ["#{$user}", "#{$pass}"]
+ end
+
+ def protected!
+ unless authorized?
+ response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
+ throw(:halt, [401, "Oops... we need your login name & password\n"])
+ end
+ end
+
configure :production, :development do
if "#{$log}".strip == 'on' then
- enable :logging
+ enable :logging
end
- end
+ end
if "#{$mode}".strip == 'development' then
set :show_exceptions, true
set :dump_errors, true
else
@@ -164,27 +202,130 @@
get '/' do
erb :index
end
+ get '/about' do
+ erb :about
+ end
+
+ not_found do
+ erb :not_found
+ end
+
+ error do
+ @error = params['captures'].first.inspect
+ end
+
+ post '/v1/send' do
+ app = params[:app]
+ message = CGI::escape(params[:message] || "")
+ pid = "#{Time.now.to_i}"
+ # begin
+ # url = URI.parse("http://localhost:#{$port}/v1/apps/#{app}/push")
+ # post_args1 = { :alert => "#{message}".encode('UTF-8'), :pid => "#{pid}" }
+ # Net::HTTP.post_form(url, post_args1)
+ # rescue =>err
+ # puts "#{err.class} ##{err}"
+ # end
+ system "curl http://localhost:#{$port}/v1/apps/#{app}/push/#{message}/#{pid}"
+ redirect '/' if (params[:app] and params[:message])
+ end
+
+ get "/v1/admin/:db" do
+ protected!
+ db = params[:db] || 'token'
+ page = 1
+ page = params[:page].to_i if params[:page]
+ if (db == 'token') then
+ @o = []
+ $apps.each_with_index { |app, index|
+ @o << Token.where(:app => app).order(:id).reverse.paginate(page, 20)
+ }
+ erb :token
+ end
+ if (db == 'push') then
+ @p = []
+ $apps.each_with_index { |app, index|
+ @p << Push.where(:app => app).order(:id).reverse.paginate(page, 20)
+ }
+ erb :push
+ end
+ end
+
$apps.each { |app|
+
+ ## register token api
get "/v1/apps/#{app}/:token" do
- puts "[#{params[:token]}] was added to '#{app}'" if "#{$mode}".strip == 'development'
- o = Token.first(:app => app , :token => params[:token])
+ puts "[#{params[:token]}] was added to '#{app}'" if "#{$mode}".strip == 'development'
+ o = Token.first(:app => app, :token => params[:token])
unless o
Token.insert(
:app => app,
:token => params[:token]
)
end
end
+ ## http POST method push api
+ post "/v1/apps/#{app}/push" do
+ protected! unless request.host == 'localhost'
+ message = CGI::unescape(params[:alert] || "")[0..107]
+ badge = 1
+ puts "params[:badge] = [#{params[:badge]}]"
+ badge = params[:badge].to_i if params[:badge] and params[:badge] != ''
+ sound = CGI::unescape(params[:sound] || "")
+ extra = CGI::unescape(params[:extra] || "")
+
+ puts "#{badge} : #{message} extra: #{extra}" if "#{$mode}".strip == 'development'
+ pid = params[:pid]
+
+ puts "'#{message}' was sent to (#{app}) with pid: [#{pid}], badge:#{badge} , sound: #{sound}, extra:#{extra}" if "#{$mode}".strip == 'development'
+
+ @push = Token.where(:app => app)
+ @exist = Push.first(:pid => pid)
+
+ unless @exist
+ openSSLContext = $certkey["#{app}"]
+ # Connect to port 2195 on the server.
+ sock = nil
+ if $mode == 'production' then
+ sock = TCPSocket.new('gateway.push.apple.com', 2195)
+ else
+ sock = TCPSocket.new('gateway.sandbox.push.apple.com', 2195)
+ end
+ # do our SSL handshaking
+ sslSocket = OpenSSL::SSL::SSLSocket.new(sock, openSSLContext)
+ sslSocket.connect
+ #Push.create( :pid => pid )
+ Push.insert(:pid => pid, :message => message, :created_at => Time.now, :app => "#{app}" )
+ # write our packet to the stream
+ @push.each do |o|
+ tokenText = o[:token]
+ # pack the token to convert the ascii representation back to binary
+ tokenData = [tokenText].pack('H*')
+ # construct the payload
+ po = {:aps => {:alert => "#{message}", :badge => badge, :sound => "#{sound}"}, :extra => "#{extra}"}
+ payload = ActiveSupport::JSON.encode(po)
+ # construct the packet
+ packet = [0, 0, 32, tokenData, 0, payload.length, payload].pack("ccca*cca*")
+ # read our certificate and set up our SSL context
+ sslSocket.write(packet)
+ end
+ # cleanup
+ sslSocket.close
+ sock.close
+ end
+ end
+
+ ## http GET method push api
get "/v1/apps/#{app}/push/:message/:pid" do
+ protected! unless request.host == 'localhost'
message = CGI::unescape(params[:message])
- puts message if "#{$mode}".strip == 'development'
+ puts message if "#{$mode}".strip == 'development'
pid = params[:pid]
- puts "'#{message}' was sent to (#{app}) with pid: [#{pid}]" if "#{$mode}".strip == 'development'
+ puts "'#{message}' was sent to (#{app}) with pid: [#{pid}]" if "#{$mode}".strip == 'development'
@push = Token.where(:app => app)
@exist = Push.first(:pid => pid)
unless @exist
\ No newline at end of file