david 0.3.0 → 0.4.0

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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +2 -2
  4. data/Gemfile +8 -2
  5. data/Gemfile.lock +84 -44
  6. data/README.md +87 -5
  7. data/benchmarks/Gemfile +1 -0
  8. data/benchmarks/Gemfile.lock +3 -1
  9. data/benchmarks/coapbench.sh +20 -0
  10. data/benchmarks/quick.sh +2 -0
  11. data/benchmarks/rackup/Gemfile +10 -0
  12. data/benchmarks/rackup/Gemfile.lock +159 -0
  13. data/benchmarks/rackup/grape.ru +18 -0
  14. data/benchmarks/rackup/rack.ru +7 -0
  15. data/benchmarks/rackup/rails.ru +14 -0
  16. data/benchmarks/rps.rb +14 -2
  17. data/benchmarks/stress.sh +17 -0
  18. data/david.gemspec +0 -3
  19. data/experiments/Gemfile +6 -0
  20. data/experiments/concurrency/Gemfile +3 -0
  21. data/experiments/concurrency/stub.rb +88 -0
  22. data/experiments/hash_key.rb +64 -0
  23. data/experiments/string_concat.rb +21 -0
  24. data/experiments/symbol_to_proc.rb +15 -0
  25. data/experiments/thread_safe.rb +40 -0
  26. data/lib/david.rb +8 -4
  27. data/lib/david/actor.rb +1 -11
  28. data/lib/david/app_config.rb +112 -0
  29. data/lib/david/exchange.rb +124 -0
  30. data/lib/david/fake_logger.rb +11 -0
  31. data/lib/david/garbage_collector.rb +9 -17
  32. data/lib/david/guerilla/rack/utils.rb +18 -0
  33. data/lib/david/interop.rb +4 -0
  34. data/lib/david/interop/mandatory_etsi.rb +4 -0
  35. data/lib/david/interop/mandatory_etsi/grape.rb +37 -0
  36. data/lib/david/interop/mandatory_etsi/hobbit.rb +30 -0
  37. data/lib/david/interop/mandatory_etsi/nyny.rb +36 -0
  38. data/lib/david/interop/mandatory_etsi/rack.rb +26 -0
  39. data/lib/david/interop/mandatory_etsi/sinatra.rb +36 -0
  40. data/lib/david/observe.rb +24 -29
  41. data/lib/david/rails/action_controller/base.rb +9 -7
  42. data/lib/david/railties/config.rb +4 -4
  43. data/lib/david/registry.rb +22 -0
  44. data/lib/david/server.rb +56 -56
  45. data/lib/david/server/constants.rb +1 -0
  46. data/lib/david/server/mapping.rb +43 -11
  47. data/lib/david/server/mid_cache.rb +29 -0
  48. data/lib/david/server/multicast.rb +7 -5
  49. data/lib/david/server/respond.rb +53 -43
  50. data/lib/david/server/utility.rb +2 -1
  51. data/lib/david/show_exceptions.rb +12 -8
  52. data/lib/david/transmitter.rb +44 -0
  53. data/lib/david/trap.rb +10 -0
  54. data/lib/david/version.rb +1 -1
  55. data/lib/rack/handler/david.rb +6 -10
  56. data/lib/rack/hello_world.rb +25 -0
  57. data/spec/app_config_spec.rb +56 -0
  58. data/spec/dummy/app/controllers/etsis_controller.rb +26 -0
  59. data/spec/dummy/app/controllers/tests_controller.rb +9 -0
  60. data/spec/dummy/config/application.rb +4 -6
  61. data/spec/dummy/config/environments/development.rb +2 -2
  62. data/spec/dummy/config/environments/test.rb +2 -2
  63. data/spec/dummy/config/routes.rb +13 -53
  64. data/spec/interop/mandatory_spec.rb +100 -0
  65. data/spec/observe_spec.rb +8 -7
  66. data/spec/resource_discovery_spec.rb +3 -3
  67. data/spec/server_spec.rb +60 -15
  68. data/spec/spec_helper.rb +21 -2
  69. metadata +40 -33
  70. data/lib/david/request.rb +0 -80
  71. data/lib/david/server/deduplication.rb +0 -21
  72. data/lib/david/server/options.rb +0 -79
data/spec/observe_spec.rb CHANGED
@@ -7,19 +7,20 @@ describe Observe do
7
7
 
