ass 0.0.21 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/README.md +14 -2
- data/VERSION +1 -1
- data/ass.yml +3 -1
- data/lib/ass.rb +2 -404
- data/lib/ass/app.rb +277 -0
- data/lib/ass/conf.rb +165 -0
- metadata +57 -86
data/lib/ass/app.rb
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'yaml'
|
5
|
+
require 'logger'
|
6
|
+
require 'sequel'
|
7
|
+
require 'socket'
|
8
|
+
require 'openssl'
|
9
|
+
require 'cgi'
|
10
|
+
|
11
|
+
require 'rufus/scheduler'
|
12
|
+
require 'eventmachine'
|
13
|
+
require 'sinatra'
|
14
|
+
require 'sinatra/base'
|
15
|
+
require 'sinatra/synchrony'
|
16
|
+
require 'rack/mobile-detect'
|
17
|
+
|
18
|
+
require 'uri'
|
19
|
+
require 'uri-handler'
|
20
|
+
require 'net/http'
|
21
|
+
|
22
|
+
require 'active_support'
|
23
|
+
require 'json'
|
24
|
+
require 'digest/sha2'
|
25
|
+
|
26
|
+
require 'will_paginate'
|
27
|
+
require 'will_paginate/sequel'
|
28
|
+
|
29
|
+
############################################################
|
30
|
+
## Apple Service Server based on Sinatra
|
31
|
+
############################################################
|
32
|
+
|
33
|
+
class App < Sinatra::Base
|
34
|
+
|
35
|
+
register Sinatra::Synchrony
|
36
|
+
|
37
|
+
use Rack::MobileDetect
|
38
|
+
|
39
|
+
enable :logging
|
40
|
+
|
41
|
+
LOGGER = Logger.new("ass-#{$mode}.log", 'a+')
|
42
|
+
|
43
|
+
case $loglevel.upcase
|
44
|
+
when 'FATAL'
|
45
|
+
set :logging, Logger::FATAL
|
46
|
+
when 'ERROR'
|
47
|
+
set :logging, Logger::ERROR
|
48
|
+
when 'WARN'
|
49
|
+
set :logging, Logger::WARN
|
50
|
+
when 'INFO'
|
51
|
+
set :logging, Logger::INFO
|
52
|
+
when 'DEBUG'
|
53
|
+
set :logging, Logger::DEBUG
|
54
|
+
else
|
55
|
+
set :logging, Logger::DEBUG
|
56
|
+
end
|
57
|
+
|
58
|
+
if "#{$mode}".strip == 'production' then
|
59
|
+
set :environment, :production
|
60
|
+
else
|
61
|
+
set :environment, :development
|
62
|
+
end
|
63
|
+
|
64
|
+
set :root, File.expand_path('../../../', __FILE__)
|
65
|
+
set :port, "#{$port}".to_i
|
66
|
+
set :public_folder, File.dirname(__FILE__) + '/../../public'
|
67
|
+
set :views, File.dirname(__FILE__) + '/../../views'
|
68
|
+
|
69
|
+
helpers do
|
70
|
+
|
71
|
+
include Rack::Utils
|
72
|
+
alias_method :h, :escape_html
|
73
|
+
|
74
|
+
def connect_socket(app)
|
75
|
+
openSSLContext = $certkey["#{app}"]
|
76
|
+
sock = nil
|
77
|
+
sslSocket = nil;
|
78
|
+
if $mode == 'production' then
|
79
|
+
sock = TCPSocket.new('gateway.push.apple.com', 2195)
|
80
|
+
else
|
81
|
+
sock = TCPSocket.new('gateway.sandbox.push.apple.com', 2195)
|
82
|
+
end
|
83
|
+
sslSocket = OpenSSL::SSL::SSLSocket.new(sock, openSSLContext)
|
84
|
+
sslSocket.connect
|
85
|
+
|
86
|
+
[sock, sslSocket]
|
87
|
+
end
|
88
|
+
|
89
|
+
def logger
|
90
|
+
LOGGER
|
91
|
+
end
|
92
|
+
|
93
|
+
def checkFlood?(req)
|
94
|
+
if $client_ip != "#{req.ip}" then
|
95
|
+
$client_ip = "#{req.ip}"
|
96
|
+
return false
|
97
|
+
else
|
98
|
+
if $last_access == 0 then
|
99
|
+
return false
|
100
|
+
else
|
101
|
+
return isFlood?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def isFlood?
|
107
|
+
result = (Time.now - $last_access) < $flood * 60
|
108
|
+
$last_access = Time.now
|
109
|
+
return result
|
110
|
+
end
|
111
|
+
|
112
|
+
def iOS?
|
113
|
+
result = case request.env['X_MOBILE_DEVICE']
|
114
|
+
when /iPhone|iPod|iPad/ then
|
115
|
+
true
|
116
|
+
else false
|
117
|
+
end
|
118
|
+
return result
|
119
|
+
end
|
120
|
+
|
121
|
+
def authorized?
|
122
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
123
|
+
@auth.provided? && @auth.basic? && @auth.credentials && @auth.credentials == ["#{$user}", "#{$pass}"]
|
124
|
+
end
|
125
|
+
|
126
|
+
def protected!
|
127
|
+
unless authorized?
|
128
|
+
response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
|
129
|
+
throw(:halt, [401, "Oops... we need your login name & password\n"])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def push(parameter)
|
134
|
+
message = CGI::unescape(parameter[:alert].encode("UTF-8") || "")[0..107]
|
135
|
+
pid = "#{parameter[:pid]}"
|
136
|
+
badge = 1
|
137
|
+
badge = parameter[:badge].to_i if parameter[:badge] and parameter[:badge] != ''
|
138
|
+
sound = CGI::unescape(parameter[:sound] || "")
|
139
|
+
extra = CGI::unescape(parameter[:extra] || "")
|
140
|
+
|
141
|
+
@tokens = Token.where(:app => "#{app}").reverse_order(:id)
|
142
|
+
@exist = Push.first(:pid => "#{pid}", :app => "#{app}")
|
143
|
+
|
144
|
+
unless @exist
|
145
|
+
Push.insert(:pid => pid,
|
146
|
+
:message => message,
|
147
|
+
:created_at => Time.now,
|
148
|
+
:app => "#{app}",
|
149
|
+
:ip => "#{parameter.ip}" )
|
150
|
+
|
151
|
+
sock, sslSocket = connect_socket("#{app}")
|
152
|
+
|
153
|
+
# write our packet to the stream
|
154
|
+
@tokens.each do |o|
|
155
|
+
begin
|
156
|
+
tokenText = "#{o[:token]}"
|
157
|
+
tokenData = [tokenText].pack('H*')
|
158
|
+
aps = {'aps'=> {}}
|
159
|
+
aps['aps']['alert'] = message
|
160
|
+
aps['aps']['badge'] = badge
|
161
|
+
aps['aps']['sound'] = sound
|
162
|
+
aps['aps']['extra'] = extra
|
163
|
+
pm = aps.to_json
|
164
|
+
packet = [0,0,32,devData,0,pm.bytesize,pm].pack("ccca*cca*")
|
165
|
+
sslSocket.write(packet)
|
166
|
+
rescue Errno::EPIPE, OpenSSL::SSL::SSLError => e
|
167
|
+
puts "e: #{e} from id:#{o[:id]}"
|
168
|
+
sleep 3
|
169
|
+
sock, sslSocket = connect_socket("#{app}")
|
170
|
+
next
|
171
|
+
#retry
|
172
|
+
end
|
173
|
+
end
|
174
|
+
# cleanup
|
175
|
+
sslSocket.close
|
176
|
+
sock.close
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def localonly(req)
|
181
|
+
protected! unless req.host == 'localhost'
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
before do
|
187
|
+
if "#{$mode}".strip == 'development' then
|
188
|
+
enable :dump_errors, :raise_errors, :show_exceptions
|
189
|
+
else
|
190
|
+
disable :dump_errors, :raise_errors, :show_exceptions
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
get '/' do
|
195
|
+
erb :index
|
196
|
+
end
|
197
|
+
|
198
|
+
get '/about' do
|
199
|
+
erb :about
|
200
|
+
end
|
201
|
+
|
202
|
+
not_found do
|
203
|
+
erb :not_found
|
204
|
+
end
|
205
|
+
|
206
|
+
error do
|
207
|
+
@error = "";
|
208
|
+
@error = params['captures'].first.inspect if development?
|
209
|
+
end
|
210
|
+
|
211
|
+
post '/v1/send' do
|
212
|
+
app = params[:app]
|
213
|
+
message = CGI::escape(params[:message] || "").encode("UTF-8")
|
214
|
+
pid = "#{Time.now.to_i}"
|
215
|
+
# begin
|
216
|
+
# url = URI.parse("http://localhost:#{$port}/v1/apps/#{app}/push")
|
217
|
+
# post_args1 = { :alert => "#{message}".encode('UTF-8'), :pid => "#{pid}" }
|
218
|
+
# Net::HTTP.post_form(url, post_args1)
|
219
|
+
# rescue =>err
|
220
|
+
# puts "#{err.class} ##{err}"
|
221
|
+
# end
|
222
|
+
system "curl http://localhost:#{$port}/v1/apps/#{app}/push/#{message}/#{pid}"
|
223
|
+
redirect '/v1/admin/push' if (params[:app] and params[:message])
|
224
|
+
end
|
225
|
+
|
226
|
+
get "/v1/admin/:db" do
|
227
|
+
protected!
|
228
|
+
db = params[:db] || 'token'
|
229
|
+
page = 1
|
230
|
+
page = params[:page].to_i if params[:page]
|
231
|
+
if (db == 'token') then
|
232
|
+
@o = []
|
233
|
+
$apps.each_with_index { |app, index|
|
234
|
+
@o << Token.where(:app => app).order(:id).reverse.paginate(page, 20)
|
235
|
+
}
|
236
|
+
erb :token
|
237
|
+
elsif (db == 'push') then
|
238
|
+
@p = []
|
239
|
+
$apps.each_with_index { |app, index|
|
240
|
+
@p << Push.where(:app => app).order(:id).reverse.paginate(page, 20)
|
241
|
+
}
|
242
|
+
erb :push
|
243
|
+
else
|
244
|
+
erb :not_found
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
$apps.each { |app|
|
249
|
+
|
250
|
+
## register token api
|
251
|
+
get "/v1/apps/#{app}/:token" do
|
252
|
+
if (("#{params[:token]}".length == 64) and iOS? and checkFlood?(request) ) then
|
253
|
+
o = Token.first(:app => app, :token => params[:token])
|
254
|
+
unless o
|
255
|
+
Token.insert(
|
256
|
+
:app => app,
|
257
|
+
:token => params[:token],
|
258
|
+
:created_at => Time.now
|
259
|
+
)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
## http POST method push api
|
265
|
+
post "/v1/apps/#{app}/push" do
|
266
|
+
localonly(request)
|
267
|
+
push(params)
|
268
|
+
end
|
269
|
+
|
270
|
+
## http GET method push api
|
271
|
+
## POST method get more options
|
272
|
+
get "/v1/apps/#{app}/push/:message/:pid" do
|
273
|
+
localonly(request)
|
274
|
+
push(params)
|
275
|
+
end
|
276
|
+
}
|
277
|
+
end
|
data/lib/ass/conf.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'yaml'
|
5
|
+
require 'logger'
|
6
|
+
require 'sequel'
|
7
|
+
require 'socket'
|
8
|
+
require 'openssl'
|
9
|
+
require 'cgi'
|
10
|
+
|
11
|
+
require 'rufus/scheduler'
|
12
|
+
|
13
|
+
require 'uri'
|
14
|
+
require 'uri-handler'
|
15
|
+
require 'net/http'
|
16
|
+
|
17
|
+
require 'active_support'
|
18
|
+
require 'json'
|
19
|
+
require 'digest/sha2'
|
20
|
+
|
21
|
+
require 'will_paginate'
|
22
|
+
require 'will_paginate/sequel'
|
23
|
+
|
24
|
+
############################################################
|
25
|
+
## Initilization Setup
|
26
|
+
############################################################
|
27
|
+
LIBDIR = File.expand_path(File.join(File.dirname(__FILE__), '../..', 'lib'))
|
28
|
+
ROOTDIR = File.expand_path(File.join(File.dirname(__FILE__), '../..'))
|
29
|
+
unless $LOAD_PATH.include?(LIBDIR)
|
30
|
+
$LOAD_PATH << LIBDIR
|
31
|
+
end
|
32
|
+
|
33
|
+
unless File.exist?("#{Dir.pwd}/ass.yml") then
|
34
|
+
puts 'create config file: ass.yml'
|
35
|
+
system "cp #{ROOTDIR}/ass.yml #{Dir.pwd}/ass.yml"
|
36
|
+
end
|
37
|
+
|
38
|
+
unless File.exist?("#{Dir.pwd}/cron") then
|
39
|
+
puts "create a demo 'cron' script"
|
40
|
+
system "cp #{ROOTDIR}/cron #{Dir.pwd}/cron"
|
41
|
+
end
|
42
|
+
|
43
|
+
############################################################
|
44
|
+
## Configuration Setup
|
45
|
+
############################################################
|
46
|
+
env = ENV['SINATRA_ENV'] || "development"
|
47
|
+
config = YAML.load_file("#{Dir.pwd}/ass.yml")
|
48
|
+
$timer = "#{config['timer']}".to_i
|
49
|
+
$cron = config['cron'] || 'cron'
|
50
|
+
$port = "#{config['port']}".to_i || 4567
|
51
|
+
$mode = config['mode'] || env
|
52
|
+
$VERSION = File.open("#{ROOTDIR}/VERSION", "rb").read
|
53
|
+
$apps = config['apps'] || []
|
54
|
+
$log = config['log'] || 'off'
|
55
|
+
$user = config['user'] || 'admin'
|
56
|
+
$pass = config['pass'] || 'pass'
|
57
|
+
$pempass = config['pempass'] || ''
|
58
|
+
$loglevel = config['loglevel'] || 'info'
|
59
|
+
$flood = "#{config['flood']}".to_i || 1 # default 1 minute
|
60
|
+
|
61
|
+
$client_ip = '127.0.0.1'
|
62
|
+
$last_access = 0
|
63
|
+
|
64
|
+
############################################################
|
65
|
+
## Certificate Key Setup
|
66
|
+
############################################################
|
67
|
+
|
68
|
+
$certkey = {}
|
69
|
+
|
70
|
+
def check_cert
|
71
|
+
$apps.each { |app|
|
72
|
+
unless File.exist?("#{Dir.pwd}/#{app}_#{$mode}.pem") then
|
73
|
+
puts "Please provide #{app}_#{$mode}.pem under '#{Dir.pwd}/' directory"
|
74
|
+
return false;
|
75
|
+
else
|
76
|
+
puts "'#{app}'s #{$mode} PEM: (#{app}_#{$mode}.pem)"
|
77
|
+
certfile = File.read("#{Dir.pwd}/#{app}_#{$mode}.pem")
|
78
|
+
openSSLContext = OpenSSL::SSL::SSLContext.new
|
79
|
+
openSSLContext.cert = OpenSSL::X509::Certificate.new(certfile)
|
80
|
+
if $pempass == '' then
|
81
|
+
openSSLContext.key = OpenSSL::PKey::RSA.new(certfile)
|
82
|
+
else
|
83
|
+
openSSLContext.key = OpenSSL::PKey::RSA.new(certfile,"#{$pempass}")
|
84
|
+
end
|
85
|
+
$certkey["#{app}"] = openSSLContext
|
86
|
+
end
|
87
|
+
}
|
88
|
+
return true
|
89
|
+
end
|
90
|
+
|
91
|
+
unless check_cert then
|
92
|
+
html = <<-END
|
93
|
+
1: please provide certificate key pem file under current directory, name should be: appid_development.pem for development and appid_production.pem for production
|
94
|
+
2: edit your ass.yml under current directory
|
95
|
+
3: run ass
|
96
|
+
4: iOS Client: in AppDelegate file, didRegisterForRemoteNotificationsWithDeviceToken method should access url below:
|
97
|
+
END
|
98
|
+
$apps.each { |app|
|
99
|
+
html << "'#{app}'s registration url: http://serverIP:#{$port}/v1/apps/#{app}/DeviceToken"
|
100
|
+
}
|
101
|
+
html << "5: Server: cron should access 'curl http://localhost:#{$port}/v1/app/push/{messages}/{pid}' to send push message"
|
102
|
+
puts html
|
103
|
+
exit
|
104
|
+
else
|
105
|
+
html = <<-END
|
106
|
+
#{'*'*80}
|
107
|
+
Apple Service Server(#{$VERSION}) is Running ...
|
108
|
+
Push Notification Service: Enabled
|
109
|
+
Mode: #{$mode}
|
110
|
+
Port: #{$port}
|
111
|
+
END
|
112
|
+
html << "#{'*'*80}"
|
113
|
+
html << "Cron Job: '#{Dir.pwd}/#{$cron}' script is running every #{$timer} #{($timer == 1) ? 'minute' : 'minutes'} " unless "#{$timer}".to_i == 0
|
114
|
+
html << "\n"
|
115
|
+
html << "access http://localhost:#{$port}/ for more information"
|
116
|
+
html << "\n"
|
117
|
+
html << "#{'*'*80}"
|
118
|
+
puts html
|
119
|
+
end
|
120
|
+
|
121
|
+
############################################################
|
122
|
+
## Sequel Database Setup
|
123
|
+
############################################################
|
124
|
+
|
125
|
+
unless File.exist?("#{Dir.pwd}/ass-#{$mode}.db") then
|
126
|
+
$DB = Sequel.connect("sqlite://#{Dir.pwd}/ass-#{$mode}.db")
|
127
|
+
$DB.create_table :tokens do
|
128
|
+
primary_key :id
|
129
|
+
String :app, :unique => false, :null => false
|
130
|
+
String :token, :unique => false, :null => false, :size => 100
|
131
|
+
Time :created_at
|
132
|
+
index [:app, :token]
|
133
|
+
end
|
134
|
+
$DB.create_table :pushes do
|
135
|
+
primary_key :id
|
136
|
+
String :pid, :unique => false, :null => false, :size => 100
|
137
|
+
String :app, :unique => false, :null => false, :size => 30
|
138
|
+
String :message, :unique => false, :null => false, :size => 107
|
139
|
+
String :ip, :unique => false, :null => false, :size => 20
|
140
|
+
Time :created_at
|
141
|
+
index [:pid, :app, :message]
|
142
|
+
end
|
143
|
+
else
|
144
|
+
$DB = Sequel.connect("sqlite://#{Dir.pwd}/ass-#{$mode}.db")
|
145
|
+
end
|
146
|
+
|
147
|
+
class Token < Sequel::Model
|
148
|
+
Sequel.extension :pagination
|
149
|
+
end
|
150
|
+
|
151
|
+
class Push < Sequel::Model
|
152
|
+
Sequel.extension :pagination
|
153
|
+
end
|
154
|
+
|
155
|
+
############################################################
|
156
|
+
## Timer Job Setup
|
157
|
+
############################################################
|
158
|
+
scheduler = Rufus::Scheduler.start_new
|
159
|
+
|
160
|
+
unless $timer == 0 then
|
161
|
+
scheduler.every "#{$timer}m" do
|
162
|
+
puts "running job: '#{Dir.pwd}/#{$cron}' every #{$timer} #{($timer == 1) ? 'minute' : 'minutes'}"
|
163
|
+
system "./#{$cron}"
|
164
|
+
end
|
165
|
+
end
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.24
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Eiffel Qiu
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-10-23 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: sqlite3
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: thin
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: json
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,23 +55,20 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: sinatra
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
|
-
- -
|
59
|
+
- - ! '>='
|
68
60
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
61
|
+
version: '0'
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
|
-
- -
|
66
|
+
- - ! '>='
|
76
67
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
68
|
+
version: '0'
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: sequel
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ! '>='
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ! '>='
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: rufus-scheduler
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ! '>='
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :runtime
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ! '>='
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -110,7 +97,6 @@ dependencies:
|
|
110
97
|
- !ruby/object:Gem::Dependency
|
111
98
|
name: eventmachine
|
112
99
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
100
|
requirements:
|
115
101
|
- - ! '>='
|
116
102
|
- !ruby/object:Gem::Version
|
@@ -118,7 +104,6 @@ dependencies:
|
|
118
104
|
type: :runtime
|
119
105
|
prerelease: false
|
120
106
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
107
|
requirements:
|
123
108
|
- - ! '>='
|
124
109
|
- !ruby/object:Gem::Version
|
@@ -126,23 +111,20 @@ dependencies:
|
|
126
111
|
- !ruby/object:Gem::Dependency
|
127
112
|
name: activesupport
|
128
113
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
114
|
requirements:
|
131
115
|
- - ! '>='
|
132
116
|
- !ruby/object:Gem::Version
|
133
|
-
version:
|
117
|
+
version: '0'
|
134
118
|
type: :runtime
|
135
119
|
prerelease: false
|
136
120
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
121
|
requirements:
|
139
122
|
- - ! '>='
|
140
123
|
- !ruby/object:Gem::Version
|
141
|
-
version:
|
124
|
+
version: '0'
|
142
125
|
- !ruby/object:Gem::Dependency
|
143
126
|
name: uri-handler
|
144
127
|
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
128
|
requirements:
|
147
129
|
- - ! '>='
|
148
130
|
- !ruby/object:Gem::Version
|
@@ -150,7 +132,6 @@ dependencies:
|
|
150
132
|
type: :runtime
|
151
133
|
prerelease: false
|
152
134
|
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
135
|
requirements:
|
155
136
|
- - ! '>='
|
156
137
|
- !ruby/object:Gem::Version
|
@@ -158,23 +139,20 @@ dependencies:
|
|
158
139
|
- !ruby/object:Gem::Dependency
|
159
140
|
name: will_paginate
|
160
141
|
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
142
|
requirements:
|
163
|
-
- -
|
143
|
+
- - ! '>='
|
164
144
|
- !ruby/object:Gem::Version
|
165
|
-
version: '
|
145
|
+
version: '0'
|
166
146
|
type: :runtime
|
167
147
|
prerelease: false
|
168
148
|
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
149
|
requirements:
|
171
|
-
- -
|
150
|
+
- - ! '>='
|
172
151
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
152
|
+
version: '0'
|
174
153
|
- !ruby/object:Gem::Dependency
|
175
154
|
name: sinatra-contrib
|
176
155
|
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
156
|
requirements:
|
179
157
|
- - ! '>='
|
180
158
|
- !ruby/object:Gem::Version
|
@@ -182,7 +160,6 @@ dependencies:
|
|
182
160
|
type: :runtime
|
183
161
|
prerelease: false
|
184
162
|
version_requirements: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
163
|
requirements:
|
187
164
|
- - ! '>='
|
188
165
|
- !ruby/object:Gem::Version
|
@@ -190,7 +167,6 @@ dependencies:
|
|
190
167
|
- !ruby/object:Gem::Dependency
|
191
168
|
name: rack-mobile-detect
|
192
169
|
requirement: !ruby/object:Gem::Requirement
|
193
|
-
none: false
|
194
170
|
requirements:
|
195
171
|
- - ! '>='
|
196
172
|
- !ruby/object:Gem::Version
|
@@ -198,7 +174,6 @@ dependencies:
|
|
198
174
|
type: :runtime
|
199
175
|
prerelease: false
|
200
176
|
version_requirements: !ruby/object:Gem::Requirement
|
201
|
-
none: false
|
202
177
|
requirements:
|
203
178
|
- - ! '>='
|
204
179
|
- !ruby/object:Gem::Version
|
@@ -206,23 +181,20 @@ dependencies:
|
|
206
181
|
- !ruby/object:Gem::Dependency
|
207
182
|
name: sinatra-synchrony
|
208
183
|
requirement: !ruby/object:Gem::Requirement
|
209
|
-
none: false
|
210
184
|
requirements:
|
211
|
-
- -
|
185
|
+
- - ! '>='
|
212
186
|
- !ruby/object:Gem::Version
|
213
|
-
version: 0
|
187
|
+
version: '0'
|
214
188
|
type: :runtime
|
215
189
|
prerelease: false
|
216
190
|
version_requirements: !ruby/object:Gem::Requirement
|
217
|
-
none: false
|
218
191
|
requirements:
|
219
|
-
- -
|
192
|
+
- - ! '>='
|
220
193
|
- !ruby/object:Gem::Version
|
221
|
-
version: 0
|
194
|
+
version: '0'
|
222
195
|
- !ruby/object:Gem::Dependency
|
223
196
|
name: shoulda
|
224
197
|
requirement: !ruby/object:Gem::Requirement
|
225
|
-
none: false
|
226
198
|
requirements:
|
227
199
|
- - ! '>='
|
228
200
|
- !ruby/object:Gem::Version
|
@@ -230,7 +202,6 @@ dependencies:
|
|
230
202
|
type: :development
|
231
203
|
prerelease: false
|
232
204
|
version_requirements: !ruby/object:Gem::Requirement
|
233
|
-
none: false
|
234
205
|
requirements:
|
235
206
|
- - ! '>='
|
236
207
|
- !ruby/object:Gem::Version
|
@@ -238,23 +209,20 @@ dependencies:
|
|
238
209
|
- !ruby/object:Gem::Dependency
|
239
210
|
name: rdoc
|
240
211
|
requirement: !ruby/object:Gem::Requirement
|
241
|
-
none: false
|
242
212
|
requirements:
|
243
|
-
- -
|
213
|
+
- - ! '>='
|
244
214
|
- !ruby/object:Gem::Version
|
245
|
-
version: '
|
215
|
+
version: '0'
|
246
216
|
type: :development
|
247
217
|
prerelease: false
|
248
218
|
version_requirements: !ruby/object:Gem::Requirement
|
249
|
-
none: false
|
250
219
|
requirements:
|
251
|
-
- -
|
220
|
+
- - ! '>='
|
252
221
|
- !ruby/object:Gem::Version
|
253
|
-
version: '
|
222
|
+
version: '0'
|
254
223
|
- !ruby/object:Gem::Dependency
|
255
224
|
name: bundler
|
256
225
|
requirement: !ruby/object:Gem::Requirement
|
257
|
-
none: false
|
258
226
|
requirements:
|
259
227
|
- - ! '>='
|
260
228
|
- !ruby/object:Gem::Version
|
@@ -262,7 +230,6 @@ dependencies:
|
|
262
230
|
type: :development
|
263
231
|
prerelease: false
|
264
232
|
version_requirements: !ruby/object:Gem::Requirement
|
265
|
-
none: false
|
266
233
|
requirements:
|
267
234
|
- - ! '>='
|
268
235
|
- !ruby/object:Gem::Version
|
@@ -270,23 +237,20 @@ dependencies:
|
|
270
237
|
- !ruby/object:Gem::Dependency
|
271
238
|
name: jeweler
|
272
239
|
requirement: !ruby/object:Gem::Requirement
|
273
|
-
none: false
|
274
240
|
requirements:
|
275
|
-
- -
|
241
|
+
- - ! '>='
|
276
242
|
- !ruby/object:Gem::Version
|
277
|
-
version:
|
243
|
+
version: '0'
|
278
244
|
type: :development
|
279
245
|
prerelease: false
|
280
246
|
version_requirements: !ruby/object:Gem::Requirement
|
281
|
-
none: false
|
282
247
|
requirements:
|
283
|
-
- -
|
248
|
+
- - ! '>='
|
284
249
|
- !ruby/object:Gem::Version
|
285
|
-
version:
|
250
|
+
version: '0'
|
286
251
|
- !ruby/object:Gem::Dependency
|
287
252
|
name: sqlite3
|
288
253
|
requirement: !ruby/object:Gem::Requirement
|
289
|
-
none: false
|
290
254
|
requirements:
|
291
255
|
- - ! '>='
|
292
256
|
- !ruby/object:Gem::Version
|
@@ -294,7 +258,6 @@ dependencies:
|
|
294
258
|
type: :runtime
|
295
259
|
prerelease: false
|
296
260
|
version_requirements: !ruby/object:Gem::Requirement
|
297
|
-
none: false
|
298
261
|
requirements:
|
299
262
|
- - ! '>='
|
300
263
|
- !ruby/object:Gem::Version
|
@@ -302,7 +265,6 @@ dependencies:
|
|
302
265
|
- !ruby/object:Gem::Dependency
|
303
266
|
name: thin
|
304
267
|
requirement: !ruby/object:Gem::Requirement
|
305
|
-
none: false
|
306
268
|
requirements:
|
307
269
|
- - ! '>='
|
308
270
|
- !ruby/object:Gem::Version
|
@@ -310,7 +272,6 @@ dependencies:
|
|
310
272
|
type: :runtime
|
311
273
|
prerelease: false
|
312
274
|
version_requirements: !ruby/object:Gem::Requirement
|
313
|
-
none: false
|
314
275
|
requirements:
|
315
276
|
- - ! '>='
|
316
277
|
- !ruby/object:Gem::Version
|
@@ -318,7 +279,6 @@ dependencies:
|
|
318
279
|
- !ruby/object:Gem::Dependency
|
319
280
|
name: sinatra
|
320
281
|
requirement: !ruby/object:Gem::Requirement
|
321
|
-
none: false
|
322
282
|
requirements:
|
323
283
|
- - ! '>='
|
324
284
|
- !ruby/object:Gem::Version
|
@@ -326,7 +286,6 @@ dependencies:
|
|
326
286
|
type: :runtime
|
327
287
|
prerelease: false
|
328
288
|
version_requirements: !ruby/object:Gem::Requirement
|
329
|
-
none: false
|
330
289
|
requirements:
|
331
290
|
- - ! '>='
|
332
291
|
- !ruby/object:Gem::Version
|
@@ -334,7 +293,6 @@ dependencies:
|
|
334
293
|
- !ruby/object:Gem::Dependency
|
335
294
|
name: sequel
|
336
295
|
requirement: !ruby/object:Gem::Requirement
|
337
|
-
none: false
|
338
296
|
requirements:
|
339
297
|
- - ! '>='
|
340
298
|
- !ruby/object:Gem::Version
|
@@ -342,7 +300,6 @@ dependencies:
|
|
342
300
|
type: :runtime
|
343
301
|
prerelease: false
|
344
302
|
version_requirements: !ruby/object:Gem::Requirement
|
345
|
-
none: false
|
346
303
|
requirements:
|
347
304
|
- - ! '>='
|
348
305
|
- !ruby/object:Gem::Version
|
@@ -350,7 +307,6 @@ dependencies:
|
|
350
307
|
- !ruby/object:Gem::Dependency
|
351
308
|
name: rufus-scheduler
|
352
309
|
requirement: !ruby/object:Gem::Requirement
|
353
|
-
none: false
|
354
310
|
requirements:
|
355
311
|
- - ! '>='
|
356
312
|
- !ruby/object:Gem::Version
|
@@ -358,7 +314,6 @@ dependencies:
|
|
358
314
|
type: :runtime
|
359
315
|
prerelease: false
|
360
316
|
version_requirements: !ruby/object:Gem::Requirement
|
361
|
-
none: false
|
362
317
|
requirements:
|
363
318
|
- - ! '>='
|
364
319
|
- !ruby/object:Gem::Version
|
@@ -366,7 +321,6 @@ dependencies:
|
|
366
321
|
- !ruby/object:Gem::Dependency
|
367
322
|
name: eventmachine
|
368
323
|
requirement: !ruby/object:Gem::Requirement
|
369
|
-
none: false
|
370
324
|
requirements:
|
371
325
|
- - ! '>='
|
372
326
|
- !ruby/object:Gem::Version
|
@@ -374,7 +328,6 @@ dependencies:
|
|
374
328
|
type: :runtime
|
375
329
|
prerelease: false
|
376
330
|
version_requirements: !ruby/object:Gem::Requirement
|
377
|
-
none: false
|
378
331
|
requirements:
|
379
332
|
- - ! '>='
|
380
333
|
- !ruby/object:Gem::Version
|
@@ -382,7 +335,6 @@ dependencies:
|
|
382
335
|
- !ruby/object:Gem::Dependency
|
383
336
|
name: activesupport
|
384
337
|
requirement: !ruby/object:Gem::Requirement
|
385
|
-
none: false
|
386
338
|
requirements:
|
387
339
|
- - ! '>='
|
388
340
|
- !ruby/object:Gem::Version
|
@@ -390,7 +342,6 @@ dependencies:
|
|
390
342
|
type: :runtime
|
391
343
|
prerelease: false
|
392
344
|
version_requirements: !ruby/object:Gem::Requirement
|
393
|
-
none: false
|
394
345
|
requirements:
|
395
346
|
- - ! '>='
|
396
347
|
- !ruby/object:Gem::Version
|
@@ -398,7 +349,6 @@ dependencies:
|
|
398
349
|
- !ruby/object:Gem::Dependency
|
399
350
|
name: uri-handler
|
400
351
|
requirement: !ruby/object:Gem::Requirement
|
401
|
-
none: false
|
402
352
|
requirements:
|
403
353
|
- - ! '>='
|
404
354
|
- !ruby/object:Gem::Version
|
@@ -406,7 +356,6 @@ dependencies:
|
|
406
356
|
type: :runtime
|
407
357
|
prerelease: false
|
408
358
|
version_requirements: !ruby/object:Gem::Requirement
|
409
|
-
none: false
|
410
359
|
requirements:
|
411
360
|
- - ! '>='
|
412
361
|
- !ruby/object:Gem::Version
|
@@ -414,7 +363,6 @@ dependencies:
|
|
414
363
|
- !ruby/object:Gem::Dependency
|
415
364
|
name: will_paginate
|
416
365
|
requirement: !ruby/object:Gem::Requirement
|
417
|
-
none: false
|
418
366
|
requirements:
|
419
367
|
- - ~>
|
420
368
|
- !ruby/object:Gem::Version
|
@@ -422,7 +370,6 @@ dependencies:
|
|
422
370
|
type: :runtime
|
423
371
|
prerelease: false
|
424
372
|
version_requirements: !ruby/object:Gem::Requirement
|
425
|
-
none: false
|
426
373
|
requirements:
|
427
374
|
- - ~>
|
428
375
|
- !ruby/object:Gem::Version
|
@@ -430,7 +377,6 @@ dependencies:
|
|
430
377
|
- !ruby/object:Gem::Dependency
|
431
378
|
name: sinatra-contrib
|
432
379
|
requirement: !ruby/object:Gem::Requirement
|
433
|
-
none: false
|
434
380
|
requirements:
|
435
381
|
- - ! '>='
|
436
382
|
- !ruby/object:Gem::Version
|
@@ -438,7 +384,34 @@ dependencies:
|
|
438
384
|
type: :runtime
|
439
385
|
prerelease: false
|
440
386
|
version_requirements: !ruby/object:Gem::Requirement
|
441
|
-
|
387
|
+
requirements:
|
388
|
+
- - ! '>='
|
389
|
+
- !ruby/object:Gem::Version
|
390
|
+
version: '0'
|
391
|
+
- !ruby/object:Gem::Dependency
|
392
|
+
name: rack-mobile-detect
|
393
|
+
requirement: !ruby/object:Gem::Requirement
|
394
|
+
requirements:
|
395
|
+
- - ! '>='
|
396
|
+
- !ruby/object:Gem::Version
|
397
|
+
version: '0'
|
398
|
+
type: :runtime
|
399
|
+
prerelease: false
|
400
|
+
version_requirements: !ruby/object:Gem::Requirement
|
401
|
+
requirements:
|
402
|
+
- - ! '>='
|
403
|
+
- !ruby/object:Gem::Version
|
404
|
+
version: '0'
|
405
|
+
- !ruby/object:Gem::Dependency
|
406
|
+
name: sinatra-synchrony
|
407
|
+
requirement: !ruby/object:Gem::Requirement
|
408
|
+
requirements:
|
409
|
+
- - ! '>='
|
410
|
+
- !ruby/object:Gem::Version
|
411
|
+
version: '0'
|
412
|
+
type: :runtime
|
413
|
+
prerelease: false
|
414
|
+
version_requirements: !ruby/object:Gem::Requirement
|
442
415
|
requirements:
|
443
416
|
- - ! '>='
|
444
417
|
- !ruby/object:Gem::Version
|
@@ -458,6 +431,8 @@ files:
|
|
458
431
|
- ass.yml
|
459
432
|
- cron
|
460
433
|
- lib/ass.rb
|
434
|
+
- lib/ass/app.rb
|
435
|
+
- lib/ass/conf.rb
|
461
436
|
- public/css/bootstrap-responsive.css
|
462
437
|
- public/css/bootstrap-responsive.min.css
|
463
438
|
- public/css/bootstrap.css
|
@@ -478,29 +453,25 @@ files:
|
|
478
453
|
homepage: http://github.com/eiffelqiu/ass
|
479
454
|
licenses:
|
480
455
|
- MIT
|
456
|
+
metadata: {}
|
481
457
|
post_install_message:
|
482
458
|
rdoc_options: []
|
483
459
|
require_paths:
|
484
460
|
- lib
|
485
461
|
required_ruby_version: !ruby/object:Gem::Requirement
|
486
|
-
none: false
|
487
462
|
requirements:
|
488
463
|
- - ! '>='
|
489
464
|
- !ruby/object:Gem::Version
|
490
465
|
version: '0'
|
491
|
-
segments:
|
492
|
-
- 0
|
493
|
-
hash: -3291505526784258788
|
494
466
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
495
|
-
none: false
|
496
467
|
requirements:
|
497
468
|
- - ! '>='
|
498
469
|
- !ruby/object:Gem::Version
|
499
470
|
version: '0'
|
500
471
|
requirements: []
|
501
472
|
rubyforge_project: ass
|
502
|
-
rubygems_version: 1.
|
473
|
+
rubygems_version: 2.1.9
|
503
474
|
signing_key:
|
504
|
-
specification_version:
|
475
|
+
specification_version: 4
|
505
476
|
summary: Apple Service Server
|
506
477
|
test_files: []
|