discovery 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 204a4d851db30ec0c717303d933b3a2f02aa8ef4
4
+ data.tar.gz: fee2b6b4a7b55e80cf87f8a535c3ff1d42487c73
5
+ SHA512:
6
+ metadata.gz: 98eee54e5dd469906d625ab2a25f5040a1b58d2cbb36dcde8f048fb93e323660767e196314ecbd7c0a667c6bef79facab4000d51a813810a59cb4287444e9c0b
7
+ data.tar.gz: d8f6778c0b2a8b56a48ca568043acc770ef664c9a4522a6d6927868c924bd89c497e252e962e681d8654ad86f2e3887103500eb0691fbe2e8dbf9c019631054f
@@ -0,0 +1,54 @@
1
+
2
+ require_relative 'util/udp'
3
+ require 'timeout'
4
+
5
+ module Discovery
6
+ class UDP
7
+ @port = 0
8
+ @group = "0.0.0.0"
9
+
10
+ def self.new; raise NotImplementedError nil end
11
+
12
+ # Register a callback to be used in the event of a recognized beacon.
13
+ # Each non-nil response object for each UDP beacon will be yielded to it.
14
+ def self.listen &block
15
+ @blocks ||= []
16
+ (@blocks << block).uniq!
17
+
18
+ @thread ||= Thread.new do
19
+ loop do
20
+ @discoverables.values.each_with_object(next_beacon) do |blk,beacon|
21
+ obj = blk.call beacon
22
+ @blocks.each do |callback|
23
+ callback.call(obj)
24
+ end unless obj.nil?
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ # Return the info hash of the next DDDP beacon detected - blocking
31
+ # Optional :timeout keyword argument specifies maximum time to block
32
+ def self.next_beacon timeout:nil
33
+ @udp_rx ||= Util::UDP::RX.new(@group, @port)
34
+ beacon_to_hash(Timeout.timeout(timeout) { @udp_rx.gets })
35
+ end
36
+
37
+ # Convert the incoming beacon to a Hash containing all necessary info
38
+ # Implement to something nontrivial in the inherited module
39
+ def self.beacon_to_hash beacon
40
+ {beacon:beacon}
41
+ end
42
+
43
+ # Register a block to be used to convert a recognized
44
+ # beacon info-hash into a response object.
45
+ # The block should accept the info hash as an argument and
46
+ # return the response object or nil if the beacon isn't recognized.
47
+ class << self; attr_reader :discoverables; end
48
+ def self.register cls, &block
49
+ @discoverables ||= {}
50
+ @discoverables[cls] = block
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,115 @@
1
+
2
+ require 'socket'
3
+ require 'ipaddr'
4
+
5
+ module Discovery
6
+ module Util
7
+ module UDP
8
+
9
+ class << self; attr_accessor :max_length; end
10
+ @max_length = 1024 # default max payload length
11
+
12
+ class Xceiver
13
+ attr_reader :group, :port, :socket, :local_ip, :local_port
14
+
15
+ def self.new(*args)
16
+ if (self.class==Xceiver)
17
+ raise TypeError, "#{self.class} is an 'abstract class' only."\
18
+ " Inherit it; don't instantiate it!"; end
19
+ super
20
+ end
21
+
22
+ def initialize(group, port, **kwargs)
23
+ @group = group
24
+ @port = port
25
+ kwargs.each_pair { |k,v| instance_variable_set("@#{k}".to_sym, v) }
26
+ open
27
+ end
28
+
29
+ def open
30
+ @socket.close if @socket
31
+ @socket = UDPSocket.new
32
+ configure
33
+ @local_ip = Socket.ip_address_list.detect{|intf| intf.ipv4_private?}
34
+ @local_port = @socket.addr[1]
35
+ return @socket
36
+ ensure
37
+ @finalizer ||= ObjectSpace.define_finalizer self, Proc.new { close }
38
+ end
39
+
40
+ def close
41
+ @socket.close if @socket
42
+ @socket = nil
43
+ end
44
+ end
45
+
46
+
47
+ class TX < Xceiver
48
+ def configure
49
+ # Set up for multicasting
50
+ @socket.setsockopt Socket::IPPROTO_IP,
51
+ Socket::IP_MULTICAST_TTL,
52
+ [1].pack('i')
53
+ # Bind to any available port
54
+ @socket.bind "0.0.0.0", (@bind_port or 0)
55
+ end
56
+
57
+ def puts(m)
58
+ max = UDP.max_length
59
+ if m.size > max
60
+ self.puts m[0...max]
61
+ self.puts m[max...m.size]
62
+ else
63
+ @socket.send(m, 0, @group, @port)
64
+ m
65
+ end
66
+ end
67
+ end
68
+
69
+
70
+ class RX < Xceiver
71
+ def configure
72
+ # Add membership to the multicast group
73
+ @socket.setsockopt Socket::IPPROTO_IP,
74
+ Socket::IP_ADD_MEMBERSHIP,
75
+ IPAddr.new(@group).hton + IPAddr.new("0.0.0.0").hton
76
+ # Don't prevent future listening peers on the same machine
77
+ @socket.setsockopt(Socket::SOL_SOCKET,
78
+ Socket::SO_REUSEADDR,
79
+ [1].pack('i')) unless @selfish
80
+ # Bind the socket to the specified port or any open port on the machine
81
+ @socket.bind Socket::INADDR_ANY, @port
82
+ end
83
+
84
+ def gets
85
+ msg, addrinfo = @socket.recvfrom(UDP.max_length)
86
+ msg.instance_variable_set :@source, addrinfo[3].to_s+':'+addrinfo[1].to_s
87
+ class << msg; attr_reader :source; end
88
+ msg
89
+ end
90
+
91
+ def test!(message="#{self}.test!")
92
+ tx = UDP::TX.new @group, @port
93
+ rx = self
94
+
95
+ outer_thread = Thread.current
96
+ passed = false
97
+ thr = Thread.new do
98
+ rx.gets
99
+ passed = true
100
+ outer_thread.wakeup
101
+ end
102
+ Thread.pass
103
+
104
+ tx.puts message
105
+ sleep 1 if thr.status
106
+ thr.kill
107
+ tx.close
108
+
109
+ passed
110
+ end
111
+ end
112
+
113
+ end
114
+ end
115
+ end
data/lib/discovery.rb ADDED
@@ -0,0 +1,2 @@
1
+
2
+ require_relative 'discovery/udp'
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: discovery
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Joe McIlvain
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Device and service discovery.
28
+ email: joe.eli.mac@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/discovery.rb
34
+ - lib/discovery/util/udp.rb
35
+ - lib/discovery/udp.rb
36
+ homepage: https://github.com/jemc/discovery/
37
+ licenses:
38
+ - Copyright 2013 Joe McIlvain. MIT Licensed.
39
+ metadata: {}
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 2.1.5
57
+ signing_key:
58
+ specification_version: 4
59
+ summary: discovery
60
+ test_files: []