ruby_home 0.1.5 → 0.1.7

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +64 -5
  3. data/bin/rubyhome +4 -4
  4. data/lib/ruby_home/accessory_info.rb +45 -30
  5. data/lib/ruby_home/factories/characteristic_factory.rb +27 -19
  6. data/lib/ruby_home/factories/default_values/float_value.rb +1 -1
  7. data/lib/ruby_home/factories/service_factory.rb +89 -0
  8. data/lib/ruby_home/factories/templates/characteristic_template.rb +6 -2
  9. data/lib/ruby_home/hap/accessory.rb +24 -3
  10. data/lib/ruby_home/hap/accessory_collection.rb +38 -0
  11. data/lib/ruby_home/hap/characteristic.rb +25 -19
  12. data/lib/ruby_home/hap/crypto/session_key.rb +31 -0
  13. data/lib/ruby_home/hap/ev_response.rb +64 -0
  14. data/lib/ruby_home/{http → hap}/hap_request.rb +12 -5
  15. data/lib/ruby_home/{http → hap}/hap_response.rb +7 -4
  16. data/lib/ruby_home/hap/server.rb +81 -0
  17. data/lib/ruby_home/hap/service.rb +11 -15
  18. data/lib/ruby_home/http/application.rb +17 -22
  19. data/lib/ruby_home/http/controllers/application_controller.rb +8 -4
  20. data/lib/ruby_home/http/controllers/characteristics_controller.rb +19 -4
  21. data/lib/ruby_home/http/controllers/pair_verifies_controller.rb +3 -5
  22. data/lib/ruby_home/http/serializers/object_serializer.rb +1 -1
  23. data/lib/ruby_home/http/services/socket_notifier.rb +40 -0
  24. data/lib/ruby_home/http/services/start_srp_service.rb +36 -34
  25. data/lib/ruby_home/http/services/verify_srp_service.rb +55 -53
  26. data/lib/ruby_home/identifier_cache.rb +22 -49
  27. data/lib/ruby_home/persistable.rb +36 -0
  28. data/lib/ruby_home/version.rb +1 -1
  29. data/lib/ruby_home.rb +14 -5
  30. data/rubyhome.gemspec +3 -3
  31. metadata +35 -38
  32. data/lib/ruby_home/factories/accessory_factory.rb +0 -73
  33. data/lib/ruby_home/http/hap_server.rb +0 -60
  34. data/lib/ruby_home/rack/handler/hap_server.rb +0 -21
  35. data/lib/ruby_home/yaml_record.rb +0 -440
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf4e167745548086679350014c0375cf64eeb8733b9e6948ef0846ea36fd4f11
4
- data.tar.gz: d8583372ac979eceafcd3c6a1cf36f8f40c32d5ab543ff28b7cf03e11e294d9b
3
+ metadata.gz: b7f5f53b947e2cfbce79204572dd8d29b284c5434304aee7214b6a7a33d3e0a6
4
+ data.tar.gz: '086845819574df45f838c8ff67979f55f01763b6fe44114af76fd3479f8f1b83'
5
5
  SHA512:
6
- metadata.gz: 84a6186ceb1d259b60bfe877ee3e12c78c4d9a25cb3fc9433605c45264a3bc174796650bb87e95795f8c39ea6dd365bc22425c6360636e07923f731cacaf185d
7
- data.tar.gz: 19899a408055f4dd74993b03679cee97ea4d440b09beccbf6aaf4d034db727a96d09a73fc85ddb85f3fc4326704782ec861f9e006149a05c9e6c00c57123513d
6
+ metadata.gz: 419df1283d71010c0a4e8e89f60f01fa752ea9366f6fe59a1ca3a2e202a9ab72361ed4dff5389ecdfb8b084feb40cd0d5c62fcbf16b90b65bfcd5096c7a3a4ab
7
+ data.tar.gz: 3644d107b711edadd639f881614ebd85cb8e164cbeebf5db30e1748303983b52bf056371e952a6c9c0e39aa2a7744351549ddaf2eef4c655428dabdf0c9fe2eb
data/README.md CHANGED
@@ -21,18 +21,18 @@ Or install it yourself as:
21
21
 