8
8
  # TODO Replace this with factory.
9
9
  before do
10
- [:@request1, :@request2].each do |var|
10
+ [:@exchange1, :@exchange2].each do |var|
11
+ mid = SecureRandom.random_number(0xffff)
11
12
  token = SecureRandom.random_number(0xff)
12
13
  options = { uri_path: [], token: token }
13
14
 
14
- message = CoAP::Message.new(:con, :get, nil, '', options)
15
- request = Request.new('127.0.0.1', CoAP::PORT, message)
15
+ message = CoAP::Message.new(:con, :get, mid, '', options)
16
+ exchange = Exchange.new('127.0.0.1', CoAP::PORT, message)
16
17
 
17
- instance_variable_set(var, request)
18
+ instance_variable_set(var, exchange)
18
19
  end
19
20
  end
20
21
 
21
- let(:dummy1) { [@request1, {'PATH_INFO' => '/'}, '1'] }
22
- let(:dummy2) { [@request2, {'PATH_INFO' => '/'}, '1'] }
22
+ let(:dummy1) { [@exchange1, {'PATH_INFO' => '/'}, '1'] }
23
+ let(:dummy2) { [@exchange2, {'PATH_INFO' => '/'}, '1'] }
23
24
 
24
25
  subject { Celluloid::Actor[:observe] }
25
26
 
@@ -36,7 +37,7 @@ describe Observe do
36
37
  end
37
38
  end
38
39
 
39
- # [n, request, env, etag, timestamp]
40
+ # [n, exchange, env, etag, timestamp]
40
41
  context 'value' do
41
42
  let!(:time) { Time.now.to_i }
42
43
 
@@ -8,7 +8,7 @@ describe David::ResourceDiscovery do
8
8
  end
9
9
 
10
10
  let!(:server) do
11
- supervised_server(:Port => port, :Log => debug, :app => Dummy::Application)
11
+ supervised_server(:Port => port, :Log => debug, :app => Rails.application)
12
12
  end
13
13
 
14
14
  context 'ordinary request' do
@@ -25,11 +25,11 @@ describe David::ResourceDiscovery do
25
25
  end
26
26
 
27
27
  it 'CoRE::Link' do
28
- expect(links.size).to eq(4)
28
+ expect(links.size).to eq(9)
29
29
  expect(links.map(&:uri).uniq.size).to eq(links.size)
30
30
 
31
31
  links.each do |link|
32
- expect(link.uri).to match(/^\/things/)
32
+ expect(link.uri).to match(/^\/(cbor|hello|query|seg.*|test|things)/)
33
33
  end
34
34
  end
35
35
  end
data/spec/server_spec.rb CHANGED
@@ -273,21 +273,6 @@ describe Server do
273
273
  end
274
274
  end
275
275
 
276
- context 'options' do
277
- describe 'default_to_true' do
278
- let(:method) do
279
- ->(*args) { Server::Options.send(:default_to_true, *args) }
280
- end
281
-
282
- it { expect(method.call(:block, nil)).to eq(true) }
283
- it { expect(method.call(:block, true)).to eq(true) }
284
- it { expect(method.call(:block, 'true')).to eq(true) }
285
-
286
- it { expect(method.call(:block, false)).to eq(false) }
287
- it { expect(method.call(:block, 'false')).to eq(false) }
288
- end
289
- end
290
-
291
276
  context 'proxy' do
292
277
  subject { client.get('/', '::1', nil, nil, proxy_uri: 'coap://[::1]/') }
293
278
 
@@ -300,6 +285,66 @@ describe Server do
300
285
  end
301
286
  end
302
287
 
