qm 1.2.2 → 1.2.3
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 +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:
|