22
22
  $ gem install ruby_home
23
23
 
24
- ## Usage
24
+ ## Basic Usage
25
25
 
26
26
  Create a fan with an on/off switch.
27
27
 
28
28
  ```ruby
29
29
  require 'ruby_home'
30
30
 
31
- accessory_information = RubyHome::AccessoryFactory.create(:accessory_information)
32
- fan = RubyHome::AccessoryFactory.create(:fan)
31
+ accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
32
+ fan = RubyHome::ServiceFactory.create(:fan)
33
33
 
34
- fan.characteristic(:on).on(:updated) do |new_value|
35
- if new_value == 1
34
+ fan.characteristic(:on).after_update do |characteristic|
35
+ if characteristic.value == 1
36
36
  puts "Fan switched on"
37
37
  else
38
38
  puts "Fan switched off"
@@ -42,6 +42,65 @@ end
42
42
  RubyHome.run
43
43
  ```
44
44
 
45
+ Create a garage door opener.
46
+
47
+ ```ruby
48
+ require 'ruby_home'
49
+
50
+ accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
51
+ door = RubyHome::ServiceFactory.create(:garage_door_opener)
52
+
53
+ door.characteristic(:target_door_state).after_update do |characteristic|
54
+ if characteristic.value == 0 # open
55
+ sleep 1
56
+ door.characteristic(:current_door_state).value = 0
57
+ elsif characteristic.value == 1 #closed
58
+ sleep 1
59
+ door.characteristic(:current_door_state).value = 1
60
+ end
61
+ end
62
+
63
+ RubyHome.run
64
+ ```
65
+
66
+ ## Customization
67
+
68
+ RubyHome ties to provide sane defaults for all services. Customization of any of the options is possible.
69
+
70
+ ```ruby
71
+ require 'ruby_home'
72
+
73
+ accessory_information = RubyHome::ServiceFactory.create(:accessory_information,
74
+ firmware_revision: '4.3.18421',
75
+ manufacturer: 'Fake Company',
76
+ model: 'BSB001',
77
+ name: 'Kickass fan bridge',
78
+ serial_number: 'AB1-UK-A123456'
79
+ )
80
+
81
+ fan = RubyHome::ServiceFactory.create(:fan,
82
+ on: false,
83
+ rotation_speed: 50,
84
+ rotation_direction: 1,
85
+ firmware_revision: '105.0.21169',
86
+ manufacturer: 'Fake Company',
87
+ model: 'LWB006',
88
+ name: 'Kickass fan',
89
+ serial_number: '123-UK-A12345'
90
+ )
91
+
92
+ fan.characteristic(:on).after_update do |characteristic|
93
+ if characteristic.value == 1
94
+ puts "Fan switched on"
95
+ else
96
+ puts "Fan switched off"
97
+ end
98
+ end
99
+
100
+ RubyHome.run
101
+ ```
102
+
103
+
45
104
  ## Development
46
105
 
47
106
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/rubyhome CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  require_relative '../lib/ruby_home'
4
4
 
5
- accessory_information = RubyHome::AccessoryFactory.create(:accessory_information)
6
- fan = RubyHome::AccessoryFactory.create(:fan)
5
+ accessory_information = RubyHome::ServiceFactory.create(:accessory_information)
6
+ fan = RubyHome::ServiceFactory.create(:fan)
7
7
 
8
- fan.characteristic(:on).on(:updated) do |new_value|
9
- if new_value == 1
8
+ fan.characteristic(:on).after_update do |characteristic|
9
+ if characteristic.value == 1
10
10
  puts "Fan switched on"
11
11
  else
12
12
  puts "Fan switched off"
@@ -1,24 +1,46 @@
1
- require_relative 'device_id'
2
- require_relative 'yaml_record'
1
+ require_relative 'persistable'
3
2
 
4
3
  module RubyHome
5
- class AccessoryInfo < YamlRecord::Base
4
+ class AccessoryInfo
5
+ include Persistable
6
+
7
+ self.source = 'accessory_info.yml'
8
+
9
+ def self.instance
10
+ @@_instance ||= persisted || create
11
+ end
12
+
13
+ def self.reload
14
+ @@_instance = nil
15
+ end
16
+
6
17
  USERNAME = -'Pair-Setup'
