ircinch 2.4.0
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 +7 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +298 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +23 -0
- data/README.md +195 -0
- data/Rakefile +14 -0
- data/docs/bot_options.md +454 -0
- data/docs/changes.md +541 -0
- data/docs/common_mistakes.md +60 -0
- data/docs/common_tasks.md +57 -0
- data/docs/encodings.md +69 -0
- data/docs/events.md +273 -0
- data/docs/getting_started.md +184 -0
- data/docs/logging.md +90 -0
- data/docs/migrating.md +267 -0
- data/docs/plugins.md +4 -0
- data/docs/readme.md +20 -0
- data/examples/basic/autovoice.rb +32 -0
- data/examples/basic/google.rb +35 -0
- data/examples/basic/hello.rb +14 -0
- data/examples/basic/join_part.rb +35 -0
- data/examples/basic/memo.rb +39 -0
- data/examples/basic/msg.rb +15 -0
- data/examples/basic/seen.rb +37 -0
- data/examples/basic/urban_dict.rb +36 -0
- data/examples/basic/url_shorten.rb +36 -0
- data/examples/plugins/autovoice.rb +37 -0
- data/examples/plugins/custom_prefix.rb +22 -0
- data/examples/plugins/dice_roll.rb +38 -0
- data/examples/plugins/google.rb +36 -0
- data/examples/plugins/hello.rb +21 -0
- data/examples/plugins/hooks.rb +34 -0
- data/examples/plugins/join_part.rb +41 -0
- data/examples/plugins/lambdas.rb +35 -0
- data/examples/plugins/last_nick.rb +24 -0
- data/examples/plugins/msg.rb +21 -0
- data/examples/plugins/multiple_matches.rb +32 -0
- data/examples/plugins/own_events.rb +37 -0
- data/examples/plugins/seen.rb +44 -0
- data/examples/plugins/timer.rb +22 -0
- data/examples/plugins/url_shorten.rb +34 -0
- data/ircinch.gemspec +43 -0
- data/lib/cinch/ban.rb +53 -0
- data/lib/cinch/bot.rb +476 -0
- data/lib/cinch/cached_list.rb +21 -0
- data/lib/cinch/callback.rb +22 -0
- data/lib/cinch/channel.rb +465 -0
- data/lib/cinch/channel_list.rb +31 -0
- data/lib/cinch/configuration/bot.rb +50 -0
- data/lib/cinch/configuration/dcc.rb +18 -0
- data/lib/cinch/configuration/plugins.rb +43 -0
- data/lib/cinch/configuration/sasl.rb +21 -0
- data/lib/cinch/configuration/ssl.rb +21 -0
- data/lib/cinch/configuration/timeouts.rb +16 -0
- data/lib/cinch/configuration.rb +75 -0
- data/lib/cinch/constants.rb +535 -0
- data/lib/cinch/dcc/dccable_object.rb +39 -0
- data/lib/cinch/dcc/incoming/send.rb +149 -0
- data/lib/cinch/dcc/incoming.rb +3 -0
- data/lib/cinch/dcc/outgoing/send.rb +123 -0
- data/lib/cinch/dcc/outgoing.rb +3 -0
- data/lib/cinch/dcc.rb +14 -0
- data/lib/cinch/exceptions.rb +48 -0
- data/lib/cinch/formatting.rb +127 -0
- data/lib/cinch/handler.rb +120 -0
- data/lib/cinch/handler_list.rb +92 -0
- data/lib/cinch/helpers.rb +230 -0
- data/lib/cinch/i_support.rb +100 -0
- data/lib/cinch/irc.rb +924 -0
- data/lib/cinch/log_filter.rb +23 -0
- data/lib/cinch/logger/formatted_logger.rb +100 -0
- data/lib/cinch/logger/zcbot_logger.rb +26 -0
- data/lib/cinch/logger.rb +171 -0
- data/lib/cinch/logger_list.rb +88 -0
- data/lib/cinch/mask.rb +69 -0
- data/lib/cinch/message.rb +397 -0
- data/lib/cinch/message_queue.rb +104 -0
- data/lib/cinch/mode_parser.rb +78 -0
- data/lib/cinch/network.rb +106 -0
- data/lib/cinch/open_ended_queue.rb +26 -0
- data/lib/cinch/pattern.rb +66 -0
- data/lib/cinch/plugin.rb +517 -0
- data/lib/cinch/plugin_list.rb +40 -0
- data/lib/cinch/rubyext/float.rb +5 -0
- data/lib/cinch/rubyext/module.rb +28 -0
- data/lib/cinch/rubyext/string.rb +35 -0
- data/lib/cinch/sasl/dh_blowfish.rb +73 -0
- data/lib/cinch/sasl/diffie_hellman.rb +50 -0
- data/lib/cinch/sasl/mechanism.rb +8 -0
- data/lib/cinch/sasl/plain.rb +29 -0
- data/lib/cinch/sasl.rb +36 -0
- data/lib/cinch/syncable.rb +83 -0
- data/lib/cinch/target.rb +199 -0
- data/lib/cinch/timer.rb +147 -0
- data/lib/cinch/user.rb +489 -0
- data/lib/cinch/user_list.rb +89 -0
- data/lib/cinch/utilities/deprecation.rb +18 -0
- data/lib/cinch/utilities/encoding.rb +39 -0
- data/lib/cinch/utilities/kernel.rb +15 -0
- data/lib/cinch/version.rb +6 -0
- data/lib/cinch.rb +7 -0
- data/lib/ircinch.rb +7 -0
- metadata +205 -0
data/lib/cinch/bot.rb
ADDED
@@ -0,0 +1,476 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
4
|
+
require "socket"
|
5
|
+
|
6
|
+
require_relative "rubyext/module"
|
7
|
+
require_relative "rubyext/string"
|
8
|
+
require_relative "rubyext/float"
|
9
|
+
|
10
|
+
require_relative "exceptions"
|
11
|
+
|
12
|
+
require_relative "handler"
|
13
|
+
require_relative "helpers"
|
14
|
+
|
15
|
+
require_relative "logger_list"
|
16
|
+
require_relative "logger"
|
17
|
+
|
18
|
+
require_relative "logger/formatted_logger"
|
19
|
+
require_relative "syncable"
|
20
|
+
require_relative "message"
|
21
|
+
require_relative "message_queue"
|
22
|
+
require_relative "irc"
|
23
|
+
require_relative "target"
|
24
|
+
require_relative "channel"
|
25
|
+
require_relative "user"
|
26
|
+
require_relative "constants"
|
27
|
+
require_relative "callback"
|
28
|
+
require_relative "ban"
|
29
|
+
require_relative "mask"
|
30
|
+
require_relative "i_support"
|
31
|
+
require_relative "plugin"
|
32
|
+
require_relative "pattern"
|
33
|
+
require_relative "mode_parser"
|
34
|
+
require_relative "dcc"
|
35
|
+
require_relative "sasl"
|
36
|
+
|
37
|
+
require_relative "handler_list"
|
38
|
+
require_relative "cached_list"
|
39
|
+
require_relative "channel_list"
|
40
|
+
require_relative "user_list"
|
41
|
+
require_relative "plugin_list"
|
42
|
+
|
43
|
+
require_relative "timer"
|
44
|
+
require_relative "formatting"
|
45
|
+
|
46
|
+
require_relative "configuration"
|
47
|
+
require_relative "configuration/bot"
|
48
|
+
require_relative "configuration/plugins"
|
49
|
+
require_relative "configuration/ssl"
|
50
|
+
require_relative "configuration/timeouts"
|
51
|
+
require_relative "configuration/dcc"
|
52
|
+
require_relative "configuration/sasl"
|
53
|
+
|
54
|
+
module Cinch
|
55
|
+
# @attr nick
|
56
|
+
# @version 2.0.0
|
57
|
+
class Bot < User
|
58
|
+
include Helpers
|
59
|
+
|
60
|
+
# @return [Configuration::Bot]
|
61
|
+
# @version 2.0.0
|
62
|
+
attr_reader :config
|
63
|
+
|
64
|
+
# The underlying IRC connection
|
65
|
+
#
|
66
|
+
# @return [IRC]
|
67
|
+
attr_reader :irc
|
68
|
+
|
69
|
+
# The logger list containing all loggers
|
70
|
+
#
|
71
|
+
# @return [LoggerList]
|
72
|
+
# @since 2.0.0
|
73
|
+
attr_accessor :loggers
|
74
|
+
|
75
|
+
# @return [Array<Channel>] All channels the bot currently is in
|
76
|
+
attr_reader :channels
|
77
|
+
|
78
|
+
# @return [PluginList] The {PluginList} giving access to
|
79
|
+
# (un)loading plugins
|
80
|
+
# @version 2.0.0
|
81
|
+
attr_reader :plugins
|
82
|
+
|
83
|
+
# @return [Boolean] whether the bot is in the process of disconnecting
|
84
|
+
attr_reader :quitting
|
85
|
+
|
86
|
+
# @return [UserList] All {User users} the bot knows about.
|
87
|
+
# @see UserList
|
88
|
+
# @since 1.1.0
|
89
|
+
attr_reader :user_list
|
90
|
+
|
91
|
+
# @return [ChannelList] All {Channel channels} the bot knows about.
|
92
|
+
# @see ChannelList
|
93
|
+
# @since 1.1.0
|
94
|
+
attr_reader :channel_list
|
95
|
+
|
96
|
+
# @return [Boolean]
|
97
|
+
# @api private
|
98
|
+
attr_accessor :last_connection_was_successful
|
99
|
+
|
100
|
+
# @return [Callback]
|
101
|
+
# @api private
|
102
|
+
attr_reader :callback
|
103
|
+
|
104
|
+
# The {HandlerList}, providing access to all registered plugins
|
105
|
+
# and plugin manipulation as well as {HandlerList#dispatch calling handlers}.
|
106
|
+
#
|
107
|
+
# @return [HandlerList]
|
108
|
+
# @see HandlerList
|
109
|
+
# @since 2.0.0
|
110
|
+
attr_reader :handlers
|
111
|
+
|
112
|
+
# The bot's modes.
|
113
|
+
#
|
114
|
+
# @return [Array<String>]
|
115
|
+
# @since 2.0.0
|
116
|
+
attr_reader :modes
|
117
|
+
|
118
|
+
# @group Helper methods
|
119
|
+
|
120
|
+
# Define helper methods in the context of the bot.
|
121
|
+
#
|
122
|
+
# @yield Expects a block containing method definitions
|
123
|
+
# @return [void]
|
124
|
+
def helpers(&b)
|
125
|
+
@callback.instance_eval(&b)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Since Cinch uses threads, all handlers can be run
|
129
|
+
# simultaneously, even the same handler multiple times. This also
|
130
|
+
# means, that your code has to be thread-safe. Most of the time,
|
131
|
+
# this is not a problem, but if you are accessing stored data, you
|
132
|
+
# will most likely have to synchronize access to it. Instead of
|
133
|
+
# managing all mutexes yourself, Cinch provides a synchronize
|
134
|
+
# method, which takes a name and block.
|
135
|
+
#
|
136
|
+
# Synchronize blocks with the same name share the same mutex,
|
137
|
+
# which means that only one of them will be executed at a time.
|
138
|
+
#
|
139
|
+
# @param [String, Symbol] name a name for the synchronize block.
|
140
|
+
# @return [void]
|
141
|
+
# @yield
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# configure do |c|
|
145
|
+
# …
|
146
|
+
# @i = 0
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# on :channel, /^start counting!/ do
|
150
|
+
# synchronize(:my_counter) do
|
151
|
+
# 10.times do
|
152
|
+
# val = @i
|
153
|
+
# # at this point, another thread might've incremented :i already.
|
154
|
+
# # this thread wouldn't know about it, though.
|
155
|
+
# @i = val + 1
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
def synchronize(name, &block)
|
160
|
+
# Must run the default block +/ fetch in a thread safe way in order to
|
161
|
+
# ensure we always get the same mutex for a given name.
|
162
|
+
semaphore = @semaphores_mutex.synchronize { @semaphores[name] }
|
163
|
+
semaphore.synchronize(&block)
|
164
|
+
end
|
165
|
+
|
166
|
+
# @endgroup
|
167
|
+
|
168
|
+
# @group Events & Plugins
|
169
|
+
|
170
|
+
# Registers a handler.
|
171
|
+
#
|
172
|
+
# @param [String, Symbol, Integer] event the event to match. For a
|
173
|
+
# list of available events, check the {file:docs/events.md Events
|
174
|
+
# documentation}.
|
175
|
+
#
|
176
|
+
# @param [Regexp, Pattern, String] regexp every message of the
|
177
|
+
# right event will be checked against this argument and the event
|
178
|
+
# will only be called if it matches
|
179
|
+
#
|
180
|
+
# @param [Array<Object>] args Arguments that should be passed to
|
181
|
+
# the block, additionally to capture groups of the regexp.
|
182
|
+
#
|
183
|
+
# @yieldparam [Array<String>] args each capture group of the regex will
|
184
|
+
# be one argument to the block.
|
185
|
+
#
|
186
|
+
# @return [Handler] The handlers that have been registered
|
187
|
+
def on(event, regexp = //, *args, &block)
|
188
|
+
event = event.to_s.to_sym
|
189
|
+
|
190
|
+
pattern = case regexp
|
191
|
+
when Pattern
|
192
|
+
regexp
|
193
|
+
when Regexp
|
194
|
+
Pattern.new(nil, regexp, nil)
|
195
|
+
else
|
196
|
+
if event == :ctcp
|
197
|
+
Pattern.generate(:ctcp, regexp)
|
198
|
+
else
|
199
|
+
Pattern.new(/^/, /#{Regexp.escape(regexp.to_s)}/, /$/)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
handler = Handler.new(self, event, pattern, {args: args, execute_in_callback: true}, &block)
|
204
|
+
@handlers.register(handler)
|
205
|
+
|
206
|
+
handler
|
207
|
+
end
|
208
|
+
|
209
|
+
# @endgroup
|
210
|
+
# @group Bot Control
|
211
|
+
|
212
|
+
# This method is used to set a bot's options. It indeed does
|
213
|
+
# nothing else but yielding {Bot#config}, but it makes for a nice DSL.
|
214
|
+
#
|
215
|
+
# @yieldparam [Struct] config the bot's config
|
216
|
+
# @return [void]
|
217
|
+
def configure
|
218
|
+
yield @config
|
219
|
+
end
|
220
|
+
|
221
|
+
# Disconnects from the server.
|
222
|
+
#
|
223
|
+
# @param [String] message The quit message to send while quitting
|
224
|
+
# @return [void]
|
225
|
+
def quit(message = nil)
|
226
|
+
@quitting = true
|
227
|
+
command = message ? "QUIT :#{message}" : "QUIT"
|
228
|
+
|
229
|
+
@irc.send command
|
230
|
+
end
|
231
|
+
|
232
|
+
# Connects the bot to a server.
|
233
|
+
#
|
234
|
+
# @param [Boolean] plugins Automatically register plugins from
|
235
|
+
# `@config.plugins.plugins`?
|
236
|
+
# @return [void]
|
237
|
+
def start(plugins = true)
|
238
|
+
@reconnects = 0
|
239
|
+
@plugins.register_plugins(@config.plugins.plugins) if plugins
|
240
|
+
|
241
|
+
loop do
|
242
|
+
@user_list.each do |user|
|
243
|
+
user.in_whois = false
|
244
|
+
user.unsync_all
|
245
|
+
end # reset state of all users
|
246
|
+
|
247
|
+
@channel_list.each do |channel|
|
248
|
+
channel.unsync_all
|
249
|
+
end # reset state of all channels
|
250
|
+
|
251
|
+
@channels = [] # reset list of channels the bot is in
|
252
|
+
|
253
|
+
@join_handler&.unregister
|
254
|
+
@join_timer&.stop
|
255
|
+
|
256
|
+
join_lambda = lambda { @config.channels.each { |channel| Channel(channel).join } }
|
257
|
+
|
258
|
+
if @config.delay_joins.is_a?(Symbol)
|
259
|
+
@join_handler = join_handler = on(@config.delay_joins) {
|
260
|
+
join_handler.unregister
|
261
|
+
join_lambda.call
|
262
|
+
}
|
263
|
+
else
|
264
|
+
@join_timer = Timer.new(self, interval: @config.delay_joins, shots: 1) {
|
265
|
+
join_lambda.call
|
266
|
+
}
|
267
|
+
end
|
268
|
+
|
269
|
+
@modes = []
|
270
|
+
|
271
|
+
@loggers.info "Connecting to #{@config.server}:#{@config.port}"
|
272
|
+
@irc = IRC.new(self)
|
273
|
+
@irc.start
|
274
|
+
|
275
|
+
if @config.reconnect && !@quitting
|
276
|
+
# double the delay for each unsuccesful reconnection attempt
|
277
|
+
if @last_connection_was_successful
|
278
|
+
@reconnects = 0
|
279
|
+
@last_connection_was_successful = false
|
280
|
+
else
|
281
|
+
@reconnects += 1
|
282
|
+
end
|
283
|
+
|
284
|
+
# Throttle reconnect attempts
|
285
|
+
wait = 2**@reconnects
|
286
|
+
wait = @config.max_reconnect_delay if wait > @config.max_reconnect_delay
|
287
|
+
@loggers.info "Waiting #{wait} seconds before reconnecting"
|
288
|
+
start_time = Time.now
|
289
|
+
while !@quitting && (Time.now - start_time) < wait
|
290
|
+
sleep 1
|
291
|
+
end
|
292
|
+
end
|
293
|
+
break unless @config.reconnect && !@quitting
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
# @endgroup
|
298
|
+
# @group Channel Control
|
299
|
+
|
300
|
+
# Join a channel.
|
301
|
+
#
|
302
|
+
# @param [String, Channel] channel either the name of a channel or a {Channel} object
|
303
|
+
# @param [String] key optionally the key of the channel
|
304
|
+
# @return [Channel] The joined channel
|
305
|
+
# @see Channel#join
|
306
|
+
def join(channel, key = nil)
|
307
|
+
channel = Channel(channel)
|
308
|
+
channel.join(key)
|
309
|
+
|
310
|
+
channel
|
311
|
+
end
|
312
|
+
|
313
|
+
# Part a channel.
|
314
|
+
#
|
315
|
+
# @param [String, Channel] channel either the name of a channel or a {Channel} object
|
316
|
+
# @param [String] reason an optional reason/part message
|
317
|
+
# @return [Channel] The channel that was left
|
318
|
+
# @see Channel#part
|
319
|
+
def part(channel, reason = nil)
|
320
|
+
channel = Channel(channel)
|
321
|
+
channel.part(reason)
|
322
|
+
|
323
|
+
channel
|
324
|
+
end
|
325
|
+
|
326
|
+
# @endgroup
|
327
|
+
|
328
|
+
# @return [Boolean] True if the bot reports ISUPPORT violations as
|
329
|
+
# exceptions.
|
330
|
+
def strict?
|
331
|
+
@config.strictness == :strict
|
332
|
+
end
|
333
|
+
|
334
|
+
# @yield
|
335
|
+
def initialize(&b)
|
336
|
+
@config = Configuration::Bot.new
|
337
|
+
|
338
|
+
@loggers = LoggerList.new
|
339
|
+
@loggers << Logger::FormattedLogger.new($stderr, level: @config.default_logger_level)
|
340
|
+
@handlers = HandlerList.new
|
341
|
+
@semaphores_mutex = Mutex.new
|
342
|
+
@semaphores = Hash.new { |h, k| h[k] = Mutex.new }
|
343
|
+
@callback = Callback.new(self)
|
344
|
+
@channels = []
|
345
|
+
@quitting = false
|
346
|
+
@modes = []
|
347
|
+
|
348
|
+
@user_list = UserList.new(self)
|
349
|
+
@channel_list = ChannelList.new(self)
|
350
|
+
@plugins = PluginList.new(self)
|
351
|
+
|
352
|
+
@join_handler = nil
|
353
|
+
@join_timer = nil
|
354
|
+
|
355
|
+
super(nil, self)
|
356
|
+
instance_eval(&b) if b
|
357
|
+
end
|
358
|
+
|
359
|
+
# @since 2.0.0
|
360
|
+
# @return [self]
|
361
|
+
# @api private
|
362
|
+
def bot
|
363
|
+
# This method is needed for the Helpers interface
|
364
|
+
self
|
365
|
+
end
|
366
|
+
|
367
|
+
# Sets a mode on the bot.
|
368
|
+
#
|
369
|
+
# @param [String] mode
|
370
|
+
# @return [void]
|
371
|
+
# @since 2.0.0
|
372
|
+
# @see Bot#modes
|
373
|
+
# @see Bot#unset_mode
|
374
|
+
def set_mode(mode)
|
375
|
+
@modes << mode unless @modes.include?(mode)
|
376
|
+
@irc.send "MODE #{nick} +#{mode}"
|
377
|
+
end
|
378
|
+
|
379
|
+
# Unsets a mode on the bot.
|
380
|
+
#
|
381
|
+
# @param [String] mode
|
382
|
+
# @return [void]
|
383
|
+
# @since 2.0.0
|
384
|
+
def unset_mode(mode)
|
385
|
+
@modes.delete(mode)
|
386
|
+
@irc.send "MODE #{nick} -#{mode}"
|
387
|
+
end
|
388
|
+
|
389
|
+
# @since 2.0.0
|
390
|
+
def modes=(modes)
|
391
|
+
(@modes - modes).each do |mode|
|
392
|
+
unset_mode(mode)
|
393
|
+
end
|
394
|
+
|
395
|
+
(modes - @modes).each do |mode|
|
396
|
+
set_mode(mode)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
# Used for updating the bot's nick from within the IRC parser.
|
401
|
+
#
|
402
|
+
# @param [String] nick
|
403
|
+
# @api private
|
404
|
+
# @return [String]
|
405
|
+
def set_nick(nick)
|
406
|
+
@name = nick
|
407
|
+
end
|
408
|
+
|
409
|
+
# The bot's nickname.
|
410
|
+
# @overload nick=(new_nick)
|
411
|
+
# @raise [Exceptions::NickTooLong] Raised if the bot is
|
412
|
+
# operating in {#strict? strict mode} and the new nickname is
|
413
|
+
# too long
|
414
|
+
# @return [String]
|
415
|
+
# @overload nick
|
416
|
+
# @return [String]
|
417
|
+
# @return [String]
|
418
|
+
def nick
|
419
|
+
@name
|
420
|
+
end
|
421
|
+
|
422
|
+
def nick=(new_nick)
|
423
|
+
if new_nick.size > @irc.isupport["NICKLEN"] && strict?
|
424
|
+
raise Exceptions::NickTooLong, new_nick
|
425
|
+
end
|
426
|
+
@config.nick = new_nick
|
427
|
+
@irc.send "NICK #{new_nick}"
|
428
|
+
end
|
429
|
+
|
430
|
+
# Gain oper privileges.
|
431
|
+
#
|
432
|
+
# @param [String] password
|
433
|
+
# @param [String] user The username to use. Defaults to the bot's
|
434
|
+
# nickname
|
435
|
+
# @since 2.1.0
|
436
|
+
# @return [void]
|
437
|
+
def oper(password, user = nil)
|
438
|
+
user ||= nick
|
439
|
+
@irc.send "OPER #{user} #{password}"
|
440
|
+
end
|
441
|
+
|
442
|
+
# Try to create a free nick, first by cycling through all
|
443
|
+
# available alternatives and then by appending underscores.
|
444
|
+
#
|
445
|
+
# @param [String] base The base nick to start trying from
|
446
|
+
# @api private
|
447
|
+
# @return [String]
|
448
|
+
# @since 2.0.0
|
449
|
+
def generate_next_nick!(base = nil)
|
450
|
+
nicks = @config.nicks || []
|
451
|
+
|
452
|
+
if base
|
453
|
+
# if `base` is not in our list of nicks to try, assume that it's
|
454
|
+
# custom and just append an underscore
|
455
|
+
if !nicks.include?(base)
|
456
|
+
new_nick = base + "_"
|
457
|
+
else
|
458
|
+
# if we have a base, try the next nick or append an
|
459
|
+
# underscore if no more nicks are left
|
460
|
+
new_index = nicks.index(base) + 1
|
461
|
+
new_nick = nicks[new_index] || base + "_"
|
462
|
+
end
|
463
|
+
else
|
464
|
+
# if we have no base, try the first possible nick
|
465
|
+
new_nick = @config.nicks ? @config.nicks.first : @config.nick
|
466
|
+
end
|
467
|
+
|
468
|
+
@config.nick = new_nick
|
469
|
+
end
|
470
|
+
|
471
|
+
# @return [String]
|
472
|
+
def inspect
|
473
|
+
"#<Bot nick=#{@name.inspect}>"
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# @api private
|
5
|
+
# @since 2.0.0
|
6
|
+
# @version 1.1.0
|
7
|
+
# @note In prior versions, this class was called CacheManager
|
8
|
+
class CachedList
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
def initialize(bot)
|
12
|
+
@bot = bot
|
13
|
+
@cache = {}
|
14
|
+
@mutex = Mutex.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def each(&block)
|
18
|
+
@cache.each_value(&block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cinch
|
4
|
+
# Class used for encapsulating handlers to prevent them from
|
5
|
+
# overwriting instance variables in {Bot}
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
class Callback
|
9
|
+
include Helpers
|
10
|
+
|
11
|
+
# @return [Bot]
|
12
|
+
attr_reader :bot
|
13
|
+
def initialize(bot)
|
14
|
+
@bot = bot
|
15
|
+
end
|
16
|
+
|
17
|
+
# (see Bot#synchronize)
|
18
|
+
def synchronize(name, &block)
|
19
|
+
@bot.synchronize(name, &block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|