Class: Cinch::Bot

Inherits:
User show all
Includes:
Helpers
Defined in:
lib/cinch/bot.rb

Overview

Version:

Instance Attribute Summary (collapse)

Attributes inherited from User

#authname, #away, #data, #host, #idle, #in_whois, #last_nick, #monitored, #online, #realname, #secure, #signed_on_at, #synced, #unknown, #user

Attributes inherited from Target

#name

Helper methods (collapse)

Events & Plugins (collapse)

Bot Control (collapse)

Channel Control (collapse)

Instance Method Summary (collapse)

Methods included from Helpers

#Channel, #Format, #Target, #Timer, #User, #debug, #error, #exception, #fatal, #incoming, #info, #log, #outgoing, #rescue_exception, #warn

Methods inherited from User

#attr, #authed?, #dcc_send, #end_of_whois, #mask, #match, #method_missing, #monitor, #online?, #respond_to?, #secure?, #to_s, #unknown?, #unmonitor, #unsync_all, #update_nick, #whois

Methods included from Syncable

#attr, #mark_as_synced, #sync, #synced?, #unsync, #unsync_all, #wait_until_synced

Methods inherited from Target

#<=>, #action, #concretize, #ctcp, #eql?, #msg, #notice, #safe_action, #safe_msg, #safe_notice

Constructor Details

- (Bot) initialize { ... }

A new instance of Bot

Yields:



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
# File 'lib/cinch/bot.rb', line 338

def initialize(&b)
  @loggers = LoggerList.new
  @loggers << Logger::FormattedLogger.new($stderr)

  @config           = Configuration::Bot.new
  @handlers         = HandlerList.new
  @semaphores_mutex = Mutex.new
  @semaphores       = Hash.new { |h, k| h[k] = Mutex.new }
  @callback         = Callback.new(self)
  @channels         = []
  @quitting         = false
  @modes            = []

  @user_list    = UserList.new(self)
  @channel_list = ChannelList.new(self)
  @plugins      = PluginList.new(self)

  @join_handler = nil
  @join_timer   = nil

  super(nil, self)
  instance_eval(&b) if block_given?
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Cinch::User

Instance Attribute Details

- (Callback) callback (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.

Returns:



103
104
105
# File 'lib/cinch/bot.rb', line 103

def callback
  @callback
end

- (ChannelList) channel_list (readonly)

All channels the bot knows about.

Returns:

See Also:

Since:

  • 1.1.0



95
96
97
# File 'lib/cinch/bot.rb', line 95

def channel_list
  @channel_list
end

- (Array<Channel>) channels (readonly)

All channels the bot currently is in

Returns:

  • (Array<Channel>)

    All channels the bot currently is in



77
78
79
# File 'lib/cinch/bot.rb', line 77

def channels
  @channels
end

- (Configuration::Bot) config (readonly)

Returns:

Version:

  • 2.0.0



63
64
65
# File 'lib/cinch/bot.rb', line 63

def config
  @config
end

- (HandlerList) handlers (readonly)

The HandlerList, providing access to all registered plugins and plugin manipulation as well as calling handlers.

Returns:

See Also:

Since:

  • 2.0.0



111
112
113
# File 'lib/cinch/bot.rb', line 111

def handlers
  @handlers
end

- (IRC) irc (readonly)

The underlying IRC connection

Returns:



68
69
70
# File 'lib/cinch/bot.rb', line 68

def irc
  @irc
end

- (Boolean) last_connection_was_successful

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.

Returns:

  • (Boolean)


99
100
101
# File 'lib/cinch/bot.rb', line 99

def last_connection_was_successful
  @last_connection_was_successful
end

- (LoggerList) loggers

The logger list containing all loggers

Returns:

Since:

  • 2.0.0



74
75
76
# File 'lib/cinch/bot.rb', line 74

def loggers
  @loggers
end

- (Array<String>) modes

The bot’s modes.

Returns:

Since:

  • 2.0.0



117
118
119
# File 'lib/cinch/bot.rb', line 117

def modes
  @modes
end

- (String) nick=(new_nick) - (String) nick

The bot’s nickname.

Overloads:

Returns:



57
58
59
# File 'lib/cinch/bot.rb', line 57

def nick
  @nick
end

- (PluginList) plugins (readonly)

The PluginList giving access to (un)loading plugins

Returns:

Version:

  • 2.0.0



82
83
84
# File 'lib/cinch/bot.rb', line 82

def plugins
  @plugins
end

- (Boolean) quitting (readonly)

Whether the bot is in the process of disconnecting

Returns:

  • (Boolean)

    whether the bot is in the process of disconnecting



85
86
87
# File 'lib/cinch/bot.rb', line 85

def quitting
  @quitting
end

- (UserList) user_list (readonly)

All users the bot knows about.

Returns:

See Also:

Since:

  • 1.1.0



90
91
92
# File 'lib/cinch/bot.rb', line 90

def user_list
  @user_list
end

Instance Method Details

- (self) bot

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.

Returns:

  • (self)

Since:

  • 2.0.0



365
366
367
368
# File 'lib/cinch/bot.rb', line 365

def bot
  # This method is needed for the Helpers interface
  self
end

- configure {|config| ... }

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.

Yield Parameters:

  • config (Struct)

    the bot’s config



218
219
220
# File 'lib/cinch/bot.rb', line 218

def configure
  yield @config
end

- (String) generate_next_nick!(base = nil)

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.

Parameters:

  • base (String) (defaults to: nil)

    The base nick to start trying from

Returns:

Since:

  • 2.0.0



440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
# File 'lib/cinch/bot.rb', line 440

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)
      new_nick =  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]
        new_nick = nicks[new_index]
      else
        new_nick = base + "_"
      end
    end
  else
    # if we have no base, try the first possible nick
    new_nick = @config.nicks ? @config.nicks.first : @config.nick
  end

  @config.nick = new_nick