7
18
 
8
- properties :device_id, :paired_clients, :password, :signature_key
9
- source 'accessory_info.yml'
19
+ def initialize(device_id: nil, paired_clients: [], password: nil, signature_key: nil)
20
+ @device_id = device_id
21
+ @paired_clients = paired_clients
22
+ @password = password
23
+ @signature_key = signature_key
24
+ end
10
25
 
11
- set_callback :before_create, :set_device_id
12
- set_callback :before_create, :set_paired_clients
13
- set_callback :before_create, :set_password
14
- set_callback :before_create, :set_signature_key
26
+ def username
27
+ USERNAME
28
+ end
15
29
 
16
- def self.instance
17
- first || create
30
+ def password
31
+ @password ||= Password.generate
32
+ end
33
+
34
+ def device_id
35
+ @device_id ||= DeviceID.generate
36
+ end
37
+
38
+ def paired_clients
39
+ @paired_clients ||= []
18
40
  end
19
41
 
20
42
  def add_paired_client(admin: false, identifier: , public_key: )
21
- paired_clients << { admin: admin, identifier: identifier, public_key: public_key }
43
+ @paired_clients << { admin: admin, identifier: identifier, public_key: public_key }
22
44
  save
23
45
  end
24
46
 
@@ -35,26 +57,19 @@ module RubyHome
35
57
  @signing_key ||= RbNaCl::Signatures::Ed25519::SigningKey.new([signature_key].pack('H*'))
36
58
  end
37
59
 
38
- def username
39
- USERNAME
40
- end
41
-
42
60
  private
43
61
 
44
- def set_device_id
45
- self.device_id ||= DeviceID.generate
46
- end
47
-
48
- def set_paired_clients
49
- self.paired_clients = []
50
- end
62
+ def signature_key
63
+ @signature_key ||= RbNaCl::Signatures::Ed25519::SigningKey.generate.to_bytes.unpack1('H*')
64
+ end
51
65
 
52
- def set_password
53
- self.password ||= Password.generate
54
- end
55
-
56
- def set_signature_key
57
- self.signature_key ||= RbNaCl::Signatures::Ed25519::SigningKey.generate.to_bytes.unpack1('H*')
58
- end
66
+ def persisted_attributes
67
+ {
68
+ device_id: device_id,
69
+ paired_clients: paired_clients,
70
+ password: password,
71
+ signature_key: signature_key
72
+ }
73
+ end
59
74
  end
60
75
  end
@@ -4,37 +4,45 @@ module RubyHome
4
4
  identify: nil,
5
5
  }.freeze
6
6
 
7
- def self.create(characteristic_name, options={}, &block)
8
- new(characteristic_name, options).create(&block)
9
- end
10
-
11
- def initialize(characteristic_name, options)
12
- @characteristic_name = characteristic_name
13
- @options = options
7
+ def self.create(characteristic_name, service: , value: nil)
8
+ new(
9
+ characteristic_name: characteristic_name,
10
+ service: service,
11
+ value: value
12
+ ).create
14
13
  end
15
14
 
16
15
  def create
17
- yield characteristic if block_given?
16
+ service.characteristics << new_characteristic
18
17
 
19
- characteristic.save
20
- characteristic
18
+ new_characteristic
21
19
  end
22
20
 
23
21
  private
24
22
 
25
- attr_reader :characteristic_name, :options
26
-
27
- def template
28
- @template ||= CharacteristicTemplate.find_by(name: characteristic_name.to_sym)
23
+ def initialize(characteristic_name:, service:, value:)
24
+ @characteristic_name = characteristic_name.to_sym
25
+ @service = service
26
+ @value = value || default_value
29
27
  end
30
28
 
31
- def characteristic
32
- @characteristic ||= Characteristic.new(characteristic_params)
29
+ attr_reader :service, :characteristic_name, :value
30
+
31
+ def new_characteristic
32
+ @new_characteristic ||= Characteristic.new(
33
+ description: template.description,
34
+ format: template.format,
35
+ name: characteristic_name,
36
+ properties: template.properties,
37
+ service: service,
38
+ unit: template.unit,
39
+ uuid: template.uuid,
40
+ value: value
41
+ )
33
42
  end
34
43
 
35
- def characteristic_params
36
- options[:value] ||= default_value
37
- options.merge(template.to_hash)
44
+ def template
45
+ @template ||= CharacteristicTemplate.find_by(name: characteristic_name)
38
46
  end
39
47
 
40
48
  def default_value
@@ -9,7 +9,7 @@ module RubyHome
9
9
  private
10
10
 
11
11
  def minimum_value
12
- template.constraints.fetch('MinimumValue')
12
+ template.constraints.fetch('MinimumValue', 0)
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,89 @@
1
+ module RubyHome
2
+ class ServiceFactory
3
+ def self.create(service_name, accessory: Accessory.new, **options)
4
+ new(
5
+ service_name: service_name,
6
+ accessory: accessory,
7
+ **options
8
+ ).create
9
+ end
10
+
11
+ def create
12
+ accessory.services << new_service
13
+
14
+ create_accessory_information
15
+ create_required_characteristics
16
+ create_optional_characteristics
17
+
18
+ new_service
19
+ end
20
+
21
+ private
22
+ ACCESSORY_INFORMATION_OPTIONS = [
23
+ :firmware_revision,
24
+ :manufacturer,
25
+ :model,
26
+ :name,
27
+ :serial_number
28
+ ].freeze
29
+
30
+ def initialize(service_name:, accessory:, **options)
31
+ @service_name = service_name.to_sym
32
+ @accessory = accessory
33
+ @options = options
34
+ end
35
+
36
+ attr_reader :service_name, :accessory, :options
37
+
38
+ def new_service
39
+ @new_service ||= Service.new(
40
+ accessory: accessory,
41
+ description: template.description,
42
+ name: service_name,
43
+ uuid: template.uuid
44
+ )
45
+ end
46
+
47
+ def create_required_characteristics
48
+ template.required_characteristics.each do |characteristic_template|
49
+ characteristic_name = characteristic_template.name
50
+ CharacteristicFactory.create(
51
+ characteristic_template.name,
52
+ service: new_service,
53
+ value: options[characteristic_name]
54
+ )
55
+ end
56
+ end
57
+
58
+ def create_optional_characteristics
59
+ optional_characteristic_templates.each do |characteristic_template|
60
+ characteristic_name = characteristic_template.name
61
+ CharacteristicFactory.create(
62
+ characteristic_name,
63
+ service: new_service,
64
+ value: options[characteristic_name]
65
+ )
66
+ end
67
+ end
68
+
69
+ def optional_characteristic_templates
70
+ template.optional_characteristics.select do |characteristic_template|
71
+ options.keys.include?(characteristic_template.name)
72
+ end
73
+ end
74
+
75
+ def create_accessory_information
76
+ unless service_name == :accessory_information
77
+ ServiceFactory.create(
78
+ :accessory_information,
79
+ accessory: accessory,
80
+ **options.slice(*ACCESSORY_INFORMATION_OPTIONS)
81
+ )
82
+ end
83
+ end
84
+
85
+ def template
86
+ @template ||= ServiceTemplate.find_by(name: service_name)
87
+ end
88
+ end
89
+ end
@@ -15,7 +15,7 @@ module RubyHome
15
15
  end
16
16
  end
17
17
 
18
- def initialize(name:, description:, uuid:, format:, unit:, permissions:, properties:, constraints:)
18
+ def initialize(name:, description:, uuid:, format:, unit:, permissions:, properties:, constraints: )
19
19
  @name = name
20
20
  @description = description
21
21
  @uuid = uuid
@@ -26,7 +26,11 @@ module RubyHome
26
26
  @constraints = constraints
27
27
  end
28
28
 
29
- attr_reader :name, :description, :uuid, :format, :unit, :permissions, :properties, :constraints
29
+ attr_reader :name, :description, :uuid, :format, :unit, :permissions, :properties
30
+
31
+ def constraints
32
+ @constraints || {}
33
+ end
30
34
 
