rbot 0.9.9
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.
- data/AUTHORS +16 -0
- data/COPYING +21 -0
- data/ChangeLog +418 -0
- data/INSTALL +8 -0
- data/README +44 -0
- data/REQUIREMENTS +34 -0
- data/TODO +5 -0
- data/Usage_en.txt +129 -0
- data/bin/rbot +81 -0
- data/data/rbot/contrib/plugins/figlet.rb +20 -0
- data/data/rbot/contrib/plugins/ri.rb +83 -0
- data/data/rbot/contrib/plugins/stats.rb +232 -0
- data/data/rbot/contrib/plugins/vandale.rb +49 -0
- data/data/rbot/languages/dutch.lang +73 -0
- data/data/rbot/languages/english.lang +75 -0
- data/data/rbot/languages/french.lang +39 -0
- data/data/rbot/languages/german.lang +67 -0
- data/data/rbot/plugins/autoop.rb +68 -0
- data/data/rbot/plugins/autorejoin.rb +16 -0
- data/data/rbot/plugins/cal.rb +15 -0
- data/data/rbot/plugins/dice.rb +81 -0
- data/data/rbot/plugins/eightball.rb +19 -0
- data/data/rbot/plugins/excuse.rb +470 -0
- data/data/rbot/plugins/fish.rb +61 -0
- data/data/rbot/plugins/fortune.rb +22 -0
- data/data/rbot/plugins/freshmeat.rb +98 -0
- data/data/rbot/plugins/google.rb +51 -0
- data/data/rbot/plugins/host.rb +14 -0
- data/data/rbot/plugins/httpd.rb.disabled +35 -0
- data/data/rbot/plugins/insult.rb +258 -0
- data/data/rbot/plugins/karma.rb +85 -0
- data/data/rbot/plugins/lart.rb +181 -0
- data/data/rbot/plugins/math.rb +122 -0
- data/data/rbot/plugins/nickserv.rb +89 -0
- data/data/rbot/plugins/nslookup.rb +43 -0
- data/data/rbot/plugins/opme.rb +19 -0
- data/data/rbot/plugins/quakeauth.rb +51 -0
- data/data/rbot/plugins/quotes.rb +321 -0
- data/data/rbot/plugins/remind.rb +228 -0
- data/data/rbot/plugins/roshambo.rb +54 -0
- data/data/rbot/plugins/rot13.rb +10 -0
- data/data/rbot/plugins/roulette.rb +147 -0
- data/data/rbot/plugins/rss.rb.disabled +414 -0
- data/data/rbot/plugins/seen.rb +89 -0
- data/data/rbot/plugins/slashdot.rb +94 -0
- data/data/rbot/plugins/spell.rb +36 -0
- data/data/rbot/plugins/tube.rb +71 -0
- data/data/rbot/plugins/url.rb +88 -0
- data/data/rbot/plugins/weather.rb +649 -0
- data/data/rbot/plugins/wserver.rb +71 -0
- data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
- data/data/rbot/templates/keywords.rbot +4 -0
- data/data/rbot/templates/lart/larts +98 -0
- data/data/rbot/templates/lart/praises +5 -0
- data/data/rbot/templates/levels.rbot +30 -0
- data/data/rbot/templates/users.rbot +1 -0
- data/lib/rbot/auth.rb +203 -0
- data/lib/rbot/channel.rb +54 -0
- data/lib/rbot/config.rb +363 -0
- data/lib/rbot/dbhash.rb +112 -0
- data/lib/rbot/httputil.rb +141 -0
- data/lib/rbot/ircbot.rb +808 -0
- data/lib/rbot/ircsocket.rb +185 -0
- data/lib/rbot/keywords.rb +433 -0
- data/lib/rbot/language.rb +69 -0
- data/lib/rbot/message.rb +256 -0
- data/lib/rbot/messagemapper.rb +262 -0
- data/lib/rbot/plugins.rb +291 -0
- data/lib/rbot/post-install.rb +8 -0
- data/lib/rbot/rbotconfig.rb +36 -0
- data/lib/rbot/registry.rb +271 -0
- data/lib/rbot/rfc2812.rb +1104 -0
- data/lib/rbot/timer.rb +201 -0
- data/lib/rbot/utils.rb +83 -0
- data/setup.rb +1360 -0
- metadata +129 -0
data/lib/rbot/channel.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
module Irc
|
2
|
+
|
3
|
+
# class to store IRC channel data (users, topic, per-channel configurations)
|
4
|
+
class IRCChannel
|
5
|
+
# name of channel
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
# current channel topic
|
9
|
+
attr_reader :topic
|
10
|
+
|
11
|
+
# hash containing users currently in the channel
|
12
|
+
attr_accessor :users
|
13
|
+
|
14
|
+
# if true, bot won't talk in this channel
|
15
|
+
attr_accessor :quiet
|
16
|
+
|
17
|
+
# name:: channel name
|
18
|
+
# create a new IRCChannel
|
19
|
+
def initialize(name)
|
20
|
+
@name = name
|
21
|
+
@users = Hash.new
|
22
|
+
@quiet = false
|
23
|
+
@topic = Topic.new
|
24
|
+
end
|
25
|
+
|
26
|
+
# eg @bot.channels[chan].topic = topic
|
27
|
+
def topic=(name)
|
28
|
+
@topic.name = name
|
29
|
+
end
|
30
|
+
|
31
|
+
# class to store IRC channel topic information
|
32
|
+
class Topic
|
33
|
+
# topic name
|
34
|
+
attr_accessor :name
|
35
|
+
|
36
|
+
# timestamp
|
37
|
+
attr_accessor :timestamp
|
38
|
+
|
39
|
+
# topic set by
|
40
|
+
attr_accessor :by
|
41
|
+
|
42
|
+
def initialize
|
43
|
+
@name = ""
|
44
|
+
end
|
45
|
+
|
46
|
+
# when called like "puts @bots.channels[chan].topic"
|
47
|
+
def to_s
|
48
|
+
@name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/rbot/config.rb
ADDED
@@ -0,0 +1,363 @@
|
|
1
|
+
module Irc
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'rbot/messagemapper'
|
5
|
+
|
6
|
+
class BotConfigValue
|
7
|
+
# allow the definition order to be preserved so that sorting by
|
8
|
+
# definition order is possible. The BotConfigWizard does this to allow
|
9
|
+
# the :wizard questions to be in a sensible order.
|
10
|
+
@@order = 0
|
11
|
+
attr_reader :type
|
12
|
+
attr_reader :desc
|
13
|
+
attr_reader :key
|
14
|
+
attr_reader :wizard
|
15
|
+
attr_reader :requires_restart
|
16
|
+
attr_reader :order
|
17
|
+
def initialize(key, params)
|
18
|
+
unless key =~ /^.+\..+$/
|
19
|
+
raise ArgumentError,"key must be of the form 'module.name'"
|
20
|
+
end
|
21
|
+
@order = @@order
|
22
|
+
@@order += 1
|
23
|
+
@key = key
|
24
|
+
if params.has_key? :default
|
25
|
+
@default = params[:default]
|
26
|
+
else
|
27
|
+
@default = false
|
28
|
+
end
|
29
|
+
@desc = params[:desc]
|
30
|
+
@type = params[:type] || String
|
31
|
+
@on_change = params[:on_change]
|
32
|
+
@validate = params[:validate]
|
33
|
+
@wizard = params[:wizard]
|
34
|
+
@requires_restart = params[:requires_restart]
|
35
|
+
end
|
36
|
+
def default
|
37
|
+
if @default.instance_of?(Proc)
|
38
|
+
@default.call
|
39
|
+
else
|
40
|
+
@default
|
41
|
+
end
|
42
|
+
end
|
43
|
+
def get
|
44
|
+
return BotConfig.config[@key] if BotConfig.config.has_key?(@key)
|
45
|
+
return @default
|
46
|
+
end
|
47
|
+
alias :value :get
|
48
|
+
def set(value, on_change = true)
|
49
|
+
BotConfig.config[@key] = value
|
50
|
+
@on_change.call(BotConfig.bot, value) if on_change && @on_change
|
51
|
+
end
|
52
|
+
def unset
|
53
|
+
BotConfig.config.delete(@key)
|
54
|
+
end
|
55
|
+
|
56
|
+
# set string will raise ArgumentErrors on failed parse/validate
|
57
|
+
def set_string(string, on_change = true)
|
58
|
+
value = parse string
|
59
|
+
if validate value
|
60
|
+
set value, on_change
|
61
|
+
else
|
62
|
+
raise ArgumentError, "invalid value: #{string}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# override this. the default will work for strings only
|
67
|
+
def parse(string)
|
68
|
+
string
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
get.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def validate(value)
|
77
|
+
return true unless @validate
|
78
|
+
if @validate.instance_of?(Proc)
|
79
|
+
return @validate.call(value)
|
80
|
+
elsif @validate.instance_of?(Regexp)
|
81
|
+
raise ArgumentError, "validation via Regexp only supported for strings!" unless value.instance_of? String
|
82
|
+
return @validate.match(value)
|
83
|
+
else
|
84
|
+
raise ArgumentError, "validation type #{@validate.class} not supported"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class BotConfigStringValue < BotConfigValue
|
90
|
+
end
|
91
|
+
class BotConfigBooleanValue < BotConfigValue
|
92
|
+
def parse(string)
|
93
|
+
return true if string == "true"
|
94
|
+
return false if string == "false"
|
95
|
+
raise ArgumentError, "#{string} does not match either 'true' or 'false'"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
class BotConfigIntegerValue < BotConfigValue
|
99
|
+
def parse(string)
|
100
|
+
raise ArgumentError, "not an integer: #{string}" unless string =~ /^-?\d+$/
|
101
|
+
string.to_i
|
102
|
+
end
|
103
|
+
end
|
104
|
+
class BotConfigFloatValue < BotConfigValue
|
105
|
+
def parse(string)
|
106
|
+
raise ArgumentError, "not a float #{string}" unless string =~ /^-?[\d.]+$/
|
107
|
+
string.to_f
|
108
|
+
end
|
109
|
+
end
|
110
|
+
class BotConfigArrayValue < BotConfigValue
|
111
|
+
def parse(string)
|
112
|
+
string.split(/,\s+/)
|
113
|
+
end
|
114
|
+
def to_s
|
115
|
+
get.join(", ")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
class BotConfigEnumValue < BotConfigValue
|
119
|
+
def initialize(key, params)
|
120
|
+
super
|
121
|
+
@values = params[:values]
|
122
|
+
end
|
123
|
+
def values
|
124
|
+
if @values.instance_of?(Proc)
|
125
|
+
return @values.call(BotConfig.bot)
|
126
|
+
else
|
127
|
+
return @values
|
128
|
+
end
|
129
|
+
end
|
130
|
+
def parse(string)
|
131
|
+
unless @values.include?(string)
|
132
|
+
raise ArgumentError, "invalid value #{string}, allowed values are: " + @values.join(", ")
|
133
|
+
end
|
134
|
+
string
|
135
|
+
end
|
136
|
+
def desc
|
137
|
+
"#{@desc} [valid values are: " + values.join(", ") + "]"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# container for bot configuration
|
142
|
+
class BotConfig
|
143
|
+
# Array of registered BotConfigValues for defaults, types and help
|
144
|
+
@@items = Hash.new
|
145
|
+
def BotConfig.items
|
146
|
+
@@items
|
147
|
+
end
|
148
|
+
# Hash containing key => value pairs for lookup and serialisation
|
149
|
+
@@config = Hash.new(false)
|
150
|
+
def BotConfig.config
|
151
|
+
@@config
|
152
|
+
end
|
153
|
+
def BotConfig.bot
|
154
|
+
@@bot
|
155
|
+
end
|
156
|
+
|
157
|
+
def BotConfig.register(item)
|
158
|
+
unless item.kind_of?(BotConfigValue)
|
159
|
+
raise ArgumentError,"item must be a BotConfigValue"
|
160
|
+
end
|
161
|
+
@@items[item.key] = item
|
162
|
+
end
|
163
|
+
|
164
|
+
# currently we store values in a hash but this could be changed in the
|
165
|
+
# future. We use hash semantics, however.
|
166
|
+
# components that register their config keys and setup defaults are
|
167
|
+
# supported via []
|
168
|
+
def [](key)
|
169
|
+
return @@items[key].value if @@items.has_key?(key)
|
170
|
+
# try to still support unregistered lookups
|
171
|
+
return @@config[key] if @@config.has_key?(key)
|
172
|
+
return false
|
173
|
+
end
|
174
|
+
|
175
|
+
# TODO should I implement this via BotConfigValue or leave it direct?
|
176
|
+
# def []=(key, value)
|
177
|
+
# end
|
178
|
+
|
179
|
+
# pass everything else through to the hash
|
180
|
+
def method_missing(method, *args, &block)
|
181
|
+
return @@config.send(method, *args, &block)
|
182
|
+
end
|
183
|
+
|
184
|
+
def handle_list(m, params)
|
185
|
+
modules = []
|
186
|
+
if params[:module]
|
187
|
+
@@items.each_key do |key|
|
188
|
+
mod, name = key.split('.')
|
189
|
+
next unless mod == params[:module]
|
190
|
+
modules.push key unless modules.include?(name)
|
191
|
+
end
|
192
|
+
if modules.empty?
|
193
|
+
m.reply "no such module #{params[:module]}"
|
194
|
+
else
|
195
|
+
m.reply modules.join(", ")
|
196
|
+
end
|
197
|
+
else
|
198
|
+
@@items.each_key do |key|
|
199
|
+
name = key.split('.').first
|
200
|
+
modules.push name unless modules.include?(name)
|
201
|
+
end
|
202
|
+
m.reply "modules: " + modules.join(", ")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def handle_get(m, params)
|
207
|
+
key = params[:key]
|
208
|
+
unless @@items.has_key?(key)
|
209
|
+
m.reply "no such config key #{key}"
|
210
|
+
return
|
211
|
+
end
|
212
|
+
value = @@items[key].to_s
|
213
|
+
m.reply "#{key}: #{value}"
|
214
|
+
end
|
215
|
+
|
216
|
+
def handle_desc(m, params)
|
217
|
+
key = params[:key]
|
218
|
+
unless @@items.has_key?(key)
|
219
|
+
m.reply "no such config key #{key}"
|
220
|
+
end
|
221
|
+
puts @@items[key].inspect
|
222
|
+
m.reply "#{key}: #{@@items[key].desc}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def handle_unset(m, params)
|
226
|
+
key = params[:key]
|
227
|
+
unless @@items.has_key?(key)
|
228
|
+
m.reply "no such config key #{key}"
|
229
|
+
end
|
230
|
+
@@items[key].unset
|
231
|
+
handle_get(m, params)
|
232
|
+
end
|
233
|
+
|
234
|
+
def handle_set(m, params)
|
235
|
+
key = params[:key]
|
236
|
+
value = params[:value].to_s
|
237
|
+
unless @@items.has_key?(key)
|
238
|
+
m.reply "no such config key #{key}"
|
239
|
+
return
|
240
|
+
end
|
241
|
+
begin
|
242
|
+
@@items[key].set_string(value)
|
243
|
+
rescue ArgumentError => e
|
244
|
+
m.reply "failed to set #{key}: #{e.message}"
|
245
|
+
return
|
246
|
+
end
|
247
|
+
if @@items[key].requires_restart
|
248
|
+
m.reply "this config change will take effect on the next restart"
|
249
|
+
else
|
250
|
+
m.okay
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def handle_help(m, params)
|
255
|
+
topic = params[:topic]
|
256
|
+
case topic
|
257
|
+
when false
|
258
|
+
m.reply "config module - bot configuration. usage: list, desc, get, set, unset"
|
259
|
+
when "list"
|
260
|
+
m.reply "config list => list configuration modules, config list <module> => list configuration keys for module <module>"
|
261
|
+
when "get"
|
262
|
+
m.reply "config get <key> => get configuration value for key <key>"
|
263
|
+
when "unset"
|
264
|
+
m.reply "reset key <key> to the default"
|
265
|
+
when "set"
|
266
|
+
m.reply "config set <key> <value> => set configuration value for key <key> to <value>"
|
267
|
+
when "desc"
|
268
|
+
m.reply "config desc <key> => describe what key <key> configures"
|
269
|
+
else
|
270
|
+
m.reply "no help for config #{topic}"
|
271
|
+
end
|
272
|
+
end
|
273
|
+
def usage(m,params)
|
274
|
+
m.reply "incorrect usage, try '#{@@bot.nick}: help config'"
|
275
|
+
end
|
276
|
+
|
277
|
+
# bot:: parent bot class
|
278
|
+
# create a new config hash from #{botclass}/conf.rbot
|
279
|
+
def initialize(bot)
|
280
|
+
@@bot = bot
|
281
|
+
|
282
|
+
# respond to config messages, to provide runtime configuration
|
283
|
+
# management
|
284
|
+
# messages will be:
|
285
|
+
# get
|
286
|
+
# set
|
287
|
+
# unset
|
288
|
+
# desc
|
289
|
+
# and for arrays:
|
290
|
+
# add TODO
|
291
|
+
# remove TODO
|
292
|
+
@handler = MessageMapper.new(self)
|
293
|
+
@handler.map 'config list :module', :action => 'handle_list',
|
294
|
+
:defaults => {:module => false}
|
295
|
+
@handler.map 'config get :key', :action => 'handle_get'
|
296
|
+
@handler.map 'config desc :key', :action => 'handle_desc'
|
297
|
+
@handler.map 'config describe :key', :action => 'handle_desc'
|
298
|
+
@handler.map 'config set :key *value', :action => 'handle_set'
|
299
|
+
@handler.map 'config unset :key', :action => 'handle_unset'
|
300
|
+
@handler.map 'config help :topic', :action => 'handle_help',
|
301
|
+
:defaults => {:topic => false}
|
302
|
+
@handler.map 'help config :topic', :action => 'handle_help',
|
303
|
+
:defaults => {:topic => false}
|
304
|
+
|
305
|
+
if(File.exist?("#{@@bot.botclass}/conf.yaml"))
|
306
|
+
newconfig = YAML::load_file("#{@@bot.botclass}/conf.yaml")
|
307
|
+
@@config.update newconfig
|
308
|
+
else
|
309
|
+
# first-run wizard!
|
310
|
+
BotConfigWizard.new(@@bot).run
|
311
|
+
# save newly created config
|
312
|
+
save
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
# write current configuration to #{botclass}/conf.rbot
|
317
|
+
def save
|
318
|
+
File.open("#{@@bot.botclass}/conf.yaml", "w") do |file|
|
319
|
+
file.puts @@config.to_yaml
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def privmsg(m)
|
324
|
+
@handler.handle(m)
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
class BotConfigWizard
|
329
|
+
def initialize(bot)
|
330
|
+
@bot = bot
|
331
|
+
@questions = BotConfig.items.values.find_all {|i| i.wizard }
|
332
|
+
end
|
333
|
+
|
334
|
+
def run()
|
335
|
+
puts "First time rbot configuration wizard"
|
336
|
+
puts "===================================="
|
337
|
+
puts "This is the first time you have run rbot with a config directory of:"
|
338
|
+
puts @bot.botclass
|
339
|
+
puts "This wizard will ask you a few questions to get you started."
|
340
|
+
puts "The rest of rbot's configuration can be manipulated via IRC once"
|
341
|
+
puts "rbot is connected and you are auth'd."
|
342
|
+
puts "-----------------------------------"
|
343
|
+
|
344
|
+
return unless @questions
|
345
|
+
@questions.sort{|a,b| a.order <=> b.order }.each do |q|
|
346
|
+
puts q.desc
|
347
|
+
begin
|
348
|
+
print q.key + " [#{q.to_s}]: "
|
349
|
+
response = STDIN.gets
|
350
|
+
response.chop!
|
351
|
+
unless response.empty?
|
352
|
+
q.set_string response, false
|
353
|
+
end
|
354
|
+
puts "configured #{q.key} => #{q.to_s}"
|
355
|
+
puts "-----------------------------------"
|
356
|
+
rescue ArgumentError => e
|
357
|
+
puts "failed to set #{q.key}: #{e.message}"
|
358
|
+
retry
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
data/lib/rbot/dbhash.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
begin
|
2
|
+
require 'bdb'
|
3
|
+
rescue Exception => e
|
4
|
+
puts "Got exception: "+e
|
5
|
+
puts "rbot couldn't load the bdb module, perhaps you need to install it? try: http://www.ruby-lang.org/en/raa-list.rhtml?name=bdb"
|
6
|
+
exit 2
|
7
|
+
end
|
8
|
+
|
9
|
+
# make BTree lookups case insensitive
|
10
|
+
module BDB
|
11
|
+
class CIBtree < Btree
|
12
|
+
def bdb_bt_compare(a, b)
|
13
|
+
a.downcase <=> b.downcase
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module Irc
|
19
|
+
|
20
|
+
# DBHash is for tying a hash to disk (using bdb).
|
21
|
+
# Call it with an identifier, for example "mydata". It'll look for
|
22
|
+
# mydata.db, if it exists, it will load and reference that db.
|
23
|
+
# Otherwise it'll create and empty db called mydata.db
|
24
|
+
class DBHash
|
25
|
+
|
26
|
+
# absfilename:: use +key+ as an actual filename, don't prepend the bot's
|
27
|
+
# config path and don't append ".db"
|
28
|
+
def initialize(bot, key, absfilename=false)
|
29
|
+
@bot = bot
|
30
|
+
@key = key
|
31
|
+
if absfilename && File.exist?(key)
|
32
|
+
# db already exists, use it
|
33
|
+
@db = DBHash.open_db(key)
|
34
|
+
elsif File.exist?(@bot.botclass + "/#{key}.db")
|
35
|
+
# db already exists, use it
|
36
|
+
@db = DBHash.open_db(@bot.botclass + "/#{key}.db")
|
37
|
+
elsif absfilename
|
38
|
+
# create empty db
|
39
|
+
@db = DBHash.create_db(key)
|
40
|
+
else
|
41
|
+
# create empty db
|
42
|
+
@db = DBHash.create_db(@bot.botclass + "/#{key}.db")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def method_missing(method, *args, &block)
|
47
|
+
return @db.send(method, *args, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def DBHash.create_db(name)
|
51
|
+
debug "DBHash: creating empty db #{name}"
|
52
|
+
return BDB::Hash.open(name, nil,
|
53
|
+
BDB::CREATE | BDB::EXCL | BDB::TRUNCATE,
|
54
|
+
0600, "set_pagesize" => 1024,
|
55
|
+
"set_cachesize" => [(0), (32 * 1024), (0)])
|
56
|
+
end
|
57
|
+
|
58
|
+
def DBHash.open_db(name)
|
59
|
+
debug "DBHash: opening existing db #{name}"
|
60
|
+
return BDB::Hash.open(name, nil,
|
61
|
+
"r+", 0600, "set_pagesize" => 1024,
|
62
|
+
"set_cachesize" => [(0), (32 * 1024), (0)])
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# DBTree is a BTree equivalent of DBHash, with case insensitive lookups.
|
69
|
+
class DBTree
|
70
|
+
|
71
|
+
# absfilename:: use +key+ as an actual filename, don't prepend the bot's
|
72
|
+
# config path and don't append ".db"
|
73
|
+
def initialize(bot, key, absfilename=false)
|
74
|
+
@bot = bot
|
75
|
+
@key = key
|
76
|
+
if absfilename && File.exist?(key)
|
77
|
+
# db already exists, use it
|
78
|
+
@db = DBTree.open_db(key)
|
79
|
+
elsif absfilename
|
80
|
+
# create empty db
|
81
|
+
@db = DBTree.create_db(key)
|
82
|
+
elsif File.exist?(@bot.botclass + "/#{key}.db")
|
83
|
+
# db already exists, use it
|
84
|
+
@db = DBTree.open_db(@bot.botclass + "/#{key}.db")
|
85
|
+
else
|
86
|
+
# create empty db
|
87
|
+
@db = DBTree.create_db(@bot.botclass + "/#{key}.db")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def method_missing(method, *args, &block)
|
92
|
+
return @db.send(method, *args, &block)
|
93
|
+
end
|
94
|
+
|
95
|
+
def DBTree.create_db(name)
|
96
|
+
debug "DBTree: creating empty db #{name}"
|
97
|
+
return BDB::CIBtree.open(name, nil,
|
98
|
+
BDB::CREATE | BDB::EXCL | BDB::TRUNCATE,
|
99
|
+
0600, "set_pagesize" => 1024,
|
100
|
+
"set_cachesize" => [(0), (32 * 1024), (0)])
|
101
|
+
end
|
102
|
+
|
103
|
+
def DBTree.open_db(name)
|
104
|
+
debug "DBTree: opening existing db #{name}"
|
105
|
+
return BDB::CIBtree.open(name, nil,
|
106
|
+
"r+", 0600, "set_pagesize" => 1024,
|
107
|
+
"set_cachesize" => [0, 32 * 1024, 0])
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|