This repository has been archived by the owner on Dec 6, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
pdns.rb
167 lines (141 loc) · 5.24 KB
/
pdns.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
require 'logger'
require 'net/geoip'
# Extend the standard Array with certain abilities that would be useful to our situation
class Array
# Randomly shuffles the contents of the array
def shuffle!
size.downto(1) { |n| push delete_at(rand(n)) }
self
end
# Weighted random stuff from http://snippets.dzone.com/posts/show/898
#
# Chooses a random array element from the receiver based on the weights
# provided. If _weights_ is nil, then each element is weighed equally.
#
# [1,2,3].random #=> 2
# [1,2,3].random #=> 1
# [1,2,3].random #=> 3
#
# If _weights_ is an array, then each element of the receiver gets its
# weight from the corresponding element of _weights_. Notice that it
# favors the element with the highest weight.
#
# [1,2,3].random([1,4,1]) #=> 2
# [1,2,3].random([1,4,1]) #=> 1
# [1,2,3].random([1,4,1]) #=> 2
# [1,2,3].random([1,4,1]) #=> 2
# [1,2,3].random([1,4,1]) #=> 3
#
# If _weights_ is a symbol, the weight array is constructed by calling
# the appropriate method on each array element in turn. Notice that
# it favors the longer word when using :length.
#
# ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus"
# ['dog', 'cat', 'hippopotamus'].random(:length) #=> "dog"
# ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus"
# ['dog', 'cat', 'hippopotamus'].random(:length) #=> "hippopotamus"
# ['dog', 'cat', 'hippopotamus'].random(:length) #=> "cat"
def random(weights=nil)
return random(map {|n| n.send(weights)}) if weights.is_a? Symbol
weights ||= Array.new(length, 1.0)
total = weights.inject(0.0) {|t,w| t+w}
point = rand * total
zip(weights).each do |n,w|
return n if w >= point
point -= w
end
end
# Generates a permutation of the receiver based on _weights_ as in
# Array#random. Notice that it favors the element with the highest
# weight.
#
# [1,2,3].randomize #=> [2,1,3]
# [1,2,3].randomize #=> [1,3,2]
# [1,2,3].randomize([1,4,1]) #=> [2,1,3]
# [1,2,3].randomize([1,4,1]) #=> [2,3,1]
# [1,2,3].randomize([1,4,1]) #=> [1,2,3]
# [1,2,3].randomize([1,4,1]) #=> [2,3,1]
# [1,2,3].randomize([1,4,1]) #=> [3,2,1]
# [1,2,3].randomize([1,4,1]) #=> [2,1,3]
def randomize(weights=nil)
return randomize(map {|n| n.send(weights)}) if weights.is_a? Symbol
weights = weights.nil? ? Array.new(length, 1.0) : weights.dup
# pick out elements until there are none left
list, result = self.dup, []
until list.empty?
# pick an element
result << list.random(weights)
# remove the element from the temporary list and its weight
weights.delete_at(list.index(result.last))
list.delete result.last
end
result
end
end
# Top module for pdns backends, record code will execute at this
# level so functions like 'country' need to be created here as
# class methods and should typically just wrap around other classes
# that does the hard work.
module Pdns
class UnknownQueryType < RuntimeError; end
class UnknownQueryClass < RuntimeError; end
class InvalidTTL < RuntimeError; end
class InvalidID < RuntimeError; end
class InvalidShuffle < RuntimeError; end
class UnknownRecord < RuntimeError; end
autoload :Resolvers, "pdns/resolvers.rb"
autoload :Response, "pdns/response.rb"
autoload :Geoip, "pdns/geoip.rb"
autoload :Runner, "pdns/runner.rb"
autoload :Config, "pdns/config.rb"
autoload :Log, "pdns/log.rb"
# should have a copy of Pdns::Config
@@config = nil
# Instance of Pdns::Log
@@logger = nil
# Register a new code block to answer a specific
# resource record
def self.newrecord(name, options = {}, &block)
Pdns::Resolvers.add_resolver(name, options, &block)
end
# Does a country lookup using Pdns::Geoip can handle hostnames
# or IP addresses
def self.country(host)
Pdns::Geoip.country(host)
end
# Saves the config, should be an instance of Pdns::Config
def self.config=(config)
@@config = config
end
# Returns the previously saved instance of Pdns::Config
def self.config
@@config
end
## methods other classes can use to acces our logger
# logs at level INFO
def self.info(msg)
@@logger = Pdns::Log.new unless @@logger
@@logger.log(Logger::INFO, msg)
end
# logs at level WARN
def self.warn(msg)
@@logger = Pdns::Log.new unless @@logger
@@logger.log(Logger::WARN, msg)
end
# logs at level DEBUG
def self.debug(msg)
@@logger = Pdns::Log.new unless @@logger
@@logger.log(Logger::DEBUG, msg)
end
# logs at level FATAL
def self.fatal(msg)
@@logger = Pdns::Log.new unless @@logger
@@logger.log(Logger::FATAL, msg)
end
# logs at level ERROR
def self.error(msg)
@@logger = Pdns::Log.new unless @@logger
@@logger.log(Logger::ERROR, msg)
end
end
# vi:tabstop=4:expandtab:ai:filetype=ruby