31
35
  def to_hash
32
36
  {
@@ -1,11 +1,22 @@
1
1
  module RubyHome
2
2
  class Accessory
3
+ @@all = AccessoryCollection.new
4
+
5
+ def self.all
6
+ @@all
7
+ end
8
+
9
+ def self.reset
10
+ @@all = AccessoryCollection.new
11
+ end
12
+
3
13
  def initialize
4
14
  @services = []
15
+ @id = next_available_accessory_id
16
+ @@all << self
5
17
  end
6
18
 
7
- attr_accessor :id
8
- attr_reader :services
19
+ attr_reader :services, :id
9
20
 
10
21
  def characteristics
11
22
  services.flat_map(&:characteristics)
@@ -15,12 +26,22 @@ module RubyHome
15
26
  (largest_instance_id || 0) + 1
16
27
  end
17
28
 
29
+ private
30
+
18
31
  def instance_ids
19
- services.map(&:instance_id) + characteristics.map(&:instance_id)
32
+ instances.map(&:instance_id)
33
+ end
34
+
35
+ def instances
36
+ services + characteristics
20
37
  end
21
38
 
22
39
  def largest_instance_id
23
40
  instance_ids.max
24
41
  end
42
+
43
+ def next_available_accessory_id
44
+ self.class.all.count + 1
45
+ end
25
46
  end
26
47
  end
@@ -0,0 +1,38 @@
1
+ module RubyHome
2
+ class AccessoryCollection
3
+ include Enumerable
4
+ attr_accessor :accessories
5
+
6
+ def initialize(*accessories)
7
+ @accessories = accessories
8
+ end
9
+
10
+ def each
11
+ @accessories.map do |accessory|
12
+ yield accessory
13
+ end
14
+ end
15
+
16
+ def <<(accessory)
17
+ @accessories << accessory
18
+ end
19
+
20
+ def find_characteristic(attributes)
21
+ characteristics.find do |characteristic|
22
+ attributes.all? do |key, value|
23
+ characteristic.send(key) == value
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def services
31
+ accessories.flat_map(&:services)
32
+ end
33
+
34
+ def characteristics
35
+ services.flat_map(&:characteristics)
36
+ end
37
+ end
38
+ end
@@ -2,6 +2,18 @@ module RubyHome
2
2
  class Characteristic
3
3
  include Wisper::Publisher
4
4
 
5
+ public :local_registrations
6
+
7
+ def unsubscribe(*listeners)
8
+ local_registrations.delete_if do |registration|
9
+ listeners.include?(registration.listener)
10
+ end
11
+ end
12
+
13
+ def after_update(&block)
14
+ on(:after_update, &block)
15
+ end
16
+
5
17
  PROPERTIES = {
6
18
  'cnotify' => 'ev',
7
19
  'read' => 'pr',
@@ -18,10 +30,20 @@ module RubyHome
18
30
  @properties = properties
19
31
  @service = service
20
32
  @value = value
33
+ @instance_id = accessory.next_available_instance_id
21
34
  end
22
35
 
23
- attr_reader :service, :value, :uuid, :name, :description, :format, :unit, :properties
24
- attr_accessor :instance_id
36
+ attr_reader(
37
+ :service,
38
+ :value,
39
+ :uuid,
40
+ :name,
41
+ :description,
42
+ :format,
43
+ :unit,
44
+ :properties,
45
+ :instance_id
46
+ )
25
47
 
26
48
  def accessory
27
49
  service.accessory
@@ -37,24 +59,8 @@ module RubyHome
37
59
 
38
60
  def value=(new_value)
39
61
  return if name == :identify
40
-
41
62
  @value = new_value
42
- broadcast(:updated, new_value)
43
- end
44
-
45
- def inspect
46
- {
47
- name: name,
48
- value: value,
49
- accessory_id: accessory_id,
50
- service_iid: service_iid,
51
- instance_id: instance_id
52
- }
53
- end
54
-
55
- def save
56
- IdentifierCache.add_accessory(accessory)
57
- IdentifierCache.add_characteristic(self)
63
+ broadcast(:after_update, self)
58
64
  end
59
65
  end
60
66
  end
@@ -0,0 +1,31 @@
1
+ module RubyHome
2
+ module HAP
3
+ module Crypto
4
+ class SessionKey
5
+ def initialize(shared_secret)
6
+ @shared_secret = shared_secret
7
+ end
8
+
9
+ def controller_to_accessory_key
10
+ @controller_to_accessory_key ||= generate_shared_secret_key(WRITE)
11
+ end
12
+
13
+ def accessory_to_controller_key
14
+ @accessory_to_controller_key ||= generate_shared_secret_key(READ)
15
+ end
16
+
17
+ private
18
+
19
+ SALT = -'Control-Salt'
20
+ READ = -'Control-Read-Encryption-Key'
21
+ WRITE = -'Control-Write-Encryption-Key'
22
+
23
+ attr_reader :shared_secret
24
+
25
+ def generate_shared_secret_key(info)
26
+ Crypto::HKDF.new(info: info, salt: SALT).encrypt(shared_secret)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,64 @@
1
+ module RubyHome
2
+ module HAP
3
+ class EVResponse
4
+ def initialize(socket, body)
5
+ @socket = socket
6
+ @body = body
7
+ cache[:accessory_to_controller_count] ||= 0
8
+ end
9
+
10
+ def send_response
11
+ response = ''
12
+
13
+ send_header(response)
14
+ send_body(response)
15
+
16
+ encrypted_response = encrypter.encrypt(response).join
17
+ cache[:accessory_to_controller_count] = encrypter.count
18
+
19
+ socket << encrypted_response
20
+ end
21
+
22
+ private
23
+
24
+ CRLF = -"\x0d\x0a"
25
+ STATUS_LINE = -'EVENT/1.0 200 OK'
26
+ CONTENT_TYPE_LINE = -'Content-Type: application/hap+json'
27
+
28
+ def send_header(socket)
29
+ socket << STATUS_LINE + CRLF
30
+ socket << CONTENT_TYPE_LINE + CRLF
31
+ socket << content_length_line + CRLF
32
+ socket << CRLF
33
+ end
34
+
35
+ def send_body(socket)
36
+ socket << body
37
+ end
38
+
39
+ def content_length_line
40
+ "Content-Length: #{body.length}"
41
+ end
42
+
43
+ attr_reader :body, :socket
44
+
45
+ def encrypter
46
+ @_encrypter ||= RubyHome::HAP::HTTPEncryption.new(encryption_key, encrypter_params)
47
+ end
48
+
49
+ def encrypter_params
50
+ {
51
+ count: cache[:accessory_to_controller_count]
52
+ }
53
+ end
54
+
55
+ def encryption_key
56
+ cache[:accessory_to_controller_key]
57
+ end
58
+
59
+ def cache
60
+ RubyHome.socket_store[socket]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,13 +1,14 @@
1
1
  module RubyHome
2
- module HTTP
2
+ module HAP
3
3
  class HAPRequest < WEBrick::HTTPRequest
4
- def initialize(*args)
4
+ def initialize(config, sock)
5
+ @sock = sock
5
6
  cache[:controller_to_accessory_count] ||= 0
6
7
 
7
- super(*args)
8
+ super(config)
8
9
  end
9
10
 
10
- def parse(socket=nil)
11
+ def parse(socket)
11
12
  if decryption_time?
12
13
  request_line = socket.read_nonblock(@buffer_size)
13
14
 
@@ -24,8 +25,14 @@ module RubyHome
24
25
  cache[:controller_to_accessory_count] >= 1
25
26
  end
26
27
 
28
+ def meta_vars
29
+ super.merge({"REQUEST_SOCKET" => sock})
30
+ end
31
+
27
32
  private
28
33
 
34
+ attr_reader :sock
35
+
29
36
  def decrypter
30
37
  @_decrypter ||= RubyHome::HAP::HTTPDecryption.new(decryption_key, decrypter_params)
31
38
  end
@@ -45,7 +52,7 @@ module RubyHome
45
52
  end
46
53
 
47
54
  def cache
48
- RequestStore.store
55
+ RubyHome.socket_store[sock]
49
56
  end
50
57
  end
51
58
  end