Class: Cinch::Bot
- Inherits:
-
Object
- Object
- Cinch::Bot
- Defined in:
- lib/cinch/bot.rb
Instance Attribute Summary collapse
- #channel_manager ⇒ ChannelManager readonly
-
#channels ⇒ Array<Channel>
readonly
All channels the bot currently is in.
- #config ⇒ Config readonly
- #handler_threads ⇒ Array<Thread> readonly private
-
#host ⇒ String
readonly
The bot’s hostname.
- #irc ⇒ IRC readonly
- #last_connection_was_successful ⇒ Boolean private
- #logger ⇒ Logger
- #mask ⇒ Mask readonly
-
#nick ⇒ String
The bot’s nickname.
-
#plugins ⇒ Array<Plugin>
readonly
All registered plugins.
-
#quitting ⇒ Boolean
readonly
Whether the bot is in the process of disconnecting.
- #realname ⇒ String readonly
- #signed_on_at ⇒ Time readonly
- #user ⇒ String readonly
- #user_manager ⇒ UserManager readonly
Helper methods collapse
-
#Channel(channel) ⇒ Channel
Helper method for turning a String into a #Channel object.
-
#halt ⇒ void
Stop execution of the current #on handler.
-
#helpers { ... } ⇒ void
Define helper methods in the context of the bot.
-
#synchronize(name) { ... } ⇒ void
Since Cinch uses threads, all handlers can be run simultaneously, even the same handler multiple times.
-
#User(user) ⇒ User
Helper method for turning a String into an #User object.
Sending messages collapse
-
#action(recipient, text) ⇒ void
Invoke an action (/me) in/to a recipient (a channel or user).
-
#msg(recipient, text, notice = false) ⇒ void
(also: #privmsg, #send)
Sends a PRIVMSG to a recipient (a channel or user).
-
#notice(recipient, text) ⇒ void
Sends a NOTICE to a recipient (a channel or user).
-
#raw(command) ⇒ void
Sends a raw message to the server.
-
#safe_action(recipient, text) ⇒ void
Like #action, but remove any non-printable characters from ‘text`.
-
#safe_msg(recipient, text) ⇒ void
(also: #safe_privmsg, #safe_send)
Like #msg, but remove any non-printable characters from ‘text`.
-
#safe_notice(recipient, text) ⇒ void
Like #safe_msg but for notices.
Events & Plugins collapse
- #dispatch(event, msg = nil, *arguments) ⇒ void
-
#on(event, regexps = [], *args) {|*args| ... } ⇒ void
Registers a handler.
-
#register_plugin(plugin) ⇒ void
Registers a plugin.
-
#register_plugins ⇒ void
Register all plugins from ‘@config.plugins.plugins`.
Bot Control collapse
-
#configure {|config| ... } ⇒ void
This method is used to set a bot’s options.
-
#quit(message = nil) ⇒ void
Disconnects from the server.
-
#start(plugins = true) ⇒ void
Connects the bot to a server.
Channel Control collapse
-
#join(channel, key = nil) ⇒ void
Join a channel.
-
#part(channel, reason = nil) ⇒ void
Part a channel.
Instance Method Summary collapse
-
#debug(msg) ⇒ void
This method can be used by plugins to log custom messages.
-
#generate_next_nick(base = nil) ⇒ Object
private
Try to create a free nick, first by cycling through all available alternatives and then by appending underscores.
-
#initialize { ... } ⇒ Bot
constructor
A new instance of Bot.
-
#secure? ⇒ Boolean
True if the bot is using SSL to connect to the server.
-
#strict? ⇒ Boolean
True if the bot reports ISUPPORT violations as exceptions.
-
#unknown? ⇒ false
This method is only provided in order to give Bot and User a common interface.
Constructor Details
#initialize { ... } ⇒ Bot
Returns a new instance of Bot.
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'lib/cinch/bot.rb', line 481 def initialize(&b) @logger = Logger::FormattedLogger.new($stderr) @events = {} @config = OpenStruct.new({ :server => "localhost", :port => 6667, :ssl => OpenStruct.new({ :use => false, :verify => false, :client_cert => nil, :ca_path => "/etc/ssl/certs", }), :password => nil, :nick => "cinch", :nicks => nil, :realname => "cinch", :user => "cinch", :verbose => true, :messages_per_second => 0.5, :server_queue_size => 10, :strictness => :forgiving, :message_split_start => '... ', :message_split_end => ' ...', :max_messages => nil, :plugins => OpenStruct.new({ :plugins => [], :prefix => /^!/, :suffix => nil, :options => Hash.new {|h,k| h[k] = {}}, }), :channels => [], :encoding => :irc, :reconnect => true, :local_host => nil, :timeouts => OpenStruct.new({ :read => 240, :connect => 10, }), :ping_interval => 120, }) @semaphores_mutex = Mutex.new @semaphores = Hash.new { |h,k| h[k] = Mutex.new } @plugins = [] @callback = Callback.new(self) @channels = [] @handler_threads = [] @quitting = false @user_manager = UserManager.new(self) @channel_manager = ChannelManager.new(self) instance_eval(&b) if block_given? on :connect do bot.config.channels.each do |channel| bot.join channel end end end |
Instance Attribute Details
#channel_manager ⇒ ChannelManager (readonly)
65 66 67 |
# File 'lib/cinch/bot.rb', line 65 def channel_manager @channel_manager end |
#channels ⇒ Array<Channel> (readonly)
Returns All channels the bot currently is in.
44 45 46 |
# File 'lib/cinch/bot.rb', line 44 def channels @channels end |
#config ⇒ Config (readonly)
38 39 40 |
# File 'lib/cinch/bot.rb', line 38 def config @config end |
#handler_threads ⇒ Array<Thread> (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
59 60 61 |
# File 'lib/cinch/bot.rb', line 59 def handler_threads @handler_threads end |
#host ⇒ String (readonly)
Returns the bot’s hostname.
46 47 48 |
# File 'lib/cinch/bot.rb', line 46 def host @host end |
#last_connection_was_successful ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
68 69 70 |
# File 'lib/cinch/bot.rb', line 68 def last_connection_was_successful @last_connection_was_successful end |
#nick=(new_nick) ⇒ String #nick ⇒ String
The bot’s nickname.
551 552 553 |
# File 'lib/cinch/bot.rb', line 551 def nick @nick end |
#plugins ⇒ Array<Plugin> (readonly)
Returns All registered plugins.
56 57 58 |
# File 'lib/cinch/bot.rb', line 56 def plugins @plugins end |
#quitting ⇒ Boolean (readonly)
Returns whether the bot is in the process of disconnecting.
61 62 63 |
# File 'lib/cinch/bot.rb', line 61 def quitting @quitting end |
#realname ⇒ String (readonly)
52 53 54 |
# File 'lib/cinch/bot.rb', line 52 def realname @realname end |
#signed_on_at ⇒ Time (readonly)
54 55 56 |
# File 'lib/cinch/bot.rb', line 54 def signed_on_at @signed_on_at end |
#user_manager ⇒ UserManager (readonly)
63 64 65 |
# File 'lib/cinch/bot.rb', line 63 def user_manager @user_manager end |
Instance Method Details
#action(recipient, text) ⇒ void
This method returns an undefined value.
Invoke an action (/me) in/to a recipient (a channel or user). You should be using Channel#action and User#action instead.
262 263 264 |
# File 'lib/cinch/bot.rb', line 262 def action(recipient, text) raw("PRIVMSG #{recipient} :\001ACTION #{text}\001") end |
#Channel(channel) ⇒ Channel
Helper method for turning a String into a #Channel object.
80 81 82 83 |
# File 'lib/cinch/bot.rb', line 80 def Channel(channel) return channel if channel.is_a?(Channel) @channel_manager.find_ensured(channel) end |
#configure {|config| ... } ⇒ void
This method returns an undefined value.
This method is used to set a bot’s options. It indeed does nothing else but yielding #config, but it makes for a nice DSL.
383 384 385 |
# File 'lib/cinch/bot.rb', line 383 def configure(&block) @callback.instance_exec(@config, &block) end |
#debug(msg) ⇒ void
This method returns an undefined value.
This method can be used by plugins to log custom messages.
470 471 472 |
# File 'lib/cinch/bot.rb', line 470 def debug(msg) @logger.debug(msg) end |
#dispatch(event, msg = nil, *arguments) ⇒ void
This method returns an undefined value.
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/cinch/bot.rb', line 338 def dispatch(event, msg = nil, *arguments) if handlers = find(event, msg) handlers.each do |handler| regexps, args, block = *handler # calling Message#match multiple times is not a problem # because we cache the result if msg regexp = regexps.find { |rx| msg.match(rx.to_r(msg), event) } captures = msg.match(regexp.to_r(msg), event).captures else captures = [] end invoke(block, args, msg, captures, arguments) end end end |
#generate_next_nick(base = nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Try to create a free nick, first by cycling through all available alternatives and then by appending underscores.
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 |
# File 'lib/cinch/bot.rb', line 572 def generate_next_nick(base = nil) nicks = @config.nicks || [] if base # if `base` is not in our list of nicks to try, assume that it's # custom and just append an underscore if !nicks.include?(base) return base + "_" else # if we have a base, try the next nick or append an # underscore if no more nicks are left new_index = nicks.index(base) + 1 if nicks[new_index] return nicks[new_index] else return base + "_" end end else # if we have no base, try the first possible nick new_nick = @config.nicks ? @config.nicks.first : @config.nick end end |
#halt ⇒ void
This method returns an undefined value.
Stop execution of the current #on handler.
148 149 150 |
# File 'lib/cinch/bot.rb', line 148 def halt throw :halt end |
#helpers { ... } ⇒ void
This method returns an undefined value.
Define helper methods in the context of the bot.
103 104 105 |
# File 'lib/cinch/bot.rb', line 103 def helpers(&b) Callback.class_eval(&b) end |
#join(channel, key = nil) ⇒ void
This method returns an undefined value.
Join a channel.
452 453 454 |
# File 'lib/cinch/bot.rb', line 452 def join(channel, key = nil) Channel(channel).join(key) end |
#msg(recipient, text, notice = false) ⇒ void Also known as: privmsg, send
This method returns an undefined value.
Sends a PRIVMSG to a recipient (a channel or user). You should be using Channel#send and User#send instead.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/cinch/bot.rb', line 174 def msg(recipient, text, notice = false) text = text.to_s split_start = @config. || "" split_end = @config. || "" command = notice ? "NOTICE" : "PRIVMSG" text.split(/\r\n|\r|\n/).each do |line| maxlength = 510 - (":" + " #{command} " + " :").size maxlength = maxlength - self.mask.to_s.length - recipient.to_s.length maxlength_without_end = maxlength - split_end.bytesize if line.bytesize > maxlength splitted = [] while line.bytesize > maxlength_without_end pos = line.rindex(/\s/, maxlength_without_end) r = pos || maxlength_without_end splitted << line.slice!(0, r) + split_end.tr(" ", "\u00A0") line = split_start.tr(" ", "\u00A0") + line.lstrip end splitted << line splitted[0, (@config. || splitted.size)].each do |string| string.tr!("\u00A0", " ") # clean string from any non-breaking spaces raw("#{command} #{recipient} :#{string}") end else raw("#{command} #{recipient} :#{line}") end end end |
#notice(recipient, text) ⇒ void
This method returns an undefined value.
Sends a NOTICE to a recipient (a channel or user). You should be using Channel#notice and User#notice instead.
217 218 219 |
# File 'lib/cinch/bot.rb', line 217 def notice(recipient, text) msg(recipient, text, true) end |
#on(event, regexps = [], *args) {|*args| ... } ⇒ void
This method returns an undefined value.
Registers a handler.
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/cinch/bot.rb', line 307 def on(event, regexps = [], *args, &block) regexps = [*regexps] regexps = [//] if regexps.empty? event = event.to_sym regexps.map! do |regexp| pattern = case regexp when Pattern regexp when Regexp Pattern.new(nil, regexp, nil) else if event == :ctcp Pattern.new(/^/, /#{Regexp.escape(regexp.to_s)}(?:$| .+)/, nil) else Pattern.new(/^/, /#{Regexp.escape(regexp.to_s)}/, /$/) end end debug "[on handler] Registering handler with pattern `#{pattern.inspect}`, reacting on `#{event}`" pattern end (@events[event] ||= []) << [regexps, args, block] end |
#part(channel, reason = nil) ⇒ void
This method returns an undefined value.
Part a channel.
462 463 464 |
# File 'lib/cinch/bot.rb', line 462 def part(channel, reason = nil) Channel(channel).part(reason) end |
#quit(message = nil) ⇒ void
This method returns an undefined value.
Disconnects from the server.
391 392 393 394 395 |
# File 'lib/cinch/bot.rb', line 391 def quit( = nil) @quitting = true command = ? "QUIT :#{}" : "QUIT" raw command end |
#raw(command) ⇒ void
This method returns an undefined value.
Sends a raw message to the server.
160 161 162 |
# File 'lib/cinch/bot.rb', line 160 def raw(command) @irc.(command) end |
#register_plugin(plugin) ⇒ void
This method returns an undefined value.
Registers a plugin.
371 372 373 |
# File 'lib/cinch/bot.rb', line 371 def register_plugin(plugin) @plugins << plugin.new(self) end |
#register_plugins ⇒ void
This method returns an undefined value.
Register all plugins from ‘@config.plugins.plugins`.
361 362 363 364 365 |
# File 'lib/cinch/bot.rb', line 361 def register_plugins @config.plugins.plugins.each do |plugin| register_plugin(plugin) end end |
#safe_action(recipient, text) ⇒ void
Handle mIRC color codes more gracefully.
This method returns an undefined value.
Like #action, but remove any non-printable characters from ‘text`. The purpose of this method is to send text from untrusted sources, like other users or feeds.
Note: this will break any mIRC color codes embedded in the string.
279 280 281 |
# File 'lib/cinch/bot.rb', line 279 def safe_action(recipient, text) action(recipient, Cinch.filter_string(text)) end |
#safe_msg(recipient, text) ⇒ void Also known as: safe_privmsg, safe_send
Handle mIRC color codes more gracefully.
This method returns an undefined value.
Like #msg, but remove any non-printable characters from ‘text`. The purpose of this method is to send text of untrusted sources, like other users or feeds.
Note: this will break any mIRC color codes embedded in the string.
234 235 236 |
# File 'lib/cinch/bot.rb', line 234 def safe_msg(recipient, text) msg(recipient, Cinch.filter_string(text)) end |
#safe_notice(recipient, text) ⇒ void
Handle mIRC color codes more gracefully.
This method returns an undefined value.
Like #safe_msg but for notices.
249 250 251 |
# File 'lib/cinch/bot.rb', line 249 def safe_notice(recipient, text) msg(recipient, Cinch.filter_string(text), true) end |
#secure? ⇒ Boolean
Returns True if the bot is using SSL to connect to the server.
598 599 600 |
# File 'lib/cinch/bot.rb', line 598 def secure? @config[:ssl] == true || (@config[:ssl].is_a?(Hash) && @config[:ssl][:use]) end |
#start(plugins = true) ⇒ void
Connects the bot to a server.
Connects the bot to a server.
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 |
# File 'lib/cinch/bot.rb', line 407 def start(plugins = true) @reconnects = 0 register_plugins if plugins begin @user_manager.each do |user| user.in_whois = false user.unsync_all end # reset state of all users @channel_manager.each do |channel| channel.unsync_all end # reset state of all channels @logger.debug "Connecting to #{@config.server}:#{@config.port}" @irc = IRC.new(self) @irc.connect if @config.reconnect && !@quitting # double the delay for each unsuccesful reconnection attempt if @last_connection_was_successful @reconnects = 0 @last_connection_was_successful = false else @reconnects += 1 end # Sleep for a few seconds before reconnecting to prevent being # throttled by the IRC server wait = 2**@reconnects @logger.debug "Waiting #{wait} seconds before reconnecting" sleep wait end end while @config.reconnect and not @quitting end |
#strict? ⇒ Boolean
Returns True if the bot reports ISUPPORT violations as exceptions.
476 477 478 |
# File 'lib/cinch/bot.rb', line 476 def strict? @config.strictness == :strict end |
#synchronize(name) { ... } ⇒ void
This method returns an undefined value.
Since Cinch uses threads, all handlers can be run simultaneously, even the same handler multiple times. This also means, that your code has to be thread-safe. Most of the time, this is not a problem, but if you are accessing stored data, you will most likely have to synchronize access to it. Instead of managing all mutexes yourself, Cinch provides a synchronize method, which takes a name and block.
Synchronize blocks with the same name share the same mutex, which means that only one of them will be executed at a time.
138 139 140 141 142 143 |
# File 'lib/cinch/bot.rb', line 138 def synchronize(name, &block) # Must run the default block +/ fetch in a thread safe way in order to # ensure we always get the same mutex for a given name. semaphore = @semaphores_mutex.synchronize { @semaphores[name] } semaphore.synchronize(&block) end |
#unknown? ⇒ false
This method is only provided in order to give Bot and User a common interface.
607 608 609 |
# File 'lib/cinch/bot.rb', line 607 def unknown? false end |