Class: IRC::Client

Inherits:
Object
  • Object
show all
Includes:
Loggable, Rhuidean
Defined in:
lib/rhuidean/client.rb,
lib/rhuidean/methods.rb

Overview

These methods are shortcuts for sending data to the IRC server. You can use `raw` to do any of them, or even add a string directly to `@sendq` if you really want. I'm sure I haven't thought of everything here.

Direct Known Subclasses

StatefulClient

Defined Under Namespace

Classes: Error

Constant Summary

IRC_RE =

Note that this doesn't match every IRC message, just the ones we care about. It also doesn't match every IRC message in the way we want. We get what we need. The rest is ignored.

Here's a compact version if you need it:

^(?:\:([^\s]+)\s)?(\w+)\s(?:([^\s\:]+)\s)?(?:\:?(.*))?$
/
^              # beginning of string
(?:            # non-capturing group
    \:         # if we have a ':' then we have an origin
    ([^\s]+)   # get the origin without the ':'
    \s         # space after the origin
)?             # close non-capturing group
(\w+)          # must have a command
\s             # and a space after it
(?:            # non-capturing group
    ([^\s\:]+) # a target for the command
    \s         # and a space after it
)?             # close non-capturing group
(?:            # non-capturing group
    \:?        # if we have a ':' then we have freeform text
    (.*)       # get the rest as one string without the ':'
)?             # close non-capturing group
$              # end of string
/x

Constants included from Rhuidean

Rhuidean::VERSION, Rhuidean::V_MAJOR, Rhuidean::V_MINOR, Rhuidean::V_PATCH

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Methods included from Loggable

#log, #log_level=, #logger=

Constructor Details

- (Client) initialize {|_self| ... }

Creates a new IRC::Client object. If there is a block given, passes itself to the block for pretty attribute setting.


<tt>client = IRC::Client.new do |c|

c.server   = 'irc.malkier.net'
c.port     = 6667
c.password = 'partypants'
c.nickname = 'rakaur'
c.username = 'rakaur'
c.realname = 'watching the weather change'
c.bind_to  = '10.0.1.20'

c.logger    = Logger.new($stderr)
c.log_level = :debug

end

client.thread = Thread.new { client.io_loop } clients.each { |client| client.thread.join }

...

client.quit("IRC quit message!") client.exit


returns

self

Yields:

  • (_self)

Yield Parameters:

  • _self (IRC::Client)

    the object that the method was called on



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/rhuidean/client.rb', line 58

def initialize
    # Is our socket dead?
    @dead      = false
    @connected = false

    # Received data waiting to be parsed.
    @recvq = []

    # Data waiting to be sent.
    @sendq = []

    # Our event queue.
    @eventq = EventQueue.new

    # Local IP to bind to
    @bind_to = nil

    # Password to login to the server
    @password = nil

    # Our Logger object.
    @logger        = Logger.new($stderr)
    self.log_level = :info

    # If we have a block let it set up our instance attributes.
    yield(self) if block_given?

    # Core events which are needed to work at all.
    on(:read_ready)  { read  }
    on(:write_ready) { write }
    on(:recvq_ready) { parse }

    on(:dead) { self.dead = true }

    on(:exit) do |from|
        log(:fatal, "exiting via #{from}...")
        Thread.exit
    end

    on(:PING) { |m| raw("PONG :#{m.target}") }

    # Set up event handlers. These track some state and such, and can
    # be overridden for other functionality in any child classes.
    set_default_handlers

    # Special method for default CTCP replies
    # I use this so they don't get wiped out when someone overrides
    # the default handlers, but also so that they CAN be wiped out.
    set_ctcp_handlers

    self
end

Instance Attribute Details

- (Object) bind_to

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def bind_to
  @bind_to
end

- (Object) nickname

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def nickname
  @nickname
end

- (Object) password

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def password
  @password
end

- (Object) port

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def port
  @port
end

- (Object) realname

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def realname
  @realname
end

- (Object) server

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def server
  @server
end

- (Object) socket (readonly)

Our TCPSocket.



27
28
29
# File 'lib/rhuidean/client.rb', line 27

def socket
  @socket
end

- (Object) thread

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def thread
  @thread
end

- (Object) username

instance attributes



23
24
25
# File 'lib/rhuidean/client.rb', line 23

def username
  @username
end

Instance Method Details

- (Object) connect

Creates and connects our socket.


returns

self



398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/rhuidean/client.rb', line 398

def connect
    verify_attributes

    log(:info, "connecting to #@server:#@port")

    begin
        @socket = TCPSocket.new(@server, @port, @bind_to)
    rescue Exception => err
        @eventq.post(:dead)
    end

    @dead      = false
    @connected = true

    pass(@password) if @password
    nick(@nickname)
    user(@username, @server, @server, @realname)
end

- (Boolean) connected?

Are we connected?


returns

true or false

Returns:

  • (Boolean)


389
390
391
# File 'lib/rhuidean/client.rb', line 389

def connected?
    @connected
end

- (Object) ctcp(to, type, params = nil)

Sends a CTCP



47
48
49
50
51
52
53
# File 'lib/rhuidean/methods.rb', line 47

def ctcp(to, type, params = nil)
    if params
        @sendq << "PRIVMSG #{to} :\1#{type} #{params}\1"
    else
        @sendq << "PRIVMSG #{to} :\1#{type}\1"
    end
end

- (Object) ctcp_reply(to, type, params = '')

Sends a CTCP reply



61
62
63
# File 'lib/rhuidean/methods.rb', line 61

def ctcp_reply(to, type, params = '')
    @sendq << "NOTICE #{to} :\1#{type} #{params}\1"
