lib/dns-sd/service_instance.rb in dns-sd-0.1.1 vs lib/dns-sd/service_instance.rb in dns-sd-0.1.2
- old
+ new
@@ -1,10 +1,11 @@
require 'dns-sd/resource_cache'
require 'dns-sd/service'
require 'dns-sd/target'
require 'resolv'
+require 'digest/md5'
class DNSSD
# A single instance of a service.
#
# This is where the rubber hits the road: servers to talk to, and instance
@@ -91,15 +92,34 @@
# connection to the service instance, you call `#targets` again, both
# because the DNS records may have expired (and thus will be re-queried),
# but also because it'll ensure that the weight-based randomisation of the
# server list is respected.
#
+ # @param deterministic [String] (Optional) If provided, use the given string
+ # to create a seed to use when shuffling the records so that each time this
+ # method is called, the same set of records will be shuffled into the same
+ # order. By default, each time this method is called, records are (probably)
+ # returned in a different order.
+ #
# @return [Array<DNSSD::Target>]
- def targets
+ def targets(deterministic: nil)
[].tap do |list|
left = cached_resources(@fqdn, Resolv::DNS::Resource::IN::SRV)
+ seed = if deterministic
+ left = left.sort_by { |rr| [rr.target.to_s, rr.port] }
+
+ Digest::MD5.hexdigest(
+ deterministic.to_s +
+ left.map { |rr| [rr.target.to_s, rr.port, rr.priority, rr.weight] }.inspect
+ ).hex
+ else
+ Random.new_seed
+ end
+
+ prng = Random.new(seed)
+
# Happily, this algorithm, whilst a bit involved, maps quite directly
# to the description from RFC2782, page 4, of which parts are quoted as
# appropriate below. A practical example of how this process runs is
# described in the test suite, also, which might help explain what's
# happening.
@@ -133,10 +153,10 @@
until candidates.empty?
# > Compute the sum of the weights of those RRs, and with each RR
# > associate the running sum in the selected order. Then choose a
# > uniform random number between 0 and the sum computed
# > (inclusive)
- selector = rand(candidates.inject(1) { |n, rr| n + rr.weight })
+ selector = prng.rand(candidates.inject(1) { |n, rr| n + rr.weight })
# > select the RR whose running sum value is the first in the
# > selected order which is greater than or equal to the random
# > number selected
chosen = candidates.inject(0) do |n, rr|