288
+ context 'transcoding' do
289
+ let!(:server) { supervised_server(:Port => port, :CBOR => true) }
290
+
291
+ let(:cbor) { {'Hello' => 'World!'}.to_cbor }
292
+
293
+ subject { client.get('/cbor', '::1', nil, cbor, content_format: 60) }
294
+
295
+ context 'incoming' do
296
+ context 'string key' do
297
+ it 'should return text' do
298
+ expect(subject).to be_a(CoAP::Message)
299
+ expect(subject.ver).to eq(1)
300
+ expect(subject.tt).to eq(:ack)
301
+ expect(subject.mcode).to eq([2, 5])
302
+ expect(subject.payload).to eq('{"Hello"=>"World!"}{"Hello"=>"World!"}')
303
+ end
304
+ end
305
+
306
+ context 'int key' do
307
+ let(:cbor) { {1 => 2}.to_cbor }
308
+
309
+ it 'should return text' do
310
+ expect(subject).to be_a(CoAP::Message)
311
+ expect(subject.ver).to eq(1)
312
+ expect(subject.tt).to eq(:ack)
313
+ expect(subject.mcode).to eq([2, 5])
314
+ expect(subject.payload).to eq('{"1"=>2}{1=>2}')
315
+ end
316
+ end
317
+
318
+ context 'rails' do
319
+ let!(:server) do
320
+ supervised_server(:Port => port, :Log => debug, :CBOR => true,
321
+ :app => Rails.application)
322
+ end
323
+
324
+ it 'should return text' do
325
+ expect(subject).to be_a(CoAP::Message)
326
+ expect(subject.ver).to eq(1)
327
+ expect(subject.tt).to eq(:ack)
328
+ expect(subject.mcode).to eq([2, 5])
329
+ expect(subject.payload).to eq('{"Hello"=>"World!"}')
330
+ end
331
+ end
332
+ end
333
+
334
+ context 'outgoing' do
335
+ subject { client.get('/json', '::1') }
336
+
337
+ it 'should return CBOR' do
338
+ expect(subject).to be_a(CoAP::Message)
339
+ expect(subject.ver).to eq(1)
340
+ expect(subject.tt).to eq(:ack)
341
+ expect(subject.mcode).to eq([2, 5])
342
+ expect(CBOR.load(subject.payload)).to eq({'Hello' => 'World!'})
343
+ expect(subject.options[:content_format]).to eq(60)
344
+ end
345
+ end
346
+ end
347
+
303
348
  after do
304
349
  server.terminate
305
350
  end
data/spec/spec_helper.rb CHANGED
@@ -6,13 +6,14 @@ SimpleCov.start { add_filter 'spec/dummy' }
6
6
  # Rails
7
7
  ENV['RAILS_ENV'] ||= 'test'
8
8
 
9
- require File.expand_path("../dummy/config/environment.rb", __FILE__)
9
+ require File.expand_path("../dummy/config/environment", __FILE__)
10
10
  require 'rspec/rails'
11
11
 
12
12
  # David
13
13
  $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
14
14
 
15
15
  require 'david'
16
+ require 'david/interop'
16
17
 
17
18
  module David
18
19
  module TestHelper
@@ -24,6 +25,21 @@ module David
24
25
  rand((2**10+1)..(2**16-1))
25
26
  end
26
27
 
28
+ def req(method, path, options = {})
29
+ mid = rand(0xffff) unless respond_to?(:mid)
30
+ port = random_port unless respond_to?(:port)
31
+
32
+ payload = options.delete(:payload)
33
+ options.merge!(mid: mid)
34
+
35
+ client = CoAP::Client.new(retransmit: false, recv_timeout: 0.1,
36
+ token: false)
37
+
38
+ response = client.send(method, path, '::1', nil, payload, options)
39
+
40
+ [mid, response]
41
+ end
42
+
27
43
  def supervised_server(options)
28
44
  defaults = {
29
45
  :Host => '::1',
@@ -35,7 +51,10 @@ module David
35
51
 
36
52
  app = options.delete(:app) || Rack::HelloWorld
37
53
 
38
- David::Server.supervise_as(:david, app, defaults.merge(options))
54
+ server = David::Server.new(app, defaults.merge(options))
55
+ server.async.run
56
+
57
+ server
39
58
  end
40
59
  end
41
60
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: david
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - henning mueller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-20 00:00:00.000000000 Z
11
+ date: 2015-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid-io
@@ -86,34 +86,6 @@ dependencies:
86
86
  version: '3.1'
87
87
  prerelease: false
88
88
  type: :development
89
- - !ruby/object:Gem::Dependency
90
- name: rspec-rails
91
- version_requirements: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - ~>
94
- - !ruby/object:Gem::Version
95
- version: '3.1'
96
- requirement: !ruby/object:Gem::Requirement
97
- requirements:
98
- - - ~>
99
- - !ruby/object:Gem::Version
100
- version: '3.1'
101
- prerelease: false
102
- type: :development
103
- - !ruby/object:Gem::Dependency
104
- name: rails
105
- version_requirements: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - ~>
108
- - !ruby/object:Gem::Version
109
- version: '4.2'
110
- requirement: !ruby/object:Gem::Requirement
111
- requirements:
112
- - - ~>
113
- - !ruby/object:Gem::Version
114
- version: '4.2'
115
- prerelease: false
116
- type: :development
117
89
  description: |-
118
90
  David is a CoAP server with Rack interface to bring the
119
91
  illustrious family of Rack compatible web frameworks into the Internet of
@@ -134,43 +106,73 @@ files:
134
106
  - TODO.md
135
107
  - benchmarks/Gemfile
136
108
  - benchmarks/Gemfile.lock
109
+ - benchmarks/coapbench.sh
110
+ - benchmarks/quick.sh
111
+ - benchmarks/rackup/Gemfile
112
+ - benchmarks/rackup/Gemfile.lock
113
+ - benchmarks/rackup/grape.ru
114
+ - benchmarks/rackup/rack.ru
115
+ - benchmarks/rackup/rails.ru
137
116
  - benchmarks/rps.rb
117
+ - benchmarks/stress.sh
138
118
  - bin/david
139
119
  - config.ru
140
120
  - david.gemspec
121
+ - experiments/Gemfile
122
+ - experiments/concurrency/Gemfile
123
+ - experiments/concurrency/stub.rb
124
+ - experiments/hash_key.rb
141
125
  - experiments/mcast.rb
126
+ - experiments/string_concat.rb
142
127
  - experiments/structs.rb
128
+ - experiments/symbol_to_proc.rb
143
129
  - experiments/test.rb
130
+ - experiments/thread_safe.rb
144
131
  - lib/david.rb
145
132
  - lib/david/actor.rb
133
+ - lib/david/app_config.rb
134
+ - lib/david/exchange.rb
135
+ - lib/david/fake_logger.rb
146
136
  - lib/david/garbage_collector.rb
147
137
  - lib/david/guerilla/rack/handler.rb
138
+ - lib/david/guerilla/rack/utils.rb
139
+ - lib/david/interop.rb
140
+ - lib/david/interop/mandatory_etsi.rb
141
+ - lib/david/interop/mandatory_etsi/grape.rb
142
+ - lib/david/interop/mandatory_etsi/hobbit.rb
143
+ - lib/david/interop/mandatory_etsi/nyny.rb
144
+ - lib/david/interop/mandatory_etsi/rack.rb
145
+ - lib/david/interop/mandatory_etsi/sinatra.rb
148
146
  - lib/david/observe.rb
149
147
  - lib/david/rails/action_controller/base.rb
150
148
  - lib/david/railties/config.rb
151
149
  - lib/david/railties/middleware.rb
152
- - lib/david/request.rb
150
+ - lib/david/registry.rb
153
151
  - lib/david/resource_discovery.rb
154
152
  - lib/david/resource_discovery_proxy.rb
155
153
  - lib/david/server.rb
156
154
  - lib/david/server/constants.rb
157
- - lib/david/server/deduplication.rb
158
155
  - lib/david/server/mapping.rb
156
+ - lib/david/server/mid_cache.rb
159
157
  - lib/david/server/multicast.rb
160
- - lib/david/server/options.rb
161
158
  - lib/david/server/respond.rb
162
159
  - lib/david/server/utility.rb
163
160
  - lib/david/show_exceptions.rb
161
+ - lib/david/transmitter.rb
162
+ - lib/david/trap.rb
164
163
  - lib/david/version.rb
165
164
  - lib/rack/handler/coap.rb
166
165
  - lib/rack/handler/david.rb
167
166
  - lib/rack/hello_world.rb
167
+ - spec/app_config_spec.rb
168
168
  - spec/dummy/Rakefile
169
169
  - spec/dummy/app/assets/images/.keep
170
170
  - spec/dummy/app/assets/javascripts/application.js
171
171
  - spec/dummy/app/assets/stylesheets/application.css
172
172
  - spec/dummy/app/controllers/application_controller.rb
173
173
  - spec/dummy/app/controllers/concerns/.keep
174
+ - spec/dummy/app/controllers/etsis_controller.rb
175
+ - spec/dummy/app/controllers/tests_controller.rb
174
176
  - spec/dummy/app/helpers/application_helper.rb
175
177
  - spec/dummy/app/mailers/.keep
176
178
  - spec/dummy/app/models/.keep
@@ -206,6 +208,7 @@ files:
206
208
  - spec/dummy/public/500.html
207
209
  - spec/dummy/public/favicon.ico
208
210
  - spec/guerilla_rack_handler_spec.rb
211
+ - spec/interop/mandatory_spec.rb
209
212
  - spec/mapping_spec.rb
210
213
  - spec/observe_spec.rb
211
214
  - spec/perf/server_perf_spec.rb
@@ -238,12 +241,15 @@ signing_key:
238
241
  specification_version: 4
239
242
  summary: CoAP server with Rack interface.
240
243
  test_files:
244
+ - spec/app_config_spec.rb
241
245
  - spec/dummy/Rakefile
242
246
  - spec/dummy/app/assets/images/.keep
243
247
  - spec/dummy/app/assets/javascripts/application.js
244
248
  - spec/dummy/app/assets/stylesheets/application.css
245
249
  - spec/dummy/app/controllers/application_controller.rb
246
250
  - spec/dummy/app/controllers/concerns/.keep
251
+ - spec/dummy/app/controllers/etsis_controller.rb
252
+ - spec/dummy/app/controllers/tests_controller.rb
247
253
  - spec/dummy/app/helpers/application_helper.rb
248
254
  - spec/dummy/app/mailers/.keep
249
255
  - spec/dummy/app/models/.keep
@@ -279,6 +285,7 @@ test_files:
279
285
  - spec/dummy/public/500.html
280
286
  - spec/dummy/public/favicon.ico
281
287
  - spec/guerilla_rack_handler_spec.rb
288
+ - spec/interop/mandatory_spec.rb
282
289
  - spec/mapping_spec.rb
283
290
  - spec/observe_spec.rb
284
291
  - spec/perf/server_perf_spec.rb
data/lib/david/request.rb DELETED
@@ -1,80 +0,0 @@
1
- class Request < Struct.new(:host, :port, :message, :ancillary, :options)
2
- def accept
3
- message.options[:accept]
4
- end
5
-
6
- def block
7
- @block ||= if message.options[:block2].nil?
8
- CoAP::Block.new(0, false, 1024)
9
- else
10
- CoAP::Block.new(message.options[:block2]).decode
11
- end
12
- end
13
-
14
- def con?
15
- message.tt == :con
16
- end
17
-
18
- def delete?
19
- message.mcode == :delete
20
- end
21
-
22
- def etag
23
- message.options[:etag]
24
- end
25
-
26
- def get_etag?
27
- message.options[:etag].nil? && get?
28
- end
29
-
30
- def get?
31
- message.mcode == :get
32
- end
33
-
34
- def idempotent?
35
- get? || put? || delete?
36
- end
37
-
38
- def mid
39
- message.mid
40
- end
41
-
42
- def multicast?
43
- a = ancillary
44
- return false if a.nil?
45
-
46
- return @multicast unless @multicast.nil?
47
-
48
- @multicast =
49
- a.cmsg_is?(:IP, :PKTINFO) && a.ip_pktinfo[0].ipv4_multicast? ||
50
- a.cmsg_is?(:IPV6, :PKTINFO) && a.ipv6_pktinfo[0].ipv6_multicast?
51
- end
52
-
53
- def non?
54
- message.tt == :non
55
- end
56
-
57
- def observe?
58
- !message.options[:observe].nil?
59
- end
60
-
61
- def post?
62
- message.mcode == :post
63
- end
64
-
65
- def proxy?
66
- !(message.options[:proxy_uri].nil? && message.options[:proxy_scheme].nil?)
67
- end
68
-
69
- def put?
70
- message.mcode == :put
71
- end
72
-
73
- def token
74
- message.options[:token]
75
- end
76
-
77
- def valid_method?
78
- CoAP::METHODS.include?(message.mcode)
79
- end
80
- end
@@ -1,21 +0,0 @@
1
- module David
2
- module Deduplication
3
- def self.included(base)
4
- attr_reader :dedup_cache
5
- end
6
-
7
- def cache_response(request, response)
8
- return if duplicate?(request)
9
- @dedup_cache[[request.host, request.mid]] = [response, Time.now.to_i]
10
- end
11
-
12
- def cached_response(request)
13
- response = @dedup_cache[[request.host, request.mid]]
14
- [response[0], response[0].options] if response
15
- end
16
-
17
- def duplicate?(request)
18
- return !!cached_response(request)
19
- end
20
- end
21
- end