qm 1.2.2 → 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/qm.rb +55 -25
- data/lib/{client.rb → qm/client.rb} +0 -0
- data/lib/qm/defs-mongo.rb +127 -0
- data/lib/{service.rb → qm/service.rb} +47 -34
- metadata +19 -5
- data/lib/defs-mongo.rb +0 -116
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0aed10f6857450ae540fea58ff7d244cbd25fe2c
|
4
|
+
data.tar.gz: 00aca546287a88a5f110039f63a82f6b53df2e37
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0372ab2af4f83154ea65e3ca914e1092e49ccedea35da6a375e639a2de6296cd6083253ab6f9a8816a989e8a2b25db9fd069620b9f53d08fa710833795a5aa21
|
7
|
+
data.tar.gz: 66787f708e1cfe4d5354d6df1e2a881350fa8cad4da42f51d02126477bf60bc562e3cc83b5cc4f135975384a241636cc72c2b61b4053bc31de06e86ed922b12a
|
data/lib/qm.rb
CHANGED
@@ -2,23 +2,17 @@
|
|
2
2
|
|
3
3
|
#- qm.rb ~~
|
4
4
|
# ~~ (c) SRW, 12 Apr 2013
|
5
|
-
# ~~ last updated
|
5
|
+
# ~~ last updated 23 Jan 2015
|
6
6
|
|
7
7
|
module QM
|
8
8
|
|
9
|
-
def self::
|
10
|
-
# This function
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def self::launch_service(options = {})
|
16
|
-
# This function creates, configures, and launches a fresh Sinatra app
|
17
|
-
# that inherits from the original "teaching version".
|
18
|
-
require 'defs-mongo'
|
19
|
-
require 'service'
|
9
|
+
def self::create_app(options = {})
|
10
|
+
# This function creates and configures a fresh Sinatra app that inherits
|
11
|
+
# from the original "teaching version". This code is separated from the
|
12
|
+
# `launch_service` method's code to allow a `QMachineService` instance to
|
13
|
+
# be used from the "config.ru" file of a Rack app.
|
14
|
+
require 'qm/service'
|
20
15
|
app = Sinatra.new(QMachineService) do
|
21
|
-
register Sinatra::MongoConnect
|
22
16
|
configure do
|
23
17
|
convert = lambda do |x|
|
24
18
|
# This converts all keys in a hash to symbols recursively.
|
@@ -32,22 +26,58 @@ module QM
|
|
32
26
|
end
|
33
27
|
options = convert.call(options)
|
34
28
|
set options
|
35
|
-
if settings.persistent_storage.has_key?(:mongo) then
|
36
|
-
helpers Sinatra::MongoAPIDefs
|
37
|
-
mongo_api_connect
|
38
|
-
end
|
39
|
-
if settings.trafficlog_storage.has_key?(:mongo) then
|
40
|
-
helpers Sinatra::MongoLogDefs
|
41
|
-
mongo_log_connect
|
42
|
-
after do
|
43
|
-
log_to_db unless response.status == 444
|
44
|
-
end
|
45
|
-
end
|
46
29
|
end
|
47
30
|
end
|
48
|
-
return app
|
31
|
+
return app
|
49
32
|
end
|
50
33
|
|
34
|
+
def self::launch_client(options = {mothership: 'https://api.qmachine.org'})
|
35
|
+
# This function needs documentation.
|
36
|
+
require 'qm/client'
|
37
|
+
return QMachineClient.new(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self::launch_service(options = {})
|
41
|
+
# This function launches a new app using Unicorn :-)
|
42
|
+
require 'unicorn'
|
43
|
+
app = self::create_app(options)
|
44
|
+
Unicorn::HttpServer.new(app, {
|
45
|
+
listeners: [
|
46
|
+
app.settings.hostname.to_s + ':' + app.settings.port.to_s
|
47
|
+
],
|
48
|
+
preload_app: true,
|
49
|
+
timeout: 30,
|
50
|
+
worker_processes: app.settings.worker_procs.to_s.to_i(10)
|
51
|
+
}).start.join
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
=begin
|
56
|
+
def self::launch_service(options = {})
|
57
|
+
# This function launches a new app using Puma. I would prefer to use Puma
|
58
|
+
# instead of Unicorn in the future, in order to support as many of the
|
59
|
+
# different Ruby platforms as possible, but that's not the main priority
|
60
|
+
# for this "teaching version" anyway. Puma will teach *me* a lot about
|
61
|
+
# concurrency in the meantime :-)
|
62
|
+
require 'puma'
|
63
|
+
app = self::create_app(options)
|
64
|
+
server = Puma::Server.new(app)
|
65
|
+
server.add_tcp_listener(app.settings.hostname, app.settings.port)
|
66
|
+
server.min_threads = 1
|
67
|
+
server.max_threads = 16
|
68
|
+
puts "QM up -> http://#{app.settings.hostname}:#{app.settings.port} ..."
|
69
|
+
server.run.join
|
70
|
+
return
|
71
|
+
end
|
72
|
+
=end
|
73
|
+
|
74
|
+
def self::version()
|
75
|
+
# This function exists because it exists in the Node.js version.
|
76
|
+
return VERSION
|
77
|
+
end
|
78
|
+
|
79
|
+
VERSION = '1.2.3'
|
80
|
+
|
51
81
|
end
|
52
82
|
|
53
83
|
#- vim:set syntax=ruby:
|
File without changes
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#- Ruby source code
|
2
|
+
|
3
|
+
#- defs-mongo.rb ~~
|
4
|
+
# ~~ (c) SRW, 16 Jul 2014
|
5
|
+
# ~~ last updated 22 Jan 2015
|
6
|
+
|
7
|
+
require 'json'
|
8
|
+
require 'mongo'
|
9
|
+
require 'sinatra/base'
|
10
|
+
|
11
|
+
module Sinatra
|
12
|
+
|
13
|
+
module MongoConnect
|
14
|
+
|
15
|
+
def connect_api_store(opts = settings.persistent_storage)
|
16
|
+
# This helper function needs documentation.
|
17
|
+
db = Mongo::MongoClient.from_uri(opts[:mongo]).db
|
18
|
+
db.collection('avars').ensure_index({
|
19
|
+
box: Mongo::ASCENDING,
|
20
|
+
key: Mongo::ASCENDING
|
21
|
+
}, {
|
22
|
+
unique: true
|
23
|
+
})
|
24
|
+
db.collection('avars').ensure_index('exp_date', {
|
25
|
+
expireAfterSeconds: 0
|
26
|
+
})
|
27
|
+
return db
|
28
|
+
end
|
29
|
+
|
30
|
+
def connect_log_store(opts = settings.trafficlog_storage)
|
31
|
+
# This helper function needs documentation.
|
32
|
+
if opts.has_key?(:mongo) then
|
33
|
+
return Mongo::MongoClient.from_uri(opts[:mongo]).db
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
module MongoAPIDefs
|
40
|
+
|
41
|
+
def get_avar(params)
|
42
|
+
# This helper function needs documentation.
|
43
|
+
x = settings.api_db.collection('avars').find_and_modify({
|
44
|
+
query: {
|
45
|
+
box: params[0],
|
46
|
+
key: params[1]
|
47
|
+
},
|
48
|
+
update: {
|
49
|
+
'$set': {
|
50
|
+
exp_date: Time.now + settings.avar_ttl
|
51
|
+
}
|
52
|
+
},
|
53
|
+
fields: {
|
54
|
+
_id: 0,
|
55
|
+
body: 1
|
56
|
+
},
|
57
|
+
upsert: false
|
58
|
+
})
|
59
|
+
return (x.nil?) ? '{}' : x['body']
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_list(params)
|
63
|
+
# This helper function needs documentation.
|
64
|
+
opts = {
|
65
|
+
fields: {
|
66
|
+
_id: 0,
|
67
|
+
key: 1
|
68
|
+
}
|
69
|
+
}
|
70
|
+
query = {
|
71
|
+
box: params[0],
|
72
|
+
status: params[1]
|
73
|
+
}
|
74
|
+
x = []
|
75
|
+
settings.api_db.collection('avars').find(query, opts).each do |doc|
|
76
|
+
# This block needs documentation.
|
77
|
+
x.push(doc['key'])
|
78
|
+
end
|
79
|
+
return (x.length == 0) ? '[]' : x.to_json
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_avar(params)
|
83
|
+
# This helper function needs documentation.
|
84
|
+
doc = {
|
85
|
+
body: params.last,
|
86
|
+
box: params[0],
|
87
|
+
exp_date: Time.now + settings.avar_ttl,
|
88
|
+
key: params[1]
|
89
|
+
}
|
90
|
+
doc['status'] = params[2] if params.length == 4
|
91
|
+
opts = {
|
92
|
+
multi: false,
|
93
|
+
upsert: true
|
94
|
+
}
|
95
|
+
query = {
|
96
|
+
box: params[0],
|
97
|
+
key: params[1]
|
98
|
+
}
|
99
|
+
settings.api_db.collection('avars').update(query, doc, opts)
|
100
|
+
return
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
module MongoLogDefs
|
106
|
+
|
107
|
+
def log_to_db()
|
108
|
+
# This helper function needs documentation.
|
109
|
+
settings.log_db.collection('traffic').insert({
|
110
|
+
host: request.host,
|
111
|
+
ip: request.ip,
|
112
|
+
method: request.request_method,
|
113
|
+
status_code: response.status,
|
114
|
+
timestamp: Time.now,
|
115
|
+
url: request.fullpath
|
116
|
+
})
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
helpers MongoAPIDefs, MongoLogDefs
|
123
|
+
register MongoConnect
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
#- vim:set syntax=ruby:
|
@@ -16,41 +16,50 @@
|
|
16
16
|
# of a 'box', 'key', or 'status' value.
|
17
17
|
#
|
18
18
|
# ~~ (c) SRW, 24 Apr 2013
|
19
|
-
# ~~ last updated
|
19
|
+
# ~~ last updated 23 Jan 2015
|
20
20
|
|
21
|
-
require '
|
21
|
+
require 'qm/defs-mongo'
|
22
|
+
require 'sinatra/base'
|
22
23
|
require 'sinatra/cross_origin'
|
23
24
|
|
24
25
|
class QMachineService < Sinatra::Base
|
25
26
|
|
26
27
|
register Sinatra::CrossOrigin
|
28
|
+
register Sinatra::MongoConnect
|
27
29
|
|
28
30
|
configure do
|
29
31
|
|
32
|
+
# Helper methods
|
33
|
+
|
34
|
+
helpers Sinatra::MongoAPIDefs, Sinatra::MongoLogDefs
|
35
|
+
|
30
36
|
# QMachine options
|
31
37
|
|
32
|
-
set avar_ttl:
|
33
|
-
enable_api_server:
|
34
|
-
enable_cors:
|
35
|
-
enable_web_server:
|
36
|
-
hostname:
|
37
|
-
max_body_size:
|
38
|
-
persistent_storage:
|
39
|
-
port:
|
40
|
-
public_folder:
|
41
|
-
trafficlog_storage:
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
38
|
+
set avar_ttl: 86400, # seconds (24 * 60 * 60 = 1 day)
|
39
|
+
enable_api_server: false,
|
40
|
+
enable_cors: false,
|
41
|
+
enable_web_server: false,
|
42
|
+
hostname: '0.0.0.0',
|
43
|
+
max_body_size: 65536, # bytes (64 * 1024 = 64 KB)
|
44
|
+
persistent_storage: {},
|
45
|
+
port: 8177,
|
46
|
+
public_folder: 'public',
|
47
|
+
trafficlog_storage: {},
|
48
|
+
worker_procs: 1
|
49
|
+
|
50
|
+
# Sinatra mappings and options needed by QMachine
|
51
|
+
|
52
|
+
mime_type webapp: 'application/x-web-app-manifest+json'
|
53
|
+
|
54
|
+
set api_db: lambda { connect_api_store },
|
55
|
+
bind: lambda { settings.hostname },
|
56
|
+
log_db: lambda { connect_log_store },
|
57
|
+
logging: lambda { settings.log_db.nil? },
|
58
|
+
raise_errors: false,
|
59
|
+
run: false,
|
60
|
+
show_exceptions: false,
|
61
|
+
static: lambda { settings.enable_web_server },
|
62
|
+
x_cascade: false
|
54
63
|
|
55
64
|
# See also: http://www.sinatrarb.com/configuration.html
|
56
65
|
|
@@ -86,27 +95,31 @@ class QMachineService < Sinatra::Base
|
|
86
95
|
hang_up
|
87
96
|
end
|
88
97
|
|
89
|
-
#
|
98
|
+
# Filter definitions
|
90
99
|
|
91
|
-
|
100
|
+
after do
|
101
|
+
log_to_db unless response.status === 444 or settings.logging == true
|
102
|
+
end
|
103
|
+
|
104
|
+
before '/:version/:box' do
|
92
105
|
# When any request matches the pattern given, this block will execute
|
93
106
|
# before the route that corresponds to its HTTP method. The code here
|
94
107
|
# will validate the request's parameters and store them as instance
|
95
108
|
# variables that will be available to the corresponding route's code.
|
96
|
-
@box, @key, @status = box, params[:key], params[:status]
|
97
|
-
hang_up unless
|
98
|
-
((version == 'box') or (version == 'v1')) and
|
99
|
-
(@
|
100
|
-
(
|
101
|
-
(@status.is_a?(String) and @status.match(/^[\w\-]+$/))) and
|
109
|
+
@box, @key, @status = params[:box], params[:key], params[:status]
|
110
|
+
hang_up unless settings.enable_api_server? and
|
111
|
+
((params[:version] == 'box') or (params[:version] == 'v1')) and
|
112
|
+
(@key.is_a?(String) ^ @status.is_a?(String)) and
|
113
|
+
(@box + @key.to_s + @status.to_s).match(/^[\w\-]+$/) and
|
102
114
|
(request.content_length.to_s.to_i(10) < settings.max_body_size)
|
103
115
|
cross_origin if settings.enable_cors?
|
104
116
|
end
|
105
117
|
|
118
|
+
# Route definitions
|
119
|
+
|
106
120
|
get '/:version/:box' do
|
107
121
|
# This route responds to API calls that "read" from persistent storage,
|
108
122
|
# such as when checking for new tasks to run or downloading results.
|
109
|
-
hang_up unless (@key.is_a?(String) ^ @status.is_a?(String))
|
110
123
|
if @key.is_a?(String) then
|
111
124
|
# This arm runs when a client requests the value of a specific avar.
|
112
125
|
y = get_avar([@box, @key])
|
@@ -120,7 +133,7 @@ class QMachineService < Sinatra::Base
|
|
120
133
|
post '/:version/:box' do
|
121
134
|
# This route responds to API calls that "write" to persistent storage,
|
122
135
|
# such as when uploading results or submitting new tasks.
|
123
|
-
hang_up unless @key.is_a?(String)
|
136
|
+
hang_up unless @key.is_a?(String)
|
124
137
|
body = request.body.read
|
125
138
|
begin
|
126
139
|
x = JSON.parse(body)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: qm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sean Wilkinson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bson_ext
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - '='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: 0.3.2
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: unicorn
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 4.8.3
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 4.8.3
|
97
111
|
description: Ruby port of QMachine web service + in-progress client
|
98
112
|
email: sean@mathbiol.org
|
99
113
|
executables: []
|
@@ -104,10 +118,10 @@ extra_rdoc_files:
|
|
104
118
|
files:
|
105
119
|
- LICENSE
|
106
120
|
- README.md
|
107
|
-
- lib/client.rb
|
108
|
-
- lib/defs-mongo.rb
|
109
121
|
- lib/qm.rb
|
110
|
-
- lib/
|
122
|
+
- lib/qm/client.rb
|
123
|
+
- lib/qm/defs-mongo.rb
|
124
|
+
- lib/qm/service.rb
|
111
125
|
homepage: https://www.qmachine.org
|
112
126
|
licenses:
|
113
127
|
- Apache-2.0
|
data/lib/defs-mongo.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
#- Ruby source code
|
2
|
-
|
3
|
-
#- defs-mongo.rb ~~
|
4
|
-
# ~~ (c) SRW, 16 Jul 2014
|
5
|
-
# ~~ last updated 14 Dec 2014
|
6
|
-
|
7
|
-
require 'json'
|
8
|
-
require 'mongo'
|
9
|
-
require 'sinatra/base'
|
10
|
-
require 'uri'
|
11
|
-
|
12
|
-
module Sinatra
|
13
|
-
|
14
|
-
module MongoConnect
|
15
|
-
|
16
|
-
def mongo_api_connect()
|
17
|
-
# This function needs documentation.
|
18
|
-
db = URI.parse(settings.persistent_storage[:mongo])
|
19
|
-
db_name = db.path.gsub(/^\//, '')
|
20
|
-
conn = Mongo::Connection.new(db.host, db.port).db(db_name)
|
21
|
-
unless db.user.nil? or db.password.nil?
|
22
|
-
conn.authenticate(db.user, db.password)
|
23
|
-
end
|
24
|
-
set api_db: conn
|
25
|
-
settings.api_db['avars'].ensure_index('box_status', {
|
26
|
-
background: true,
|
27
|
-
sparse: true
|
28
|
-
})
|
29
|
-
settings.api_db['avars'].ensure_index('exp_date', {
|
30
|
-
expireAfterSeconds: 0
|
31
|
-
})
|
32
|
-
return
|
33
|
-
end
|
34
|
-
|
35
|
-
def mongo_log_connect()
|
36
|
-
# This function needs documentation.
|
37
|
-
db = URI.parse(settings.trafficlog_storage[:mongo])
|
38
|
-
db_name = db.path.gsub(/^\//, '')
|
39
|
-
conn = Mongo::Connection.new(db.host, db.port).db(db_name)
|
40
|
-
unless db.user.nil? or db.password.nil?
|
41
|
-
conn.authenticate(db.user, db.password)
|
42
|
-
end
|
43
|
-
set log_db: conn, logging: false
|
44
|
-
return
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
|
49
|
-
module MongoAPIDefs
|
50
|
-
|
51
|
-
def get_avar(params)
|
52
|
-
# This helper function needs documentation.
|
53
|
-
db = settings.api_db
|
54
|
-
x = db['avars'].find_and_modify({
|
55
|
-
query: {_id: "#{params[0]}&#{params[1]}"},
|
56
|
-
update: {'$set' => {exp_date: Time.now + settings.avar_ttl}},
|
57
|
-
fields: {body: 1}
|
58
|
-
})
|
59
|
-
y = (x.nil?) ? '{}' : x['body']
|
60
|
-
return y
|
61
|
-
end
|
62
|
-
|
63
|
-
def get_list(params)
|
64
|
-
# This helper function needs documentation.
|
65
|
-
bs, db, x = "#{params[0]}&#{params[1]}", settings.api_db, []
|
66
|
-
db['avars'].find({box_status: bs}).each do |doc|
|
67
|
-
# This block needs documentation.
|
68
|
-
x.push(doc['key'])
|
69
|
-
end
|
70
|
-
y = (x.length == 0) ? '[]' : x.to_json
|
71
|
-
return y
|
72
|
-
end
|
73
|
-
|
74
|
-
def set_avar(params)
|
75
|
-
# This helper function needs documentation.
|
76
|
-
db = settings.api_db
|
77
|
-
doc = {
|
78
|
-
_id: "#{params[0]}&#{params[1]}",
|
79
|
-
body: params[2],
|
80
|
-
exp_date: Time.now + settings.avar_ttl,
|
81
|
-
key: params[1]
|
82
|
-
}
|
83
|
-
options = {upsert: true}#, w: 1}
|
84
|
-
if (params.length == 4) then
|
85
|
-
doc['body'] = params[3]
|
86
|
-
doc['box_status'] = "#{params[0]}&#{params[2]}"
|
87
|
-
end
|
88
|
-
db['avars'].update({_id: doc[:_id]}, doc, options)
|
89
|
-
return
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
module MongoLogDefs
|
95
|
-
|
96
|
-
def log_to_db()
|
97
|
-
# This method needs documentation.
|
98
|
-
settings.log_db['traffic'].insert({
|
99
|
-
host: request.host,
|
100
|
-
ip: request.ip,
|
101
|
-
method: request.request_method,
|
102
|
-
status_code: response.status,
|
103
|
-
timestamp: Time.now,
|
104
|
-
url: request.fullpath
|
105
|
-
})
|
106
|
-
return
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
helpers MongoAPIDefs, MongoLogDefs
|
112
|
-
register MongoConnect
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
#- vim:set syntax=ruby:
|