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 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: