david 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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