end

- helpers { ... }

This method returns an undefined value.

Define helper methods in the context of the bot.

Yields:

  • Expects a block containing method definitions



125
126
127
# File 'lib/cinch/bot.rb', line 125

def helpers(&b)
  @callback.instance_eval(&b)
end

- (String) inspect

Returns:



467
468
469
# File 'lib/cinch/bot.rb', line 467

def inspect
  "#<Bot nick=#{@name.inspect}>"
end

- (Channel) join(channel, key = nil)

Join a channel.

Parameters:

  • channel (String, Channel)

    either the name of a channel or a Channel object

  • key (String) (defaults to: nil)

    optionally the key of the channel

Returns:

See Also:



309
310
311
312
313
314
# File 'lib/cinch/bot.rb', line 309

def join(channel, key = nil)
  channel = Channel(channel)
  channel.join(key)

  channel
end

- (Handler) on(event, regexp = //, *args) {|*args| ... }

Registers a handler.

Parameters:

  • event (String, Symbol, Integer)

    the event to match. For a list of available events, check the Events documentation.

  • regexp (Regexp, Pattern, String) (defaults to: //)

    every message of the right event will be checked against this argument and the event will only be called if it matches

  • *args (Array<Object>)

    Arguments that should be passed to the block, additionally to capture groups of the regexp.

Yield Parameters:

  • *args (String)

    each capture group of the regex will be one argument to the block.

Returns:

  • (Handler)

    The handlers that have been registered



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/cinch/bot.rb', line 188

def on(event, regexp = //, *args, &block)
  event = event.to_s.to_sym

  pattern = case regexp
            when Pattern
              regexp
            when Regexp
              Pattern.new(nil, regexp, nil)
            else
              if event == :ctcp
                Pattern.generate(:ctcp, regexp)
              else
                Pattern.new(/^/, /#{Regexp.escape(regexp.to_s)}/, /$/)
              end
            end

  handler = Handler.new(self, event, pattern, {args: args, execute_in_callback: true}, &block)
  @handlers.register(handler)

  return handler
end

- (Channel) part(channel, reason = nil)

Part a channel.

Parameters:

  • channel (String, Channel)

    either the name of a channel or a Channel object

  • reason (String) (defaults to: nil)

    an optional reason/part message

Returns:

  • (Channel)

    The channel that was left

See Also:



322
323
324
325
326
327
# File 'lib/cinch/bot.rb', line 322

def part(channel, reason = nil)
  channel = Channel(channel)
  channel.part(reason)

  channel
end

- quit(message = nil)

This method returns an undefined value.

Disconnects from the server.

Parameters:

  • message (String) (defaults to: nil)

    The quit message to send while quitting



226
227
228
229
230
231
# File 'lib/cinch/bot.rb', line 226

def quit(message = nil)
  @quitting = true
  command   = message ? "QUIT :#{message}" : "QUIT"

  @irc.send command
end

- set_mode(mode)

This method returns an undefined value.

Sets a mode on the bot.

Parameters:

See Also:

Since:

  • 2.0.0



377
378
379
380
# File 'lib/cinch/bot.rb', line 377

def set_mode(mode)
  @modes << mode unless @modes.include?(mode)
  @irc.send "MODE #{nick} +#{mode}"
end

- (String) set_nick(nick)

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.

Used for updating the bot’s nick from within the IRC parser.

Parameters:

Returns:



408
409
410
# File 'lib/cinch/bot.rb', line 408

def set_nick(nick)
  @name = nick
end

- start(plugins = true)

This method returns an undefined value.

Connects the bot to a server.

Parameters:

  • plugins (Boolean) (defaults to: true)

    Automatically register plugins from @config.plugins.plugins?



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/cinch/bot.rb', line 238

def start(plugins = true)
  @reconnects = 0
  @plugins.register_plugins(@config.plugins.plugins) if plugins

  begin
    @user_list.each do |user|
      user.in_whois = false
      user.unsync_all
    end # reset state of all users

    @channel_list.each do |channel|
      channel.unsync_all
    end # reset state of all channels

    @join_handler.unregister if @join_handler
    @join_timer.stop if @join_timer

    join_lambda = lambda { @config.channels.each { |channel| Channel(channel).join }}

    if @config.delay_joins.is_a?(Symbol)
      @join_handler = join_handler = on(@config.delay_joins) {
        join_handler.unregister
        join_lambda.call
      }
    else
      @join_timer = Timer.new(self, interval: @config.delay_joins, shots: 1) {
        join_lambda.call
      }
    end

    @loggers.info "Connecting to #{@config.server}:#{@config.port}"
    @irc = IRC.new(self)
    @irc.start

    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

      # Throttle reconnect attempts
      wait = 2**@reconnects
      wait = @config.max_reconnect_delay if wait > @config.max_reconnect_delay
      @loggers.info "Waiting #{wait} seconds before reconnecting"
      start_time = Time.now
      while !@quitting && (Time.now - start_time) < wait
        sleep 1
      end
    end
  end while @config.reconnect and not @quitting
end

- (Object) stop



293
294
295
296
297
298
# File 'lib/cinch/bot.rb', line 293

def stop
  # @plugins.each do |plugin|
  #   plugin.storage.save
  #   plugin.storage.unload
  # end
end

- (Boolean) strict?

True if the bot reports ISUPPORT violations as exceptions.

Returns:

  • (Boolean)

    True if the bot reports ISUPPORT violations as exceptions.



333
334
335
# File 'lib/cinch/bot.rb', line 333

def strict?
  @config.strictness == :strict
end

- synchronize(name) { ... }

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.

Examples:

configure do |c|
  
  @i = 0
end

on :channel, /^start counting!/ do
  synchronize(:my_counter) do
    10.times do
      val = @i
      # at this point, another thread might've incremented :i already.
      # this thread wouldn't know about it, though.
      @i = val + 1
    end
  end
end

Parameters:

  • name (String, Symbol)

    a name for the synchronize block.

Yields:



160
161
162
163
164
165
# File 'lib/cinch/bot.rb', line 160

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

- unset_mode(mode)

This method returns an undefined value.

Unsets a mode on the bot.

Parameters:

Since:

  • 2.0.0



387
388
389
390
# File 'lib/cinch/bot.rb', line 387

def unset_mode(mode)
  @modes.delete(mode)
  @irc.send "MODE #{nick} -#{mode}"
end