end

- (Boolean) dead?

Is the socket dead?


returns

true or false

Returns:

  • (Boolean)


380
381
382
# File 'lib/rhuidean/client.rb', line 380

def dead?
    @dead
end

- (Object) exit(from = 'exit')

Forces the Client's Thread to die. If it's the main thread, the application goes with it.


returns

nope!



432
433
434
435
# File 'lib/rhuidean/client.rb', line 432

def exit(from = 'exit')
    @eventq.post(:exit, from)
    @eventq.run
end

- (Object) invite(target, channel)

Sends an IRC INVITE command.



96
97
98
# File 'lib/rhuidean/methods.rb', line 96

def invite(target, channel)
    @senq << "INVITE #{target} #{channel}"
end

- (Object) io_loop

Schedules input/output and runs the EventQueue.


returns

never, thread dies on :exit



340
341
342
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
370
371
372
373
# File 'lib/rhuidean/client.rb', line 340

def io_loop
    loop do
        if dead?
            sleep(30)
            connect
            next
        end

        connect unless connected?

        # Run the event loop. These events will add IO, and possibly other
        # events, so we keep running until it's empty.
        @eventq.run while @eventq.needs_ran?

        next if dead?

        writefd = [@socket] unless @sendq.empty?

        # Ruby's threads suck. In theory, the timers should
        # manage themselves in separate threads. Unfortunately,
        # Ruby has a global lock and the scheduler isn't great, so
        # this tells select() to timeout when the next timer needs to run.
        timeout = (Timer.next_time - Time.now.to_f).round
        timeout = 1 if timeout == 0 # Don't want 0, that's forever
        timeout = 60 if timeout < 0 # Less than zero means no timers

        ret = IO.select([@socket], writefd, [], timeout)

        next unless ret

        @eventq.post(:read_ready)  unless ret[0].empty?
        @eventq.post(:write_ready) unless ret[1].empty?
    end
end

- (Object) join(channel, key = '')

Sends an IRC JOIN command.



66
67
68
# File 'lib/rhuidean/methods.rb', line 66

def join(channel, key = '')
    @sendq << "JOIN #{channel} #{key}"
end

- (Object) kick(channel, target, reason = '')

Sends an IRC KICK command.



76
77
78
# File 'lib/rhuidean/methods.rb', line 76

def kick(channel, target, reason = '')
    @sendq << "KICK #{channel} #{target} :#{reason}"
end

- (Object) mode(target, mode = '')

Sends an IRC MODE command.



91
92
93
# File 'lib/rhuidean/methods.rb', line 91

def mode(target, mode = '')
    @sendq << "MODE #{target} #{mode}"
end

- (Object) nick(nick)

Sends an IRC NICK command.



27
28
29
# File 'lib/rhuidean/methods.rb', line 27

def nick(nick)
    @sendq << "NICK #{nick}"
end

- (Object) notice(to, message)

Sends an IRC NOTICE command.



56
57
58
# File 'lib/rhuidean/methods.rb', line 56

def notice(to, message)
    @sendq << "NOTICE #{to} :#{message}"
end

- (Object) on(event, &block)

Registers Event handlers with our EventQueue.


<tt>c.on(:PRIVMSG) do |m|

next if m.params.empty?
if m.params =~ /\.die/ and m.origin == my_master
    c.quit(params)
    c.exit
end</tt>

event

name of the event as a Symbol

block

block to call when Event is posted

returns

self



329
330
331
332
333
# File 'lib/rhuidean/client.rb', line 329

def on(event, &block)
    @eventq.handle(event, &block)

    self
end

- (Object) part(channel, message = '')

Sends an IRC PART command.



71
72
73
# File 'lib/rhuidean/methods.rb', line 71

def part(channel, message = '')
    @sendq << "PART #{channel} :#{message}"
end

- (Object) pass(password)

Sends an IRC PASS command.



37
38
39
# File 'lib/rhuidean/methods.rb', line 37

def pass(password)
    @sendq << "PASS #{password}"
end

- (Object) privmsg(to, message)

Sends an IRC PRIVMSG command.



42
43
44
# File 'lib/rhuidean/methods.rb', line 42

def privmsg(to, message)
    @sendq << "PRIVMSG #{to} :#{message}"
end

- (Object) quit(message = '')

Send an IRC QUIT command.



101
102
103
# File 'lib/rhuidean/methods.rb', line 101

def quit(message = '')
    @sendq << "QUIT :#{message}"
end

- (Object) raw(message)

Sends text directly to the server.



22
23
24
# File 'lib/rhuidean/methods.rb', line 22

def raw(message)
    @sendq << message
end

- (Object) to_s

Represent ourselves in a string.


returns

our nickname and object ID



422
423
424
# File 'lib/rhuidean/client.rb', line 422

def to_s
    "#{@nickname}:#{self.object_id}"
end

- (Object) topic(target, new = '')

Sends an IRC TOPIC command.



81
82
83
# File 'lib/rhuidean/methods.rb', line 81

def topic(target, new = '')
    @sendq << "TOPIC #{target} :#{new}"
end

- (Object) umode(mode)

Sends an IRC MODE command.



86
87
88
# File 'lib/rhuidean/methods.rb', line 86

def umode(mode)
    @sendq << "MODE #@nickname #{mode}"
end

- (Object) user(username, server, host, realname)

Sends an IRC USER command.



32
33
34
# File 'lib/rhuidean/methods.rb', line 32

def user(username, server, host, realname)
    @sendq << "USER #{username} #{server} #{host} :#{realname}"
end