Class: Cinch::Bot

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

Overview

Version:

  • 2.0.0

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, #Sanitize, #Target, #Timer, #Unformat, #User, #debug, #error, #exception, #fatal, #incoming, #info, #log, #outgoing, #rescue_exception, sanitize, #warn

Methods inherited from User

#attr, #authed?, #dcc_send, #end_of_whois, #mask, #match, #monitor, #refresh, #to_s, #unmonitor, #unsync_all, #update_nick

Methods included from Syncable

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

Methods inherited from Target

#<=>, #action, #concretize, #ctcp, #eql?, #notice, #safe_action, #safe_notice, #safe_privmsg, #safe_send, #send

Constructor Details

#initialize { ... } ⇒ Bot

Returns a new instance of Bot.

Yields:



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/cinch/bot.rb', line 343

def initialize(&b)
  @config = Configuration::Bot.new

  @loggers = LoggerList.new
  @loggers << Logger::FormattedLogger.new($stderr, level: @config.default_logger_level)
  @handlers = HandlerList.new
  @semaphores_mutex = Mutex.new
  @semaphores       = Hash.new { |h, k| h[k] = Mutex.new }
  @callback         = Callback.new(self)
  @channels         = []
  @quitting         = false
  @quit_queue       = Queue.new
  @modes            = []

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

  @join_handler = nil
  @join_timer   = nil

  @last_connection_was_successful = false
  @last_connection_error = nil

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

Instance Attribute Details

#callbackCallback (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:



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

def callback
  @callback
end

#channel_listChannelList (readonly)

Returns All channels the bot knows about.

Returns:

See Also:

Since:

  • 1.1.0



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

def channel_list
  @channel_list
end

#channelsArray<Channel> (readonly)

Returns All channels the bot currently is in.

Returns:

  • (Array<Channel>)

    All channels the bot currently is in



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

def channels
  @channels
end

#configConfiguration::Bot (readonly)

Returns:

Version:

  • 2.0.0



61
62
63
# File 'lib/cinch/bot.rb', line 61

def config
  @config
end

#handlersHandlerList (readonly)

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

Returns:

See Also:

Since:

  • 2.0.0



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

def handlers
  @handlers
end

#ircIRC (readonly)

The underlying IRC connection

Returns:



66
67
68
# File 'lib/cinch/bot.rb', line 66

def irc
  @irc
end

#last_connection_errorStandardError?

The exception that occurred in the last connection.

Returns:

  • (StandardError, nil)

Since:

  • 2.4.0



106
107
108
# File 'lib/cinch/bot.rb', line 106

def last_connection_error
  @last_connection_error
end

#last_connection_was_successfulBoolean

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.

Whether the last connection was successful.

Returns:

  • (Boolean)


101
102
103
# File 'lib/cinch/bot.rb', line 101

def last_connection_was_successful
  @last_connection_was_successful
end

#loggersLoggerList

The logger list containing all loggers

Returns:

Since:

  • 2.0.0



72
73
74
# File 'lib/cinch/bot.rb', line 72

def loggers
  @loggers
end

#modesArray<String>

The bot’s modes.

Returns:

Since:

  • 2.0.0



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

def modes
  @modes
end

#nick=(new_nick) ⇒ String #nickString

The bot’s nickname.

Overloads:

Returns:



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

def nick
  @nick
end

#pluginsPluginList (readonly)

Returns The PluginList giving access to (un)loading plugins.

Returns:

Version:

  • 2.0.0



80
81
82
# File 'lib/cinch/bot.rb', line 80

def plugins
  @plugins
end

#quit_queueQueue (readonly)

Returns queue for gentle process of disconnecting.

Returns:

  • (Queue)

    queue for gentle process of disconnecting



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

def quit_queue
  @quit_queue
end

#quittingBoolean (readonly)

Returns whether the bot is in the process of disconnecting.

Returns:

  • (Boolean)

    whether the bot is in the process of disconnecting



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

def quitting
  @quitting
end

#user_listUserList (readonly)

Returns All users the bot knows about.

Returns:

See Also:

Since:

  • 1.1.0



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

def user_list
  @user_list
end

Instance Method Details

#botself

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



374
375
376
377
# File 'lib/cinch/bot.rb', line 374

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



225
226
227
# File 'lib/cinch/bot.rb', line 225

def configure
  yield @config
end

#generate_next_nick!(base = nil) ⇒ String

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



462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/cinch/bot.rb', line 462

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
      new_nick = nicks[new_index] || base + '_'
    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



132
133
134
# File 'lib/cinch/bot.rb', line 132

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

#inspectString

Returns:



485
486
487
# File 'lib/cinch/bot.rb', line 485

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

#join(channel, key = nil) ⇒ Channel

Join a channel.

Parameters:

Returns:

See Also:



314
315
316
317
318
319
# File 'lib/cinch/bot.rb', line 314

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

  channel
end

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

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 (Array<String>)

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

Returns:

  • (Handler)

    The handlers that have been registered



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/cinch/bot.rb', line 195

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)

  handler
end

#oper(password, user = nil)

This method returns an undefined value.

Gain oper privileges.

Parameters:

  • password (String)
  • user (String) (defaults to: nil)

    The username to use. Defaults to the bot’s nickname

Since:

  • 2.1.0



450
451
452
453
# File 'lib/cinch/bot.rb', line 450

def oper(password, user = nil)
  user ||= nick
  @irc.send "OPER #{user} #{password}"
end

#part(channel, reason = nil) ⇒ Channel

Part a channel.

Parameters:

Returns:

  • (Channel)

    The channel that was left

See Also:



327
328
329
330
331
332
# File 'lib/cinch/bot.rb', line 327

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



233
234
235
236
# File 'lib/cinch/bot.rb', line 233

def quit(message = nil)
  @quitting = true
  @quit_queue.push([:quit, message])
end

#set_mode(mode)

This method returns an undefined value.

Sets a mode on the bot.

Parameters:

See Also:

Since:

  • 2.0.0



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

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

#set_nick(nick) ⇒ String

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:



417
418
419
# File 'lib/cinch/bot.rb', line 417

def set_nick(nick)
  @name = nick
end

#start(plugins = true) ⇒ Boolean

Connects the bot to a server.

Parameters:

  • plugins (Boolean) (defaults to: true)

    Automatically register plugins from @config.plugins.plugins?

Returns:

  • (Boolean)

    Whether the connection was successful.



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
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/cinch/bot.rb', line 243

def start(plugins = true)
  @last_connection_was_successful = false
  @last_connection_error = nil

  @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(&:unsync_all) # reset state of all channels

    @channels = [] # reset list of channels the bot is in

    @join_handler&.unregister
    @join_timer&.stop

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

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

    @modes = []

    @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 && !@quitting

  @last_connection_was_successful
end

#strict?Boolean

Returns True if the bot reports ISUPPORT violations as exceptions.

Returns:

  • (Boolean)

    True if the bot reports ISUPPORT violations as exceptions.



338
339
340
# File 'lib/cinch/bot.rb', line 338

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|
  

Parameters:

  • name (String, Symbol)

    a name for the synchronize block.

Yields:



167
168
169
170
171
172
# File 'lib/cinch/bot.rb', line 167

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



396
397
398
399
# File 'lib/cinch/bot.rb', line 396

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