qm 1.1.11 → 1.1.12

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: 4e4b2cd330c69ee8a8d56b14249fb06e9d1b3d2a
4
- data.tar.gz: 00c4657ea4b0dfbc005c6f01203f68392b111b9c
3
+ metadata.gz: c404fd6af1628ffecc1b74c37bb6ea79510a0838
4
+ data.tar.gz: a5ce742f60e5b7234af3019321d8472a1babdeed
5
5
  SHA512:
6
- metadata.gz: 715e30c6223fd2daf8d63f23b973c1f5741692266b0bd17e51fe7e644a9e026d48ab47f7c21690b94a9b2e586e1930c3246d0af72ba9cf464c26e6fb116ffcbf
7
- data.tar.gz: ccc3852764ffdfdd44b7945470fe4237c90127f4d4052eb35a361d30718a3274f7a6a89c2340e1c4f3ba39bf25a9fc32d6e7b171eaf17af695e0ff856d02c388
6
+ metadata.gz: e808c306e2e806c964c5425eeb1925ad9795ab4afaa52b0d54c4528c62353daf506c9637b5f329d9559fc0e6b6aab322ece6b0d2901dc6105c4b0c39ebbe88c2
7
+ data.tar.gz: 1ad66076c0d3b6b516fb71ae9ab15918562add2176eb941d29cd3a981801e900995aac6299b201698d9000efb844b3da84101a5a7f63c456e5e9447178c4fad4
data/README.md CHANGED
@@ -1,15 +1,17 @@
1
1
  # qm
2
2
 
