xwot_discovery 0.0.1.pre → 0.1.0.pre
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 +4 -4
- data/example/client.rb +28 -0
- data/example/resource.rb +34 -0
- data/lib/xwot_discovery/message.rb +21 -0
- data/lib/xwot_discovery/protocol.rb +149 -0
- data/lib/xwot_discovery/resource.rb +20 -0
- data/lib/xwot_discovery/service.rb +102 -0
- data/lib/xwot_discovery/service_listener.rb +44 -0
- data/lib/xwot_discovery/service_protocol.rb +124 -0
- data/lib/xwot_discovery/version.rb +1 -1
- data/lib/xwot_discovery.rb +31 -2
- data/spec/discovery_spec.rb +63 -0
- data/spec/resource_spec.rb +36 -0
- data/spec/service_protocol_spec.rb +106 -0
- data/spec/service_spec.rb +50 -0
- data/spec/spec_helper.rb +2 -0
- data/xwot_discovery-0.0.1.pre.gem +0 -0
- data/xwot_discovery.gemspec +1 -0
- metadata +38 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8575eb9a35250840b1d4f04d3882f5dca531b916
|
4
|
+
data.tar.gz: b26d956d36f96ee6861b1ab424e14a76b61a4a6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 567f659c31ceb050ecf58145b8911d2b93ef81840de0c206e39166905e799c2a39573e6d90e97fafdfa06790044d5a2aadfe699ed206ffaa60a0718b70c4e86a
|
7
|
+
data.tar.gz: b2cf5a5a42e98ba5b09f65caf4212594a08de1d2a1f9bed6600529cf12e80bc6aea32ae4a44a8dd733dee8a9f24f1f9c5a491f453892f4fe916481bd3b738d87
|
data/example/client.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'xwot_discovery'
|
2
|
+
|
3
|
+
class MyListener < XwotDiscovery::BaseListener
|
4
|
+
|
5
|
+
def alive(message)
|
6
|
+
puts "received alive msg:\n"
|
7
|
+
mprint(message)
|
8
|
+
end
|
9
|
+
|
10
|
+
def bye(message)
|
11
|
+
puts "received bye msg:\n"
|
12
|
+
mprint(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
def mprint(message)
|
16
|
+
m = ''
|
17
|
+
m += "\thostname: #{message.hostname}\n"
|
18
|
+
m += "\thost: #{message.host}\n"
|
19
|
+
m += "\tlocation: #{message.location}\n"
|
20
|
+
m += "\turn: #{message.urn}\n\n"
|
21
|
+
puts m
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
XwotDiscovery.service.register_listener(MyListener.new)
|
27
|
+
|
28
|
+
loop { }
|
data/example/resource.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'xwot_discovery'
|
2
|
+
require 'sinatra'
|
3
|
+
require 'socket'
|
4
|
+
|
5
|
+
addr_info = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
|
6
|
+
ip = addr_info.ip_address
|
7
|
+
port = 4567
|
8
|
+
a_hash = {
|
9
|
+
urn: 'urn:xwot:temperature-sensor',
|
10
|
+
location: "http://#{ip}:#{port}/temperature-sensor",
|
11
|
+
description: {
|
12
|
+
name: 'a temperature sensor',
|
13
|
+
room: 'blah blah'
|
14
|
+
},
|
15
|
+
interface: {
|
16
|
+
'http://10.0.0.33/temperature-sensor' => {
|
17
|
+
input: [],
|
18
|
+
output: [ :xml, :json, :html ],
|
19
|
+
method: :get,
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
resource = XwotDiscovery::XwotResource.new a_hash
|
25
|
+
XwotDiscovery.service.register_resource(resource)
|
26
|
+
|
27
|
+
set :bind, '0.0.0.0'
|
28
|
+
get '/temperature-sensor' do
|
29
|
+
'hello world!'
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/' do
|
33
|
+
'hello world'
|
34
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
class Message
|
4
|
+
|
5
|
+
attr_reader :method, :payload, :location,
|
6
|
+
:content_type, :protocol, :urn, :hostname, :host
|
7
|
+
|
8
|
+
def initialize(a_hash)
|
9
|
+
@method = a_hash[:method]
|
10
|
+
@location = a_hash[:location]
|
11
|
+
@content_type = a_hash[:content_type]
|
12
|
+
@payload = a_hash[:payload]
|
13
|
+
@protocol = a_hash[:protocol] || ''
|
14
|
+
@urn = a_hash[:urn]
|
15
|
+
@host = a_hash[:host]
|
16
|
+
@hostname = a_hash[:hostname]
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
#
|
4
|
+
# An interface for a discovery protocol.
|
5
|
+
#
|
6
|
+
class Protocol
|
7
|
+
|
8
|
+
def listen
|
9
|
+
raise 'not implemented!'
|
10
|
+
end
|
11
|
+
|
12
|
+
def close
|
13
|
+
raise 'not implemented!'
|
14
|
+
end
|
15
|
+
|
16
|
+
def send(message)
|
17
|
+
raise 'not implemented!'
|
18
|
+
end
|
19
|
+
|
20
|
+
def receive
|
21
|
+
raise 'not implemented!'
|
22
|
+
end
|
23
|
+
|
24
|
+
def notify_me(subject)
|
25
|
+
raise 'not implemented!'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Prototype: The Xwot Protocol Discovery implements the protocol interface.
|
32
|
+
#
|
33
|
+
class XwotProtocol < Protocol
|
34
|
+
|
35
|
+
TTL = 1 # time-to-live
|
36
|
+
MULTICAST_ADDR = "224.0.0.15" # multicast group
|
37
|
+
BIND_ADDR = "0.0.0.0"
|
38
|
+
PORT = 2015
|
39
|
+
|
40
|
+
NAME = "XWOT-DISCOVERY"
|
41
|
+
VERSION = "1.0"
|
42
|
+
CRLN = "\r\n"
|
43
|
+
FLAGS = 0
|
44
|
+
|
45
|
+
RECEIVE_MAX_BYTES = 256
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@socket = nil
|
49
|
+
@observer = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def listen
|
53
|
+
init
|
54
|
+
Thread.new do
|
55
|
+
loop do
|
56
|
+
Thread.start(receive) do |data|
|
57
|
+
lines = data.split(CRLN)
|
58
|
+
msg_hash = parse(lines)
|
59
|
+
message = Message.new(msg_hash)
|
60
|
+
#puts "#{Thread.current} - #{msg_hash}\n"
|
61
|
+
@observer.dispatch(message)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse(lines)
|
68
|
+
msg_hash = {
|
69
|
+
method: '',
|
70
|
+
protocol: '',
|
71
|
+
urn: '*',
|
72
|
+
payload: []
|
73
|
+
}
|
74
|
+
|
75
|
+
payload = false
|
76
|
+
lines.each_with_index do |line, index|
|
77
|
+
if index == 0
|
78
|
+
method, urn, protocol = line.split(' ')
|
79
|
+
msg_hash[:method] = method
|
80
|
+
msg_hash[:protocol] = protocol
|
81
|
+
msg_hash[:urn] = urn
|
82
|
+
elsif payload
|
83
|
+
msg_hash[:payload] ||= []
|
84
|
+
msg_hash[:payload] << line
|
85
|
+
elsif !line.empty?
|
86
|
+
header_field, header_value = line.split(' ')
|
87
|
+
header_field = header_field[0...-1].downcase.tr('-','_').to_sym
|
88
|
+
msg_hash[header_field] = header_value
|
89
|
+
elsif line.empty?
|
90
|
+
payload = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
msg_hash[:payload] = msg_hash[:payload].join('')
|
94
|
+
msg_hash
|
95
|
+
end
|
96
|
+
|
97
|
+
def close
|
98
|
+
@socket.close if !@socket.nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
def send(message)
|
102
|
+
client_socket = UDPSocket.open
|
103
|
+
client_socket.setsockopt(:IPPROTO_IP, :IP_MULTICAST_TTL, TTL)
|
104
|
+
|
105
|
+
urn = if message.urn.nil?
|
106
|
+
'*'
|
107
|
+
else
|
108
|
+
message.urn
|
109
|
+
end
|
110
|
+
|
111
|
+
msg = ""
|
112
|
+
msg += "#{message.method} #{urn} #{NAME}/#{VERSION}#{CRLN}"
|
113
|
+
msg += "HOST: #{MULTICAST_ADDR}:#{PORT}#{CRLN}"
|
114
|
+
msg += "HOSTNAME: #{Socket.gethostname}#{CRLN}"
|
115
|
+
|
116
|
+
if ['alive', 'bye', 'update'].include?(message.method)
|
117
|
+
msg += "LOCATION: #{message.location}#{CRLN}"
|
118
|
+
msg += "CONTENT-TYPE: #{message.content_type}#{CRLN}"
|
119
|
+
msg += "#{CRLN}"
|
120
|
+
msg += "#{message.payload}#{CRLN}"
|
121
|
+
end
|
122
|
+
|
123
|
+
msg += "#{CRLN}"
|
124
|
+
client_socket.send(msg, FLAGS, MULTICAST_ADDR, PORT)
|
125
|
+
client_socket.close
|
126
|
+
end
|
127
|
+
|
128
|
+
def receive
|
129
|
+
data, _ = @socket.recvfrom(RECEIVE_MAX_BYTES)
|
130
|
+
data
|
131
|
+
end
|
132
|
+
|
133
|
+
def notify_me(subject)
|
134
|
+
@observer = subject
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def init
|
140
|
+
@socket = UDPSocket.new(Socket::AF_INET)
|
141
|
+
membership = IPAddr.new(MULTICAST_ADDR).hton + IPAddr.new(BIND_ADDR).hton
|
142
|
+
@socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, membership)
|
143
|
+
@socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
144
|
+
@socket.bind(BIND_ADDR, PORT)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
class XwotResource
|
4
|
+
|
5
|
+
attr_reader :description, :urn, :interface, :location
|
6
|
+
|
7
|
+
def initialize(a_hash)
|
8
|
+
@urn = a_hash[:urn]
|
9
|
+
@location = a_hash[:location]
|
10
|
+
@interface = a_hash[:interface]
|
11
|
+
@description = a_hash[:description]
|
12
|
+
end
|
13
|
+
|
14
|
+
def payload
|
15
|
+
JSON.generate(@description)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
class XwotService
|
4
|
+
|
5
|
+
ALIVE_INTERVAL_SECONDS = 60
|
6
|
+
|
7
|
+
class ServiceProtocolListener < BaseListener
|
8
|
+
|
9
|
+
def initialize(service, resources)
|
10
|
+
@service = service
|
11
|
+
@resources = resources
|
12
|
+
end
|
13
|
+
|
14
|
+
def alive(message)
|
15
|
+
remove = []
|
16
|
+
@service.find_callbacks.each do |tuple|
|
17
|
+
urn, callback = tuple
|
18
|
+
if urn == message.urn
|
19
|
+
callback.call(message)
|
20
|
+
remove << tuple
|
21
|
+
end
|
22
|
+
end
|
23
|
+
@service.find_callbacks = @service.find_callbacks - remove
|
24
|
+
end
|
25
|
+
|
26
|
+
def find(message, service)
|
27
|
+
if message.urn == '*'
|
28
|
+
@resources.each { |resource| @service.send_alive(resource) }
|
29
|
+
else
|
30
|
+
filtered = @resources.select { |resource| resource.urn == message.urn }
|
31
|
+
filtered.each { |resource| @service.send_alive(resource) }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_accessor :find_callbacks
|
38
|
+
|
39
|
+
def initialize(service_protocol)
|
40
|
+
@service_protocol = service_protocol
|
41
|
+
@resources = []
|
42
|
+
@rand = rand * 2 * 60
|
43
|
+
@find_callbacks = []
|
44
|
+
listener = ServiceProtocolListener.new(self, @resources)
|
45
|
+
@service_protocol.register_listener(listener)
|
46
|
+
end
|
47
|
+
|
48
|
+
def start
|
49
|
+
@service_protocol.start
|
50
|
+
#p @rand
|
51
|
+
Thread.new do
|
52
|
+
sleep @rand
|
53
|
+
loop do
|
54
|
+
@resources.each { |resource| send_alive(resource) }
|
55
|
+
sleep ALIVE_INTERVAL_SECONDS
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def find(urn = '*', &block)
|
61
|
+
if block_given?
|
62
|
+
@find_callbacks << [urn, block]
|
63
|
+
end
|
64
|
+
@service_protocol.find(urn)
|
65
|
+
end
|
66
|
+
|
67
|
+
def register_resource(resource)
|
68
|
+
@resources << resource
|
69
|
+
send_alive(resource)
|
70
|
+
end
|
71
|
+
|
72
|
+
def unregister_resource(resource)
|
73
|
+
@resources.delete(resource)
|
74
|
+
send_bye(resource)
|
75
|
+
end
|
76
|
+
|
77
|
+
def register_listener(listener)
|
78
|
+
@service_protocol.register_listener(listener)
|
79
|
+
end
|
80
|
+
|
81
|
+
def unregister_listener(listener)
|
82
|
+
@service_protocol.unregister_listener(listener)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def send_alive(resource)
|
87
|
+
2.times do
|
88
|
+
@service_protocol.alive(resource)
|
89
|
+
sleep 0.5
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def send_bye(resource)
|
94
|
+
2.times do
|
95
|
+
@service_protocol.bye(resource)
|
96
|
+
sleep 0.5
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
class ServiceListener
|
4
|
+
|
5
|
+
def alive(message)
|
6
|
+
raise 'not implemented!'
|
7
|
+
end
|
8
|
+
|
9
|
+
def find(message, service = nil)
|
10
|
+
raise 'not implemented!'
|
11
|
+
end
|
12
|
+
|
13
|
+
def bye(message)
|
14
|
+
raise 'not implemented!'
|
15
|
+
end
|
16
|
+
|
17
|
+
def update(message)
|
18
|
+
raise 'not implemented!'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class BaseListener < ServiceListener
|
25
|
+
|
26
|
+
def alive(message)
|
27
|
+
# do nothing
|
28
|
+
end
|
29
|
+
|
30
|
+
def find(message, service = nil)
|
31
|
+
# do nothing
|
32
|
+
end
|
33
|
+
|
34
|
+
def bye(message)
|
35
|
+
# do nothing
|
36
|
+
end
|
37
|
+
|
38
|
+
def update(message)
|
39
|
+
# do nothing
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module XwotDiscovery
|
2
|
+
|
3
|
+
class XwotServiceProtocol
|
4
|
+
|
5
|
+
class Registry
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@registry = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(message)
|
12
|
+
@registry[message.location] ||= {
|
13
|
+
uri: message.location,
|
14
|
+
message: message
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def update(message)
|
19
|
+
@registry[message.location] = {
|
20
|
+
uri: message.location,
|
21
|
+
message: message
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove(message)
|
26
|
+
@registry.delete(message.location)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(protocol)
|
32
|
+
@protocol = protocol
|
33
|
+
@listeners = []
|
34
|
+
@find_callbacks = []
|
35
|
+
@registry = Registry.new
|
36
|
+
@protocol.notify_me(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def start
|
40
|
+
@protocol.listen
|
41
|
+
end
|
42
|
+
|
43
|
+
def shutdown
|
44
|
+
@protocol.close
|
45
|
+
end
|
46
|
+
|
47
|
+
def register_listener(listener)
|
48
|
+
@listeners << listener
|
49
|
+
end
|
50
|
+
|
51
|
+
def unregister_listener(listener)
|
52
|
+
@listeners.delete(listener)
|
53
|
+
end
|
54
|
+
|
55
|
+
def dispatch(message)
|
56
|
+
@listeners.each do |listener|
|
57
|
+
case message.method.downcase
|
58
|
+
when 'alive'
|
59
|
+
@registry.add(message)
|
60
|
+
listener.alive(message)
|
61
|
+
when 'update'
|
62
|
+
@registry.update(message)
|
63
|
+
listener.update(message)
|
64
|
+
when 'find'
|
65
|
+
listener.find(message, self)
|
66
|
+
when 'bye'
|
67
|
+
@registry.remove(message)
|
68
|
+
listener.bye(message)
|
69
|
+
else
|
70
|
+
# do nothing
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def find(urn = '')
|
76
|
+
urn_str = case urn.to_s
|
77
|
+
when '*'
|
78
|
+
'*'
|
79
|
+
when ''
|
80
|
+
'*'
|
81
|
+
else
|
82
|
+
urn
|
83
|
+
end
|
84
|
+
# TODO: registry lookup
|
85
|
+
message = Message.new({
|
86
|
+
method: 'find',
|
87
|
+
urn: urn_str})
|
88
|
+
#p message
|
89
|
+
@protocol.send(message)
|
90
|
+
end
|
91
|
+
|
92
|
+
def alive(resource)
|
93
|
+
message = Message.new({
|
94
|
+
method: 'alive',
|
95
|
+
urn: resource.urn,
|
96
|
+
location: resource.location,
|
97
|
+
content_type: 'application/json',
|
98
|
+
payload: resource.payload})
|
99
|
+
@protocol.send(message)
|
100
|
+
end
|
101
|
+
|
102
|
+
def bye(resource)
|
103
|
+
message = Message.new({
|
104
|
+
method: 'bye',
|
105
|
+
urn: resource.urn,
|
106
|
+
location: resource.location,
|
107
|
+
content_type: 'application/json',
|
108
|
+
payload: resource.payload})
|
109
|
+
@protocol.send(message)
|
110
|
+
end
|
111
|
+
|
112
|
+
def update(resource)
|
113
|
+
message = Message.new({
|
114
|
+
method: 'update',
|
115
|
+
urn: resource.urn,
|
116
|
+
location: resource.location,
|
117
|
+
content_type: 'application/json',
|
118
|
+
payload: resource.payload})
|
119
|
+
@protocol.send(message)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
data/lib/xwot_discovery.rb
CHANGED
@@ -1,5 +1,34 @@
|
|
1
|
-
require
|
1
|
+
require 'socket'
|
2
|
+
require 'ipaddr'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require 'xwot_discovery/version'
|
6
|
+
require 'xwot_discovery/message'
|
7
|
+
require 'xwot_discovery/protocol'
|
8
|
+
require 'xwot_discovery/service_listener'
|
9
|
+
require 'xwot_discovery/service_protocol'
|
10
|
+
require 'xwot_discovery/service'
|
11
|
+
require 'xwot_discovery/resource'
|
12
|
+
|
2
13
|
|
3
14
|
module XwotDiscovery
|
4
|
-
|
15
|
+
|
16
|
+
def self.service
|
17
|
+
if @service.nil?
|
18
|
+
init
|
19
|
+
@service.start
|
20
|
+
@service
|
21
|
+
else
|
22
|
+
@service
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def self.init
|
29
|
+
@protocol ||= XwotProtocol.new
|
30
|
+
@service_protocol ||= XwotServiceProtocol.new(@protocol)
|
31
|
+
@service ||= XwotService.new @service_protocol
|
32
|
+
end
|
33
|
+
|
5
34
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module XwotDiscovery
|
4
|
+
|
5
|
+
class MyListener < BaseListener
|
6
|
+
|
7
|
+
def alive(message)
|
8
|
+
#p 'alive received!!'
|
9
|
+
#p message
|
10
|
+
end
|
11
|
+
|
12
|
+
def find(message, service)
|
13
|
+
#p 'find received!!'
|
14
|
+
#p message
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "XwotDiscovery.service" do
|
20
|
+
|
21
|
+
before do
|
22
|
+
@a_hash = {
|
23
|
+
urn: 'urn:xwot:temperature-sensor',
|
24
|
+
location: 'http://10.0.0.33/temperature-sensor',
|
25
|
+
description: {
|
26
|
+
name: 'a temperature sensor',
|
27
|
+
room: 'blah blah'
|
28
|
+
},
|
29
|
+
interface: {
|
30
|
+
'http://10.0.0.33/temperature-sensor' => {
|
31
|
+
input: [],
|
32
|
+
output: [ :xml, :json, :html ],
|
33
|
+
method: :get,
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
@resource = XwotResource.new @a_hash
|
38
|
+
s = XwotDiscovery.service
|
39
|
+
s.register_listener(MyListener.new)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "#register_device" do
|
43
|
+
s = XwotDiscovery.service
|
44
|
+
s.register_resource(@resource)
|
45
|
+
#sleep 120 * 2
|
46
|
+
end
|
47
|
+
|
48
|
+
it "#find" do
|
49
|
+
s = XwotDiscovery.service
|
50
|
+
s.find 'urn:xwot:temperature-sensor'
|
51
|
+
s.find
|
52
|
+
|
53
|
+
s.find 'urn:xwot:temperature-sensor' do |message|
|
54
|
+
p 'callback!!'
|
55
|
+
p message.urn
|
56
|
+
end
|
57
|
+
sleep 120 * 2
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module XwotDiscovery
|
4
|
+
|
5
|
+
describe XwotResource do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@a_hash = {
|
9
|
+
urn: 'urn:xwot:temperature-sensor',
|
10
|
+
location: 'http://10.0.0.33/temperature-sensor',
|
11
|
+
description: {
|
12
|
+
name: 'a temperature sensor',
|
13
|
+
room: 'blah blah'
|
14
|
+
},
|
15
|
+
interface: {
|
16
|
+
'http://10.0.0.33/temperature-sensor' => {
|
17
|
+
input: [],
|
18
|
+
output: [ :xml, :json, :html ],
|
19
|
+
method: :get,
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it ".new" do
|
26
|
+
res = XwotResource.new @a_hash
|
27
|
+
expect(res.urn).to_not be_nil
|
28
|
+
expect(res.location).to_not be_nil
|
29
|
+
expect(res.description).to_not be_nil
|
30
|
+
expect(res.interface).to_not be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module XwotDiscovery
|
4
|
+
|
5
|
+
#
|
6
|
+
# The MockProtocol implements a mock discovery protocol.
|
7
|
+
# It's used to test the main protocol logic of the service protocol.
|
8
|
+
#
|
9
|
+
class MockProtocol < Protocol
|
10
|
+
|
11
|
+
def listen
|
12
|
+
p 'listen'
|
13
|
+
receive
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
p 'close'
|
18
|
+
end
|
19
|
+
|
20
|
+
def send(message)
|
21
|
+
p 'send'
|
22
|
+
p message
|
23
|
+
end
|
24
|
+
|
25
|
+
def receive
|
26
|
+
p 'receive'
|
27
|
+
message = Message.new(method: 'alive',
|
28
|
+
host: '224.0.0.15:2015',
|
29
|
+
content_type: 'application/json',
|
30
|
+
payload: '{ "property": "value" }',
|
31
|
+
location: 'http://10.0.0.26/test')
|
32
|
+
@observer.dispatch(message)
|
33
|
+
end
|
34
|
+
|
35
|
+
def notify_me(subject)
|
36
|
+
p 'notify_me called'
|
37
|
+
@observer = subject
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class MockListener < ServiceListener
|
43
|
+
|
44
|
+
def alive(message)
|
45
|
+
p message
|
46
|
+
p 'alive method called'
|
47
|
+
end
|
48
|
+
|
49
|
+
def find(message, service)
|
50
|
+
p message
|
51
|
+
p 'find method called'
|
52
|
+
end
|
53
|
+
|
54
|
+
def bye(message)
|
55
|
+
p message
|
56
|
+
p 'bye method called'
|
57
|
+
end
|
58
|
+
|
59
|
+
def update(message)
|
60
|
+
p message
|
61
|
+
p 'update method called'
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe XwotServiceProtocol do
|
67
|
+
before do
|
68
|
+
@protocol = XwotProtocol.new
|
69
|
+
@service_protocol = XwotServiceProtocol.new(@protocol)
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#start" do
|
73
|
+
it "starts the service" do
|
74
|
+
@service_protocol.start
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#register" do
|
79
|
+
|
80
|
+
it "handles an incoming message" do
|
81
|
+
@service_protocol.register_listener(MockListener.new)
|
82
|
+
@protocol.listen
|
83
|
+
message = Message.new(
|
84
|
+
method: 'alive',
|
85
|
+
content_type: 'application/json',
|
86
|
+
payload: '{ "property": "value" }',
|
87
|
+
location: 'http://10.0.0.26/test'
|
88
|
+
)
|
89
|
+
@protocol.send(message)
|
90
|
+
@service_protocol.find
|
91
|
+
loop do
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#shutdown" do
|
99
|
+
it "shuts down the service" do
|
100
|
+
@service.shutdown
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module XwotDiscovery
|
4
|
+
|
5
|
+
class MyListener < BaseListener
|
6
|
+
|
7
|
+
def alive(message)
|
8
|
+
p 'alive received!!'
|
9
|
+
p message
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
describe XwotService do
|
15
|
+
|
16
|
+
before do
|
17
|
+
@a_hash = {
|
18
|
+
urn: 'urn:xwot:temperature-sensor',
|
19
|
+
location: 'http://10.0.0.33/temperature-sensor',
|
20
|
+
description: {
|
21
|
+
name: 'a temperature sensor',
|
22
|
+
room: 'blah blah'
|
23
|
+
},
|
24
|
+
interface: {
|
25
|
+
'http://10.0.0.33/temperature-sensor' => {
|
26
|
+
input: [],
|
27
|
+
output: [ :xml, :json, :html ],
|
28
|
+
method: :get,
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
@resource = XwotResource.new @a_hash
|
33
|
+
@protocol = XwotProtocol.new
|
34
|
+
@service_protocol = XwotServiceProtocol.new(@protocol)
|
35
|
+
@service = XwotService.new @service_protocol
|
36
|
+
@service.register_listener(MyListener.new)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "#register_device" do
|
40
|
+
@service.register_resource(@resource)
|
41
|
+
@service.start
|
42
|
+
loop do
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
end
|
data/spec/spec_helper.rb
ADDED
Binary file
|
data/xwot_discovery.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xwot_discovery
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.1.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Rueedlinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: Discovery for the xWoT
|
42
56
|
email:
|
43
57
|
- a.rueedlinger@gmail.com
|
@@ -50,8 +64,22 @@ files:
|
|
50
64
|
- LICENSE.txt
|
51
65
|
- README.md
|
52
66
|
- Rakefile
|
67
|
+
- example/client.rb
|
68
|
+
- example/resource.rb
|
53
69
|
- lib/xwot_discovery.rb
|
70
|
+
- lib/xwot_discovery/message.rb
|
71
|
+
- lib/xwot_discovery/protocol.rb
|
72
|
+
- lib/xwot_discovery/resource.rb
|
73
|
+
- lib/xwot_discovery/service.rb
|
74
|
+
- lib/xwot_discovery/service_listener.rb
|
75
|
+
- lib/xwot_discovery/service_protocol.rb
|
54
76
|
- lib/xwot_discovery/version.rb
|
77
|
+
- spec/discovery_spec.rb
|
78
|
+
- spec/resource_spec.rb
|
79
|
+
- spec/service_protocol_spec.rb
|
80
|
+
- spec/service_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
- xwot_discovery-0.0.1.pre.gem
|
55
83
|
- xwot_discovery.gemspec
|
56
84
|
homepage: https://github.com/lexruee/xwot-discovery-ruby
|
57
85
|
licenses:
|
@@ -73,8 +101,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
101
|
version: 1.3.1
|
74
102
|
requirements: []
|
75
103
|
rubyforge_project:
|
76
|
-
rubygems_version: 2.
|
104
|
+
rubygems_version: 2.2.2
|
77
105
|
signing_key:
|
78
106
|
specification_version: 4
|
79
107
|
summary: Discovery for the xWoT
|
80
|
-
test_files:
|
108
|
+
test_files:
|
109
|
+
- spec/discovery_spec.rb
|
110
|
+
- spec/resource_spec.rb
|
111
|
+
- spec/service_protocol_spec.rb
|
112
|
+
- spec/service_spec.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
has_rdoc:
|