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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da264638d70859692298a689d2a92d025733719f
4
- data.tar.gz: 10ed26e4b45118477d7b48ac2adc611e9e4a3093
3
+ metadata.gz: 0aed10f6857450ae540fea58ff7d244cbd25fe2c
4
+ data.tar.gz: 00aca546287a88a5f110039f63a82f6b53df2e37
5
5
  SHA512:
6
- metadata.gz: fef5c587e41035dbaa90bb16a1320f3f41b7ab9f306fb454ae5bb662b7ca5f8a5fbd83b275767e58484a9167fafbbf7afd8c727513b96dff3257cda93eefd374
7
- data.tar.gz: 3b43abf641787cc89a3730899c1ce44ef665d6b597079190b871d35545f0665ac9f90491f18a029d77fb4a5c0736a43a848a0d08ce4c566ff2bf611b5b0f6fda
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 07 Dec 2014
5
+ # ~~ last updated 23 Jan 2015
6
6
 
7
7
  module QM
8
8
 
9
- def self::launch_client(options = {mothership: 'https://api.qmachine.org'})
10
- # This function needs documentation.
11
- require 'client'
12
- return QMachineClient.new(options)
13
- end
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.run!
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 12 Jan 2015
19
+ # ~~ last updated 23 Jan 2015
20
20
 
21
- require 'sinatra'
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: 86400, # seconds
33
- enable_api_server: false,
34
- enable_cors: false,
35
- enable_web_server: false,
36
- hostname: '0.0.0.0',
37
- max_body_size: 1048576, # 1024 * 1024 = 1 MB
38
- persistent_storage: {},
39
- port: 8177,
40
- public_folder: 'public',
41
- trafficlog_storage: {}
42
-
43
- # Sinatra mappings and options needed by QMachine.
44
-
45
- mime_type :webapp, 'application/x-web-app-manifest+json'
46
-
47
- set bind: lambda { settings.hostname },
48
- logging: true,
49
- raise_errors: false,
50
- run: false,
51
- show_exceptions: false,
52
- static: lambda { settings.enable_web_server },
53
- x_cascade: false
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
- # Route definitions
98
+ # Filter definitions
90
99
 
91
- before '/*/*' do |version, box|
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 (settings.enable_api_server?) and
98
- ((version == 'box') or (version == 'v1')) and
99
- (@box.match(/^[\w\-]+$/)) and
100
- ((@key.is_a?(String) and @key.match(/^[\w\-]+$/)) or
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) and not @status.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.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-12 00:00:00.000000000 Z
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/service.rb
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
@@ -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: