Sutto-marvin 0.4.0 → 0.8.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/bin/marvin +22 -156
  2. data/handlers/keiki_thwopper.rb +21 -0
  3. data/handlers/tweet_tweet.rb +1 -3
  4. data/lib/marvin/abstract_client.rb +75 -189
  5. data/lib/marvin/abstract_parser.rb +9 -11
  6. data/lib/marvin/base.rb +134 -101
  7. data/lib/marvin/client/actions.rb +104 -0
  8. data/lib/marvin/client/default_handlers.rb +97 -0
  9. data/lib/marvin/command_handler.rb +60 -49
  10. data/lib/marvin/console.rb +4 -31
  11. data/lib/marvin/core_commands.rb +30 -12
  12. data/lib/marvin/distributed/client.rb +225 -0
  13. data/lib/marvin/distributed/handler.rb +85 -0
  14. data/lib/marvin/distributed/protocol.rb +88 -0
  15. data/lib/marvin/distributed/server.rb +154 -0
  16. data/lib/marvin/distributed.rb +4 -10
  17. data/lib/marvin/dsl.rb +103 -0
  18. data/lib/marvin/exception_tracker.rb +7 -4
  19. data/lib/marvin/irc/client.rb +127 -99
  20. data/lib/marvin/irc/event.rb +14 -10
  21. data/lib/marvin/irc.rb +0 -1
  22. data/lib/marvin/middle_man.rb +1 -1
  23. data/lib/marvin/parsers/command.rb +10 -8
  24. data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
  25. data/lib/marvin/parsers/prefixes/server.rb +1 -1
  26. data/lib/marvin/parsers/ragel_parser.rb +59 -52
  27. data/lib/marvin/parsers/ragel_parser.rl +6 -7
  28. data/lib/marvin/parsers/simple_parser.rb +4 -9
  29. data/lib/marvin/parsers.rb +1 -2
  30. data/lib/marvin/settings.rb +29 -79
  31. data/lib/marvin/test_client.rb +20 -26
  32. data/lib/marvin/util.rb +10 -3
  33. data/lib/marvin.rb +42 -39
  34. data/templates/boot.erb +3 -0
  35. data/templates/connections.yml.erb +10 -0
  36. data/templates/debug_handler.erb +5 -0
  37. data/templates/hello_world.erb +10 -0
  38. data/templates/rakefile.erb +15 -0
  39. data/templates/settings.yml.erb +8 -0
  40. data/{config/setup.rb → templates/setup.erb} +8 -10
  41. data/templates/test_helper.erb +17 -0
  42. data/test/abstract_client_test.rb +63 -0
  43. data/test/parser_comparison.rb +2 -2
  44. data/test/parser_test.rb +3 -3
  45. data/test/test_helper.rb +58 -6
  46. metadata +51 -83
  47. data/README.textile +0 -105
  48. data/TUTORIAL.textile +0 -54
  49. data/VERSION.yml +0 -4
  50. data/config/boot.rb +0 -14
  51. data/config/connections.yml.sample +0 -5
  52. data/config/settings.yml.sample +0 -13
  53. data/handlers/logging_handler.rb +0 -89
  54. data/lib/marvin/core_ext.rb +0 -11
  55. data/lib/marvin/daemon.rb +0 -71
  56. data/lib/marvin/data_store.rb +0 -73
  57. data/lib/marvin/dispatchable.rb +0 -99
  58. data/lib/marvin/distributed/dispatch_handler.rb +0 -83
  59. data/lib/marvin/distributed/drb_client.rb +0 -78
  60. data/lib/marvin/distributed/ring_server.rb +0 -41
  61. data/lib/marvin/handler.rb +0 -12
  62. data/lib/marvin/irc/server/abstract_connection.rb +0 -84
  63. data/lib/marvin/irc/server/base_connection.rb +0 -66
  64. data/lib/marvin/irc/server/channel.rb +0 -115
  65. data/lib/marvin/irc/server/named_store.rb +0 -14
  66. data/lib/marvin/irc/server/remote_interface.rb +0 -77
  67. data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
  68. data/lib/marvin/irc/server/user.rb +0 -5
  69. data/lib/marvin/irc/server/user_connection.rb +0 -134
  70. data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
  71. data/lib/marvin/irc/server.rb +0 -71
  72. data/lib/marvin/loader.rb +0 -149
  73. data/lib/marvin/logger.rb +0 -86
  74. data/lib/marvin/options.rb +0 -42
  75. data/lib/marvin/parsers/regexp_parser.rb +0 -93
  76. data/lib/marvin/status.rb +0 -72
  77. data/script/client +0 -3
  78. data/script/console +0 -3
  79. data/script/distributed_client +0 -3
  80. data/script/install +0 -1
  81. data/script/ring_server +0 -4
  82. data/script/server +0 -4
  83. data/script/status +0 -3
  84. data/spec/marvin/abstract_client_test.rb +0 -38
  85. data/spec/spec_helper.rb +0 -14