3
3
  The `qm` gem for [Ruby](http://www.ruby-lang.org/) implements both the API
4
- server and web server components of [QMachine](https://www.qmachine.org) (QM),
5
- but currently it is incomplete, especially with regard to configuration.
4
+ server and web server components of [QMachine](https://www.qmachine.org) (QM).
5
+ The gem currently only supports [MongoDB](http://www.mongodb.org/) for
6
+ persistent storage, although the repository contains working definitions for
7
+ [SQLite](https://www.sqlite.org/).
6
8
 
7
9
  Install
8
10
  -------
9
11
 
10
12
  To install the latest release, run
11
13
 
12
- gem install qm
14
+ $ gem install qm
13
15
 
14
16
  ===
15
17
 
data/lib/defs-mongo.rb ADDED
@@ -0,0 +1,84 @@
1
+ #- Ruby source code
2
+
3
+ #- defs-mongo.rb ~~
4
+ # ~~ (c) SRW, 16 Jul 2014
5
+ # ~~ last updated 18 Jul 2014
6
+
7
+ require 'bson'
8
+ require 'json'
9
+ require 'mongo'
10
+ require 'sinatra/base'
11
+ require 'uri'
12
+
13
+ module Sinatra
14
+
15
+ module MongoConnect
16
+
17
+ def mongo_connect()
18
+ # This function needs documentation.
19
+ db = URI.parse(settings.persistent_storage[:mongo])
20
+ db_name = db.path.gsub(/^\//, '')
21
+ conn = Mongo::Connection.new(db.host, db.port).db(db_name)
22
+ unless db.user.nil? or db.password.nil?
23
+ conn.authenticate(db.user, db.password)
24
+ end
25
+ set db: conn
26
+ settings.db['avars'].ensure_index('box_status', {
27
+ background: true,
28
+ sparse: true
29
+ })
30
+ settings.db['avars'].ensure_index('exp_date', {
31
+ expireAfterSeconds: settings.avar_ttl
32
+ })
33
+ return
34
+ end
35
+
36
+ end
37
+
38
+ module MongoDefs
39
+
40
+ def get_avar(params)
41
+ # This helper function needs documentation.
42
+ bk, db = "#{params[0]}&#{params[1]}", settings.db
43
+ x = db['avars'].find_one({_id: bk})
44
+ y = (x.nil?) ? '{}' : x['body']
45
+ return y
46
+ end
47
+
48
+ def get_list(params)
49
+ # This helper function needs documentation.
50
+ bs, db, x = "#{params[0]}&#{params[1]}", settings.db, []
51
+ db['avars'].find({box_status: bs}).each do |doc|
52
+ # This block needs documentation.
53
+ x.push(doc['key'])
54
+ end
55
+ y = (x.length == 0) ? '[]' : x.to_json
56
+ return y
57
+ end
58
+
59
+ def set_avar(params)
60
+ # This helper function needs documentation.
61
+ db = settings.db
62
+ doc = {
63
+ _id: "#{params[0]}&#{params[1]}",
64
+ body: params[2],
65
+ exp_date: Time.now,
66
+ key: params[1]
67
+ }
68
+ options = {upsert: true}#, w: 1}
69
+ if (params.length == 4) then
70
+ doc['body'] = params[3]
71
+ doc['box_status'] = "#{params[0]}&#{params[2]}"
72
+ end
73
+ db['avars'].update({_id: doc[:_id]}, doc, options)
74
+ return
75
+ end
76
+
77
+ end
78
+
79
+ helpers MongoDefs
80
+ register MongoConnect
81
+
82
+ end
83
+
84
+ #- vim:set syntax=ruby:
data/lib/qm.rb CHANGED
@@ -2,34 +2,49 @@
2
2
 
3
3
  #- qm.rb ~~
4
4
  # ~~ (c) SRW, 12 Apr 2013
5
- # ~~ last updated 13 Jul 2014
5
+ # ~~ last updated 18 Jul 2014
6
6
 
7
7
  module QM
8
8
 
9
- private
10
-
11
- class QM_Client
12
-
13
- def initialize
14
- # This function needs documentation.
15
- # ...
16
- end
17
-
18
- end
19
-
20
- public
21
-
22
- def self::launch_client()
9
+ def self::launch_client(options = {})
23
10
  # This function needs documentation.
24
- puts '(placeholder: `launch_client`)';
25
- return;
11
+ puts '(placeholder: `launch_client`)'
12
+ return
26
13
  end
27
14
 
28
- def self::launch_service(*obj)
29
- # This function needs documentation.
30
- require 'api-server.rb'
31
- #puts '(placeholder: `launch_service`)';
32
- return;
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 'service.rb'
19
+ require 'defs-mongo'
20
+ #require 'defs-sqlite'
21
+ app = Sinatra.new(QMachineService) do
22
+ register Sinatra::MongoConnect
23
+ #register Sinatra::SQLiteConnect
24
+ configure do
25
+ convert = lambda do |x|
26
+ # This converts all keys in a hash to symbols recursively.
27
+ if (x.is_a?(Hash)) then
28
+ x = x.inject({}) do |memo, (k, v)|
29
+ memo[k.to_sym] = convert.call(v)
30
+ memo
31
+ end
32
+ end
33
+ return x
34
+ end
35
+ options = convert.call(options)
36
+ set options
37
+ set bind: :hostname, run: false, static: :enable_web_server
38
+ if (settings.persistent_storage.has_key?(:mongo)) then
39
+ helpers Sinatra::MongoDefs
40
+ mongo_connect
41
+ #elsif (settings.persistent_storage.has_key?(:sqlite)) then
42
+ # helpers Sinatra::SQLiteDefs
43
+ # sqlite_connect
44
+ end
45
+ end
46
+ end
47
+ return app.run!
33
48
  end
34
49
 
35
50
  end
data/lib/service.rb ADDED
@@ -0,0 +1,133 @@
1
+ #- Ruby source code
2
+
3
+ #- service.rb ~~
4
+ #
5
+ # This file is derived from the original "teaching version" of QMachine,
6
+ # which used Sinatra and SQLite in a self-contained way. Where that version
7
+ # sought to abbreviate the original Node.js codebase as succinctly as
8
+ # possible, this version attempts to provide a more similar interface and
9
+ # level of configurability. Performance will *never* be a priority in the
10
+ # Ruby port.
11
+ #
12
+ # NOTE: Using a "%" character incorrectly in a URL will cause you great
13
+ # anguish, and there isn't a good way for me to handle this problem "softly"
14
+ # because it is the expected behavior (http://git.io/bmKr2w). Thus, you will
15
+ # tend to see "Bad Request" on your screen if you insist on using "%" as part
16
+ # of a 'box', 'key', or 'status' value.
17
+ #
18
+ # ~~ (c) SRW, 24 Apr 2013
19
+ # ~~ last updated 17 Jul 2014
20
+
21
+ require 'sinatra'
22
+ require 'sinatra/cross_origin'
23
+
24
+ class QMachineService < Sinatra::Base
25
+
26
+ register Sinatra::CrossOrigin
27
+
28
+ configure do
29
+
30
+ # QMachine options
31
+
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
+ persistent_storage: {},
38
+ port: 8177,
39
+ public_folder: 'public'
40
+
41
+ # Sinatra mappings and options needed by QMachine.
42
+
43
+ mime_type webapp: 'application/x-web-app-manifest+json'
44
+ set bind: :hostname, run: false, static: :enable_web_server
45
+
46
+ # See also: http://www.sinatrarb.com/configuration.html
47
+
48
+ end
49
+
50
+ error do
51
+ # This "route" handles errors that occur as part of the server-side code.
52
+ hang_up
53
+ end
54
+
55
+ helpers do
56
+ # This block defines "subfunctions" for use inside the route definitions.
57
+ # The most important ones are the three functions for interacting with
58
+ # persistent storage: `get_avar`, `get_list`, and `set_avar`. Those three
59
+ # functions are not defined here -- they are defined separately in modules
60
+ # that are loaded at runtime by `QM::launch_service`.
61
+
62
+ def hang_up
63
+ # This helper method "hangs up" on a request by sending a nondescript
64
+ # 444 response back to the client, a convention taken from nginx.
65
+ halt [444, {'Content-Type' => 'text/plain'}, ['']]
66
+ end
67
+
68
+ end
69
+
70
+ not_found do
71
+ # This "route" handles requests that didn't match.
72
+ hang_up
73
+ end
74
+
75
+ # Route definitions
76
+
77
+ before '/*/*' do |version, box|
78
+ # When any request matches the pattern given, this block will execute
79
+ # before the route that corresponds to its HTTP method. The code here
80
+ # will validate the request's parameters and store them as instance
81
+ # variables that will be available to the corresponding route's code.
82
+ @box, @key, @status = box, params[:key], params[:status]
83
+ hang_up unless (settings.enable_api_server?) and
84
+ ((version == 'box') or (version == 'v1')) and
85
+ (@box.match(/^[\w\-]+$/)) and
86
+ ((@key.is_a?(String) and @key.match(/^[A-Za-z0-9]+$/)) or
87
+ (@status.is_a?(String) and @status.match(/^[A-Za-z0-9]+$/)))
88
+ cross_origin if settings.enable_CORS?
89
+ end
90
+
91
+ get '/:version/:box' do
92
+ # This route responds to API calls that "read" from persistent storage,
93
+ # such as when checking for new tasks to run or downloading results.
94
+ hang_up unless (@key.is_a?(String) ^ @status.is_a?(String))
95
+ if @key.is_a?(String) then
96
+ # This arm runs when a client requests the value of a specific avar.
97
+ y = get_avar([@box, @key])
98
+ else
99
+ # This arm runs when a client requests a task queue.
100
+ y = get_list([@box, @status])
101
+ end
102
+ return [200, {'Content-Type' => 'application/json'}, [y]]
103
+ end
104
+
105
+ post '/:version/:box' do
106
+ # This route responds to API calls that "write" to persistent storage,
107
+ # such as when uploading results or submitting new tasks.
108
+ hang_up unless @key.is_a?(String) and not @status.is_a?(String)
109
+ body = request.body.read
110
+ x = JSON.parse(body)
111
+ hang_up unless (@box == x['box']) and (@key == x['key'])
112
+ if x['status'].is_a?(String) then
113
+ # This arm runs only when a client writes an avar which represents a
114
+ # task description.
115
+ hang_up unless x['status'].match(/^[A-Za-z0-9]+$/)
116
+ set_avar([@box, @key, x['status'], body])
117
+ else
118
+ # This arm runs when a client is writing a "regular avar".
119
+ set_avar([@box, @key, body])
120
+ end
121
+ return [201, {'Content-Type' => 'text/plain'}, ['']]
122
+ end
123
+
124
+ get '/' do
125
+ # This route enables a static index page to be served from the public
126
+ # folder, if and only if QM's web server has been enabled.
127
+ hang_up unless settings.enable_web_server?
128
+ send_file(File.join(settings.public_folder, 'index.html'))
129
+ end
130
+
131
+ end
132
+
133
+ #- vim:set syntax=ruby:
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.11
4
+ version: 1.1.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Wilkinson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-13 00:00:00.000000000 Z
11
+ date: 2014-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bson
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.10.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.10.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: bson_ext
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 1.10.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 1.10.2
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: json
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -24,6 +52,20 @@ dependencies:
24
52
  - - '='
25
53
  - !ruby/object:Gem::Version
26
54
  version: 1.8.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: mongo
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.10.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.10.2
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: sinatra
29
71
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +81,19 @@ dependencies:
39
81
  - !ruby/object:Gem::Version
40
82
  version: 1.4.5
41
83
  - !ruby/object:Gem::Dependency
42
- name: sqlite3
84
+ name: sinatra-cross_origin
43
85
  requirement: !ruby/object:Gem::Requirement
44
86
  requirements:
45
87
  - - '='
46
88
  - !ruby/object:Gem::Version
47
- version: 1.3.9
89
+ version: 0.3.2
48
90
  type: :runtime
49
91
  prerelease: false
50
92
  version_requirements: !ruby/object:Gem::Requirement
51
93
  requirements:
52
94
  - - '='
53
95
  - !ruby/object:Gem::Version
54
- version: 1.3.9
96
+ version: 0.3.2
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: thin
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +108,7 @@ dependencies:
66
108
  - - '='
67
109
  - !ruby/object:Gem::Version
68
110
  version: 1.6.2
69
- description: This is an incomplete port of the QMachine web service.
111
+ description: This is a port of the QMachine web service.
70
112
  email: sean@mathbiol.org
71
113
  executables: []
72
114
  extensions: []
@@ -76,11 +118,12 @@ extra_rdoc_files:
76
118
  files:
77
119
  - LICENSE
78
120
  - README.md
79
- - lib/api-server.rb
121
+ - lib/defs-mongo.rb
80
122
  - lib/qm.rb
123
+ - lib/service.rb
81
124
  homepage: https://www.qmachine.org
82
125
  licenses:
83
- - Apache 2.0
126
+ - Apache-2.0
84
127
  metadata:
85
128
  issue_tracker: https://github.com/qmachine/qm-ruby/issues
86
129
  post_install_message:
@@ -99,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
142
  version: '0'
100
143
  requirements: []
101
144
  rubyforge_project:
102
- rubygems_version: 2.3.0
145
+ rubygems_version: 2.4.1
103
146
  signing_key:
104
147
  specification_version: 4
105
148
  summary: A platform for World Wide Computing
data/lib/api-server.rb DELETED
@@ -1,198 +0,0 @@
1
- #- Ruby source code / Rack configuration file
2
-
3
- #- api-server.rb ~~
4
- #
5
- # This file is a hacked-up version of the "teaching version" of QMachine,
6
- # and the rest of this introduction reflects that.
7
- #
8
- # This is a self-contained Rack app that uses Sinatra's domain-specific
9
- # language (DSL) in tandem with SQLite to implement a teaching version of
10
- # QMachine. The idea here is to pack most of the functionality of the
11
- # original Node.js codebase into a single file that reads like pseudo-code.
12
- #
13
- # Of course, there are some caveats. This version succeeds in abbreviating
14
- # the original codebase, but it doesn't support all of the original options
15
- # yet. The code can also be hard to modify if you're unfamiliar with Sinatra,
16
- # because Ruby's scoping rules are very different from JavaScript's, and
17
- # Sinatra's DSL makes things even "worse", to be honest. My advice here is,
18
- # don't think too hard about it. Just enjoy it.
19
- #
20
- # I do plan to merge this program with the Ruby gem in the future, which is
21
- # why the database schema matches the Node.js implementation's (which is not
22
- # as straight-forward as it could be). For now, it serves its purpose, and it
23
- # does so with just 95 lines of source code ;-)
24
- #
25
- # NOTE: Using a "%" character incorrectly in a URL will cause you great
26
- # anguish, and there isn't a good way for me to handle this problem "softly"
27
- # because it is the expected behavior (http://git.io/bmKr2w). Thus, you will
28
- # tend to see "Bad Request" on your screen if you insist on using "%" as part
29
- # of a 'box', 'key', or 'status' value.
30
- #
31
- # ~~ (c) SRW, 24 Apr 2013
32
- # ~~ last updated 13 Jul 2014
33
-
34
- require 'json'
35
- require 'sinatra'
36
- #require 'sinatra/cross_origin'
37
- require 'sqlite3'
38
-
39
- class QMachineService < Sinatra::Base
40
-
41
- configure do
42
-
43
- # QMachine options
44
-
45
- set avar_ttl: 86400, # seconds
46
- enable_api_server: true,
47
- enable_CORS: true,
48
- enable_web_server: true,
49
- hostname: '0.0.0.0',
50
- persistent_storage: 'qm.db',
51
- port: ENV['PORT'] || 8177,
52
- public_folder: 'public'
53
-
54
- # Sinatra mappings and options needed by QMachine -- leave these alone ;-)
55
-
56
- mime_type webapp: 'application/x-web-app-manifest+json'
57
- set bind: :hostname, run: false, static: :enable_web_server
58
-
59
- # See also: http://www.sinatrarb.com/configuration.html
60
-
61
- end
62
-
63
- error do
64
- # This "route" handles errors that occur as part of the server-side code.
65
- hang_up
66
- end
67
-
68
- helpers do
69
- # This block defines subfunctions for use inside the route definitions.
70
-
71
- def sqlite(query)
72
- # This helper method helps DRY out the code for database queries, and
73
- # it does so in an incredibly robust and inefficient way -- by
74
- # creating the table and evicting expired rows before every single
75
- # query. A caveat, of course, is that the special ":memory:" database
76
- # doesn't work correctly, but ":memory:" isn't *persistent* storage
77
- # anyway. Also, I have omitted indexing on `box_status` for obvious
78
- # reasons :-P
79
- begin
80
- db = SQLite3::Database.open(settings.persistent_storage)
81
- db.execute_batch <<-sql
82
- CREATE TABLE IF NOT EXISTS avars (
83
- body TEXT NOT NULL,
84
- box_key TEXT NOT NULL PRIMARY KEY,
85
- box_status TEXT,
86
- exp_date INTEGER NOT NULL,
87
- key TEXT
88
- );
89
- DELETE FROM avars WHERE (exp_date < #{now_plus(0)})
90
- sql
91
- # We have to execute the query code `query` separately because
92
- # the `db.execute_batch` function always returns `nil`, which
93
- # prevents us from being able to retrieve the results of the
94
- # query.
95
- x = db.execute(query)
96
- rescue SQLite3::Exception => err
97
- puts "Exception occurred: #{err}"
98
- ensure
99
- db.close if db
100
- end
101
- return x
102
- end
103
-
104
- def hang_up
105
- # This helper method "hangs up" on a request by sending a nondescript
106
- # 444 response back to the client, a convention taken from nginx.
107
- halt [444, {'Content-Type' => 'text/plain'}, ['']]
108
- end
109
-
110
- def now_plus(dt)
111
- # This helper method computes a date (in milliseconds) that is
112
- # specified by an offset `dt` (in seconds).
113
- return (1000 * (Time.now.to_f + dt)).to_i
114
- end
115
-
116
- end
117
-
118
- not_found do
119
- # This "route" handles requests that didn't match.
120
- hang_up
121
- end
122
-
123
- if settings.enable_api_server? then
124
-
125
- # Here, we set up "routes" to handle incoming GET and POST requests.
126
-
127
- before '/*/*' do |version, box|
128
- # When any request matches the pattern given, this block will execute
129
- # before the route that corresponds to its HTTP method. The code here
130
- # will validate the request's parameters and store them as instance
131
- # variables that will be available to the corresponding route's code.
132
- @box, @key, @status = box, params[:key], params[:status]
133
- hang_up unless ((version == 'box') or (version == 'v1')) and
134
- (@box.match(/^[\w\-]+$/)) and
135
- ((@key.is_a?(String) and @key.match(/^[A-Za-z0-9]+$/)) or
136
- (@status.is_a?(String) and @status.match(/^[A-Za-z0-9]+$/)))
137
- #cross_origin if settings.enable_CORS?
138
- end
139
-
140
- get '/:version/:box' do
141
- # This route responds to API calls that "read" from persistent
142
- # storage, such as when checking for new tasks to run or downloading
143
- # results.
144
- hang_up unless (@key.is_a?(String) ^ @status.is_a?(String))
145
- bk, bs = "#{@box}&#{@key}", "#{@box}&#{@status}"
146
- if @key.is_a?(String) then
147
- # This arm runs when a client requests the value of a specific
148
- # avar.
149
- x = sqlite("SELECT body FROM avars WHERE box_key = '#{bk}'")
150
- y = (x.length == 0) ? '{}' : x[0][0]
151
- else
152
- # This arm runs when a client requests a task queue.
153
- x = sqlite("SELECT key FROM avars WHERE box_status = '#{bs}'")
154
- y = (x.length == 0) ? '[]' : (x.map {|row| row[0]}).to_json
155
- end
156
- return [200, {'Content-Type' => 'application/json'}, [y]]
157
- end
158
-
159
- post '/:version/:box' do
160
- # This route responds to API calls that "write" to persistent
161
- # storage, such as when uploading results or submitting new tasks.
162
- hang_up unless @key.is_a?(String) and not @status.is_a?(String)
163
- body, ed = request.body.read, now_plus(settings.avar_ttl)
164
- x = JSON.parse(body)
165
- hang_up unless (@box == x['box']) and (@key == x['key'])
166
- bk, bs = "#{@box}&#{@key}", "#{@box}&#{x['status']}"
167
- if x['status'].is_a?(String) then
168
- # This arm runs only when a client writes an avar which
169
- # represents a task description.
170
- hang_up unless x['status'].match(/^[A-Za-z0-9]+$/)
171
- sqlite("INSERT OR REPLACE INTO avars
172
- (body, box_key, box_status, exp_date, key)
173
- VALUES ('#{body}', '#{bk}', '#{bs}', #{ed}, '#{@key}')")
174
- else
175
- # This arm runs when a client is writing a "regular avar".
176
- sqlite("INSERT OR REPLACE INTO avars (body, box_key, exp_date)
177
- VALUES ('#{body}', '#{bk}', #{ed})")
178
- end
179
- return [201, {'Content-Type' => 'text/plain'}, ['']]
180
- end
181
-
182
- end
183
-
184
- if settings.enable_web_server? then
185
-
186
- get '/' do
187
- # This route enables a static index page to be served from the public
188
- # folder, if and only if QM's web server has been enabled.
189
- send_file(File.join(settings.public_folder, 'index.html'))
190
- end
191
-
192
- end
193
-
194
- end
195
-
196
- QMachineService.run!
197
-
198
- #- vim:set syntax=ruby: