Class: Xap::XapHandler
- Inherits:
-
EM::Connection
- Object
- EM::Connection
- Xap::XapHandler
- Defined in:
- lib/xap/xap_handler.rb
Constant Summary collapse
- @@instance =
nil
Class Method Summary collapse
Instance Method Summary collapse
-
#add_device(device) ⇒ Object
Adds a device object to the list of devices.
-
#add_receiver(src_addr, callback) ⇒ Object
Adds a callback to be called with the XapMessage when a message is received from the given source address (src_addr may be wildcarded).
-
#initialize(servername) ⇒ XapHandler
constructor
A new instance of XapHandler.
- #receive_data(d) ⇒ Object
-
#remove_device(device) ⇒ Object
Removes the given device from message notifications.
-
#remove_receiver(src_addr, callback) ⇒ Object
Removes an address/callback pair from the list of callbacks called when a matching message is received.
-
#send_heartbeat(src_addr, src_uid, interval = 60) ⇒ Object
Broadcasts an xAP heartbeat from the given address and UID.
-
#send_message(message) ⇒ Object
Sends an XapMessage to the network.
- #unbind ⇒ Object
Constructor Details
#initialize(servername) ⇒ XapHandler
Returns a new instance of XapHandler.
15 16 17 18 19 20 21 |
# File 'lib/xap/xap_handler.rb', line 15 def initialize servername @@instance = self @servername = servername @devices = [] @receivers = [] @timers = {} end |
Class Method Details
.instance ⇒ Object
11 12 13 |
# File 'lib/xap/xap_handler.rb', line 11 def self.instance @@instance end |
Instance Method Details
#add_device(device) ⇒ Object
Adds a device object to the list of devices. The device will be notified about incoming messages with a target matching the device’s address. If the device’s heartbeat interval is non-nil and greater than 0 then a periodic heartbeat will automatically be transmitted for the device,
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/xap/xap_handler.rb', line 70 def add_device device raise 'device must be an XapDevice' unless device.is_a? XapDevice raise 'device is already in this XapHandler' if @devices.include? device @devices << device if device.interval && device.interval > 0 @timers[device] = EM.add_periodic_timer(device.interval) { send_heartbeat device.address, device.uid, device.interval } end device.handler = self end |
#add_receiver(src_addr, callback) ⇒ Object
Adds a callback to be called with the XapMessage when a message is received from the given source address (src_addr may be wildcarded).
95 96 97 98 99 100 |
# File 'lib/xap/xap_handler.rb', line 95 def add_receiver src_addr, callback raise 'src_addr must be an XapAddress' unless src_addr.is_a? XapAddress raise 'callback must be callable' unless callback.respond_to? :call @receivers << [src_addr, callback] self end |
#receive_data(d) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/xap/xap_handler.rb', line 31 def receive_data d handled = false begin msg = XapMessage.parse(d) rescue Exception => e Xap.log "Error parsing incoming message: #{e}\n\t#{e.backtrace.join("\n\t")}" Xap.log "receive_data(#{d.length}) invalid: #{d.inspect}" return end if msg.target_addr @devices.each do |d| begin if msg.target_addr.base =~ d.address d. msg handled = true end rescue RuntimeError => e Xap.log "Error processing message with device #{d}: #{e}\n\t#{e.backtrace.join("\n\t")}" end end end @receivers.each do |rcv| if rcv[0] =~ msg.src_addr rcv[1].call msg end end if !handled && $DEBUG Xap.log "Received a #{msg.class.name} message (#{msg.src_addr.inspect} => #{msg.target_addr.inspect})" end end |
#remove_device(device) ⇒ Object
Removes the given device from message notifications. Cancels its heartbeat timer if it has one.
86 87 88 89 90 91 |
# File 'lib/xap/xap_handler.rb', line 86 def remove_device device @devices.delete device timer = @timers.delete device timer.cancel if timer device.handler = nil end |
#remove_receiver(src_addr, callback) ⇒ Object
Removes an address/callback pair from the list of callbacks called when a matching message is received.
104 105 106 107 108 109 |
# File 'lib/xap/xap_handler.rb', line 104 def remove_receiver src_addr, callback @receivers.delete_if { |rcv| rcv[0] == src_addr && rcv[1] == callback } nil end |
#send_heartbeat(src_addr, src_uid, interval = 60) ⇒ Object
Broadcasts an xAP heartbeat from the given address and UID.
src_addr and src_uid should be convertible to the exact strings that should go into the packet. interval is how often other devices should expect the heartbeat, in seconds.
www.xapautomation.org/index.php?title=Protocol_definition#Device_Monitoring_-_Heartbeats
The resulting packet will look like this: xap-hbeat { v=12 hop=1 uid= class=xap-hbeat.alive source= interval= }
135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/xap/xap_handler.rb', line 135 def send_heartbeat src_addr, src_uid, interval = 60 msg = "xap-hbeat\n" + "{\n" + "v=12\n" + "hop=1\n" + "uid=#{src_uid}\n" + "class=xap-hbeat.alive\n" + "source=#{src_addr}\n" + "interval=#{interval}\n" + "}\n" send_datagram(msg, BCAST_ADDR, XAP_PORT) end |
#send_message(message) ⇒ Object
Sends an XapMessage to the network.
112 113 114 115 |
# File 'lib/xap/xap_handler.rb', line 112 def raise 'message must be an XapMessage' unless .is_a? XapMessage send_datagram(.to_s, BCAST_ADDR, XAP_PORT) end |
#unbind ⇒ Object
23 24 25 26 27 28 29 |
# File 'lib/xap/xap_handler.rb', line 23 def unbind @@instance = nil if @@instance == self @devices.each do |d| d.handler = nil end end |