@@ -1,89 +0,0 @@
1
- # A Simple Channel Logger, built for the
2
- # #offrails community. Please note that this
3
- # relies on models etc. inside the Rails App.
4
- # it's suited for modification of subclassing
5
- # if you wish to write your own Channel Logger.
6
- # I plan on open sourcing the app sometime in
7
- # the near future.
8
- class LoggingHandler < Marvin::CommandHandler
9
-
10
- class_inheritable_accessor :connection, :setup
11
- attr_accessor :listening, :users
12
-
13
- def initialize
14
- super
15
- logger.debug "Setting up LoggingHandler"
16
- self.setup!
17
- self.users = {}
18
- end
19
-
20
- # Control
21
-
22
- exposes :listen, :earmuffs
23
-
24
- desc "Makes me listen up and take not of what you're saying."
25
- def listen(data)
26
- unless listening?
27
- @listening = true
28
- reply "Busted! I heard _everything_ you said ;)"
29
- else
30
- reply "Uh, You never asked me to put my earmuffs on?"
31
- end
32
- end
33
-
34
- desc "Sends me off into a corner with my ear muffs so you can have your discussions in peace"
35
- def earmuffs(data)
36
- if listening?
37
- @listening = false
38
- reply "Oh hai, I'm not listening anymore."
39
- else
40
- reply "I've already put the earmuffs on!"
41
- end
42
- end
43
-
44
- def listening?
45
- @listening
46
- end
47
-
48
- # The actual logging
49
-
50
- on_event :incoming_message do
51
- log_message(options.nick, options.target, options.message)
52
- end
53
-
54
- on_event :outgoing_message do
55
- log_message(client.nickname, options.target, options.message)
56
- end
57
-
58
- on_event :incoming_action do
59
- log_message(options.nick, options.target, "ACTION \01#{options.message}\01")
60
- end
61
-
62
- def log_message(from, to, message)
63
- return unless listening?
64
- ensure_connection_is_alive # Before Logging, ensure that the connection is alive.
65
- self.users[from.strip] ||= IrcHandle.find_or_create_by_name(from.strip)
66
- self.users[from.strip].messages.create :message => message, :target => to
67
- end
68
-
69
- # Our General Tasks
70
-
71
- def setup!
72
- return true if self.setup
73
- load_prerequisites
74
- self.setup = true
75
- self.listening = true
76
- end
77
-
78
- def load_prerequisites
79
- require File.join(Marvin::Settings.rails_root, "config/environment")
80
- end
81
-
82
- def ensure_connection_is_alive
83
- unless ActiveRecord::Base.connection.active?
84
- ActiveRecord::Base.connection.reconnect!
85
- end
86
- end
87
-
88
-
89
- end
@@ -1,11 +0,0 @@
1
- class File
2
- def self.present_dir
3
- File.dirname(__FILE__)
4
- end
5
- end
6
-
7
- class String
8
- def /(*args)
9
- File.join(self, *args)
10
- end
11
- end
data/lib/marvin/daemon.rb DELETED
@@ -1,71 +0,0 @@
1
- module Marvin
2
- class Daemon
3
- class << self
4
-
5
- def alive?(pid)
6
- return Process.getpgid(pid) != -1
7
- rescue Errno::ESRCH
8
- return false
9
- end
10
-
11
- def kill_all(type = :all)
12
- if type == :all
13
- files = Dir[Marvin::Settings.root / "tmp/pids/*.pid"]
14
- files.each { |f| kill_all_from f }
15
- elsif type.is_a?(Symbol)
16
- kill_all_from(pid_file_for(type))
17
- end
18
- return nil
19
- end
20
-
21
- def daemonize!
22
- exit if fork
23
- Process.setsid
24
- exit if fork
25
- self.write_pid
26
- File.umask 0000
27
- STDIN.reopen "/dev/null"
28
- STDOUT.reopen "/dev/null", "a"
29
- STDERR.reopen STDOUT
30
- Marvin::Settings.verbose = false
31
- end
32
-
33
- def cleanup!
34
- f = pids_file_for(Marvin::Loader.type)
35
- FileUtils.rm_f(f) if (pids_from(f) - Process.pid).blank?
36
- end
37
-
38
- def pids_for_type(type)
39
- pids_from(pid_file_for(type))
40
- end
41
-
42
- protected
43
-
44
- def kill_all_from(file)
45
- pids = pids_from(file)
46
- pids.each { |p| Process.kill("TERM", p) unless p == Process.pid }
47
- FileUtils.rm_f(file)
48
- rescue => e
49
- STDOUT.puts e.inspect
50
- end
51
-
52
- def pid_file_for(type)
53
- Marvin::Settings.root / "tmp" / "pids" / "marvin-#{type.to_s.underscore}.pid"
54
- end
55
-
56
- def pids_from(file)
57
- return [] unless File.exist?(file)
58
- pids = File.read(file)
59
- pids = pids.split("\n").map { |l| l.strip.to_i(10) }.select { |p| alive?(p) }
60
- end
61
-
62
- def write_pid
63
- f = pid_file_for(Marvin::Loader.type)
64
- pids = pids_from(f)
65
- pids << Process.pid unless pids.include?(Process.pid)
66
- File.open(f, "w+") { |f| f.puts pids.join("\n") }
67
- end
68
-
69
- end
70
- end
71
- end
@@ -1,73 +0,0 @@
1
- require 'json'
2
-
3
- module Marvin
4
- # Implements a simple datastore interface, designed to make
5
- # it easy to develop handlers which have persistent data.
6
- class DataStore
7
-
8
- cattr_accessor :logger, :registered_stores
9
- self.logger = Marvin::Logger.logger
10
- self.registered_stores = {}
11
-
12
- # Returns the path to the data store relative to this file.
13
- # Used when loading / dumping the data.
14
- def self.datastore_location
15
- path = Marvin::Settings[:datastore_location] ? Marvin::Settings.datastore_location : "tmp/datastore.json"
16
- return Marvin::Settings.root / path
17
- end
18
-
19
- # Dump the current data store contents to file.
20
- def self.dump!
21
- File.open(self.datastore_location, "w+") do |f|
22
- f.write self.registered_stores.to_json
23
- end
24
- end
25
-
26
- # Load the current data store contents from file.
27
- def self.load!
28
- results = {}
29
- if File.exists?(self.datastore_location)
30
- begin
31
- json = JSON.load(File.read(self.datastore_location))
32
- results = json if json.is_a?(Hash)
33
- rescue JSON::ParserError
34
- end
35
- end
36
- self.registered_stores = results
37
- end
38
-
39
-
40
- # For each individual datastore.
41
-
42
- attr_accessor :name
43
-
44
- def initialize(name)
45
- self.name = name.to_s
46
- self.registered_stores ||= {}
47
- self.registered_stores[self.name] ||= {}
48
- end
49
-
50
- def [](key)
51
- ((self.registered_stores||={})[self.name]||={})[key.to_s]
52
- end
53
-
54
- def []=(key,value)
55
- self.registered_stores[self.name][key.to_s] = value
56
- end
57
-
58
- def method_missing(name, *args, &blk)
59
- if name.to_s =~ /^(.*)=$/i
60
- self[$1.to_s] = args.first
61
- elsif self.registered_stores[self.name].has_key?(name.to_s)
62
- return self.registered_stores[self.name][name.to_s]
63
- else
64
- super(name, *args, &blk)
65
- end
66
- end
67
-
68
- def to_hash
69
- self.registered_stores[self.name]
70
- end
71
-
72
- end
73
- end
@@ -1,99 +0,0 @@
1
- module Marvin
2
- # = Marvin::Dispatchable
3
- # A Generic mixin which lets you define an object
4
- # Which accepts handlers which can have arbitrary
5
- # events dispatched.
6
- # == Usage
7
- #
8
- # class X
9
- # include Marvin::Dispatchable
10
- # self.handlers << SomeHandler.new
11
- # end
12
- # X.new.dispatch(:name, {:args => "Values"})
13
- #
14
- # Will first check if SomeHandler#handle_name exists,
15
- # calling handle_name({:args => "Values"}) if it does,
16
- # otherwise calling SomeHandler#handle(:name, {:args => "Values"})
17
- module Dispatchable
18
-
19
- def self.included(parent)
20
- parent.class_eval do
21
- include InstanceMethods
22
- extend ClassMethods
23
- end
24
- end
25
-
26
- module InstanceMethods
27
-
28
- # Returns the handlers registered on this class,
29
- # used inside +dispatch+. Note that it will call
30
- # dup on each of the objects to get a new instance.
31
- # please ensure your object acts accordingly.
32
- def handlers
33
- @handlers ||= self.class.handlers.map { |h| h.dup }
34
- end
35
-
36
- # Dispatch an 'event' with a given name to the handlers
37
- # registered on the current class. Used as a nicer way of defining
38
- # behaviours that should occur under a given set of circumstances.
39
- # == Params
40
- # +name+: The name of the current event
41
- # +opts+: an optional hash of options to pass
42
- def dispatch(name, opts = {})
43
- # The full handler name is the method we call given it exists.
44
- full_handler_name = :"handle_#{name.to_s.underscore}"
45
- # First, dispatch locally if the method is defined.
46
- if self.respond_to?(full_handler_name)
47
- self.send(full_handler_name, opts)
48
- end
49
- # Iterate through all of the registered handlers,
50
- # If there is a method named handle_<event_name>
51
- # defined we sent that otherwise we call the handle
52
- # method on the handler. Note that the handle method
53
- # is the only required aspect of a handler. An improved
54
- # version of this would likely cache the respond_to?
55
- # call.
56
- self.handlers.each do |handler|
57
- if handler.respond_to?(full_handler_name)
58
- handler.send(full_handler_name, opts)
59
- else
60
- handler.handle name, opts
61
- end
62
- end
63
- # If we get the HaltHandlerProcessing exception, we
64
- # catch it and continue on our way. In essence, we
65
- # stop the dispatch of events to the next set of the
66
- # handlers.
67
- rescue HaltHandlerProcessing => e
68
- Marvin::Logger.info "Halting processing chain"
69
- rescue Exception => e
70
- Marvin::ExceptionTracker.log(e)
71
- end
72
-
73
- end
74
-
75
- module ClassMethods
76
-
77
- # Return an array of all registered handlers, stored in the
78
- # class variable @@handlers. Used inside the #handlers instance
79
- # method as well as inside things such as register_handler.
80
- def handlers
81
- @@handlers ||= []
82
- end
83
-
84
- # Assigns a new array of handlers and assigns each.
85
- def handlers=(new_value)
86
- @@handlers = []
87
- new_value.to_a.each { |h| register_handler h }
88
- end
89
-
90
- # Appends a handler to the list of handlers for this object.
91
- # Handlers are called in the order they are registered.
92
- def register_handler(handler)
93
- self.handlers << handler unless handler.nil? || !handler.respond_to?(:handle)
94
- end
95
-
96
- end
97
-
98
- end
99
- end
@@ -1,83 +0,0 @@
1
- require 'rinda/ring'
2
- require 'rinda/tuplespace'
3
-
4
- DRb.start_service
5
-
6
- module Marvin
7
- module Distributed
8
-
9
- # Handler to provide
10
- class DispatchHandler < Marvin::Base
11
-
12
- LOOKUP_TIMEOUT = 0.5
13
-
14
- # Tell the client that we shouldn't be dumped.
15
- Marvin::AbstractClient.class_eval { include(DRbUndumped) }
16
-
17
- # Get the ring server - if it exists, we will return the current
18
- # instance other wise it follows a few steps to try and find a new
19
- # one. Since there can be a delay in getting a response, we'll only
20
- # check every 5 messages.
21
- def ring_server
22
- if @@rs.nil? && (@lookup_attempts ||= 6) > 5
23
- @lookup_attempts = 0
24
- @@rs = Rinda::RingFinger.finger.lookup_ring(LOOKUP_TIMEOUT)
25
- logger.info "Found new ring server => #{@@rs.__drburi}"
26
- elsif @@rs.nil?
27
- @lookup_attempts += 1
28
- end
29
- return @@rs
30
- rescue RingNotFound
31
- @@rs = nil
32
- end
33
-
34
- # Takes an incoming messsage and does all the fancy
35
- # Stuff with it.
36
- def handle(message, options)
37
- # Don't forward lines for the moment to halve the traffic.
38
- return if message == :incoming_line
39
- super(message, options)
40
- dispatch(message, options)
41
- end
42
-
43
- # Attempts to add a message to the current tuple space,
44
- # adding it to a message queue if it can't be added.
45
- # If there are many items, it will log a warning.
46
- # TODO: Improve it to dump messages to disk at a predefined limit.
47
- def dispatch(name, options)
48
- options[:dispatched_at] ||= Time.now
49
- tuple = [:marvin_event, Marvin::Settings.distributed_namespace, name, options, self.client]
50
- begin
51
- (@queued_messages ||= []) << tuple
52
- if self.ring_server.nil?
53
- size = @queued_messages.size
54
- if size > 0 && size % 25 == 0
55
- logger.warn "Dispatch handler queue is currently holding #{size} items"
56
- end
57
- else
58
- logger.debug "Writing #{@queued_messages.size} message to the ring server"
59
- @queued_messages.dup.each do |t|
60
- ring_server.write(t)
61
- @queued_messages.delete(t)
62
- end
63
- end
64
- rescue
65
- # Reset the ring finger to the next choice.
66
- logger.debug "Ring server unavailable, resetting..."
67
- @@rs = nil
68
- end
69
- end
70
-
71
- # Register this as a handler, but only if we're
72
- # running in "client mode" - in other words, we
73
- # want to make sure it won't start up an infinite
74
- # loop.
75
- def self.register!(*args)
76
- # DO NOT register if this is not a normal client.
77
- return unless Marvin::Loader.type == :client
78
- super
79
- end
80
-
81
- end
82
- end
83
- end
@@ -1,78 +0,0 @@
1
- module Marvin
2
- module Distributed
3
- # A method for operating on marvin objects.
4
- class DRbClient
5
-
6
- # Wait 1 second on a lookup.
7
- LOOKUP_TIMEOUT = 1
8
-
9
- class << self
10
-
11
- @@handlers = []
12
- attr_accessor :stopped
13
-
14
- def register_handler(handler)
15
- @@handlers << handler unless handler.nil? || !handler.respond_to?(:handle)
16
- end
17
-
18
- def dispatch(name, opts, client)
19
- Marvin::Logger.debug "Processing Event: #{name}"
20
- full_handler_name = :"handle_#{name.to_s.underscore}"
21
- @@handlers.each do |handler|
22
- has_client = handler.respond_to?(:client=)
23
- handler.client = client if has_client
24
- if handler.respond_to?(full_handler_name)
25
- handler.send(full_handler_name, opts)
26
- else
27
- handler.handle name, opts
28
- end
29
- handler.client = nil if has_client
30
- end
31
- rescue HaltHandlerProcessing => e
32
- Marvin::Logger.info "Halting processing chain"
33
- rescue Exception => e
34
- Marvin::ExceptionTracker.log(e)
35
- end
36
-
37
- # Starts up a drb processor / client, and walks through the process of dealing
38
- # with it / processing events.
39
- def run
40
- self.stopped = false
41
- Marvin::Logger.info "Starting up DRb Client"
42
- DRb.start_service
43
- # Loop through, making sure we have a valid
44
- # RingFinger and then process events as they
45
- # appear.
46
- enter_loop!
47
- end
48
-
49
- def stop
50
- self.stopped = true
51
- end
52
-
53
- def ring_server
54
- @ring_server = Rinda::RingFinger.finger.lookup_ring(LOOKUP_TIMEOUT) if @ring_server.nil?
55
- return @ring_server
56
- rescue RingNotFound
57
- @ring_server = nil
58
- end
59
-
60
- def enter_loop!
61
- Marvin::Logger.info "Entering processing loop"
62
- while !self.stopped
63
- begin
64
- unless self.ring_server.blank?
65
- event = self.ring_server.take([:marvin_event, Marvin::Settings.distributed_namespace, nil, nil, nil], 2)
66
- dispatch(*event[2..-1]) unless event.blank?
67
- end
68
- rescue
69
- # Reset the ring server on event of connection refused etc.
70
- @ring_server = nil
71
- end
72
- end
73
- end
74
-
75
- end
76
- end
77
- end
78
- end
@@ -1,41 +0,0 @@
1
- require 'rinda/ring'
2
- require 'rinda/tuplespace'
3
-
4
- module Marvin
5
- module Distributed
6
- class RingServer
7
-
8
- attr_accessor :tuple_space, :ring_server
9
- cattr_accessor :logger
10
- self.logger = Marvin::Logger
11
-
12
- def initialize
13
- self.tuple_space = Rinda::TupleSpace.new
14
- if Marvin::Settings.log_level == :debug
15
- observer = self.tuple_space.notify('write', [:marvin_event, Marvin::Settings.distributed_namespace, nil, nil, nil])
16
- Thread.start do
17
- observer.each do |i|
18
- event_name, args = i[1][2..3]
19
- Marvin::Logger.logger.debug "Marvin event added - #{event_name.inspect} w/ #{args.inspect}"
20
- end
21
- end
22
- end
23
- self.ring_server = Rinda::RingServer.new(self.tuple_space)
24
- end
25
-
26
- def self.run
27
- begin
28
- logger.info "Starting up DRb"
29
- drb_server = DRb.start_service
30
- logger.info "Creating TupleSpace & Ring Server Instances - Running on #{DRb.uri}"
31
- self.new
32
- logger.info "Started - Joining thread."
33
- DRb.thread.join
34
- rescue
35
- logger.fatal "Error starting ring server - please ensure another instance isn't already running."
36
- end
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,12 +0,0 @@
1
- module Marvin
2
- module Handler
3
-
4
- # Received a given +message+ with a set of default
5
- # +opts+ (defaulting back to an empty hash), which
6
- # will be used to perform some sort of action.
7
- def handle(message, opts = {})
8
- Marvin::Logger.debug "NOP handle - got message #{message.inspect}"
9
- end
10
-
11
- end
12
- end
@@ -1,84 +0,0 @@
1
- module Marvin::IRC::Server
2
- class AbstractConnection
3
- include Marvin::Dispatchable
4
-
5
- cattr_accessor :connections, :logger, :alive
6
- self.connections = []
7
- self.logger = Marvin::Logger
8
-
9
- attr_accessor :connection
10
-
11
- # Create a new connection with a given parent
12
- # and an incoming buffer of messages
13
- def initialize(parent, buffer = [])
14
- @connection = parent
15
- buffer.each { |line| receive_line(line) }
16
- end
17
-
18
- def receive_line(line)
19
- dispatch :incoming_line, :line => line
20
- event = Marvin::Settings.default_parser.parse(line)
21
- dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
22
- end
23
-
24
- def send_line(line)
25
- @connection.send_line(line)
26
- end
27
-
28
- def process_connect
29
- @alive = true
30
- # Send the welcome notice / auth command.
31
- command :NOTICE, "AUTH", ":Marvin v#{Marvin.version} initialized, welcome."
32
- dispatch :client_connected, :client => self
33
- end
34
-
35
- def process_disconnect
36
- @@connections.delete(self)
37
- @alive = false
38
- dispatch :client_disconnected, :client => self
39
- end
40
-
41
- class << self
42
-
43
- # Return an array of all registered handlers, stored in the
44
- # class variable @@handlers. Used inside the #handlers instance
45
- # method as well as inside things such as register_handler.
46
- def handlers
47
- (@@handlers ||= {})[self] ||= []
48
- end
49
-
50
- # Assigns a new array of handlers and assigns each.
51
- def handlers=(new_value)
52
- (@@handlers ||= {})[self] = []
53
- new_value.to_a.each { |h| register_handler h }
54
- end
55
-
56
- end
57
-
58
- def dispatch(name, opts = {})
59
- opts[:connection] ||= self
60
- super
61
- end
62
-
63
- private
64
-
65
- def command(name, *args)
66
- opts = args.extract_options!
67
- formatted = [name.to_s.upcase, *args].join(" ")
68
- formatted = ":#{opts[:prefix]} #{formatted}" if opts[:prefix]
69
- send_line formatted
70
- end
71
-
72
- def peer_name
73
- return @peer_name unless @peer_name.blank?
74
- sock_addr = @connection.get_peername
75
- begin
76
- @peer_name = Socket.getnameinfo(sock_addr, Socket::NI_NAMEREQD).first
77
- rescue
78
- @peer_name = Socket.getnameinfo(sock_addr).first
79
- end
80
- return @peer_name
81
- end
82
-
83
- end
84
- end