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.
- data/bin/marvin +22 -156
- data/handlers/keiki_thwopper.rb +21 -0
- data/handlers/tweet_tweet.rb +1 -3
- data/lib/marvin/abstract_client.rb +75 -189
- data/lib/marvin/abstract_parser.rb +9 -11
- data/lib/marvin/base.rb +134 -101
- data/lib/marvin/client/actions.rb +104 -0
- data/lib/marvin/client/default_handlers.rb +97 -0
- data/lib/marvin/command_handler.rb +60 -49
- data/lib/marvin/console.rb +4 -31
- data/lib/marvin/core_commands.rb +30 -12
- data/lib/marvin/distributed/client.rb +225 -0
- data/lib/marvin/distributed/handler.rb +85 -0
- data/lib/marvin/distributed/protocol.rb +88 -0
- data/lib/marvin/distributed/server.rb +154 -0
- data/lib/marvin/distributed.rb +4 -10
- data/lib/marvin/dsl.rb +103 -0
- data/lib/marvin/exception_tracker.rb +7 -4
- data/lib/marvin/irc/client.rb +127 -99
- data/lib/marvin/irc/event.rb +14 -10
- data/lib/marvin/irc.rb +0 -1
- data/lib/marvin/middle_man.rb +1 -1
- data/lib/marvin/parsers/command.rb +10 -8
- data/lib/marvin/parsers/prefixes/host_mask.rb +12 -7
- data/lib/marvin/parsers/prefixes/server.rb +1 -1
- data/lib/marvin/parsers/ragel_parser.rb +59 -52
- data/lib/marvin/parsers/ragel_parser.rl +6 -7
- data/lib/marvin/parsers/simple_parser.rb +4 -9
- data/lib/marvin/parsers.rb +1 -2
- data/lib/marvin/settings.rb +29 -79
- data/lib/marvin/test_client.rb +20 -26
- data/lib/marvin/util.rb +10 -3
- data/lib/marvin.rb +42 -39
- data/templates/boot.erb +3 -0
- data/templates/connections.yml.erb +10 -0
- data/templates/debug_handler.erb +5 -0
- data/templates/hello_world.erb +10 -0
- data/templates/rakefile.erb +15 -0
- data/templates/settings.yml.erb +8 -0
- data/{config/setup.rb → templates/setup.erb} +8 -10
- data/templates/test_helper.erb +17 -0
- data/test/abstract_client_test.rb +63 -0
- data/test/parser_comparison.rb +2 -2
- data/test/parser_test.rb +3 -3
- data/test/test_helper.rb +58 -6
- metadata +51 -83
- data/README.textile +0 -105
- data/TUTORIAL.textile +0 -54
- data/VERSION.yml +0 -4
- data/config/boot.rb +0 -14
- data/config/connections.yml.sample +0 -5
- data/config/settings.yml.sample +0 -13
- data/handlers/logging_handler.rb +0 -89
- data/lib/marvin/core_ext.rb +0 -11
- data/lib/marvin/daemon.rb +0 -71
- data/lib/marvin/data_store.rb +0 -73
- data/lib/marvin/dispatchable.rb +0 -99
- data/lib/marvin/distributed/dispatch_handler.rb +0 -83
- data/lib/marvin/distributed/drb_client.rb +0 -78
- data/lib/marvin/distributed/ring_server.rb +0 -41
- data/lib/marvin/handler.rb +0 -12
- data/lib/marvin/irc/server/abstract_connection.rb +0 -84
- data/lib/marvin/irc/server/base_connection.rb +0 -66
- data/lib/marvin/irc/server/channel.rb +0 -115
- data/lib/marvin/irc/server/named_store.rb +0 -14
- data/lib/marvin/irc/server/remote_interface.rb +0 -77
- data/lib/marvin/irc/server/user/handle_mixin.rb +0 -140
- data/lib/marvin/irc/server/user.rb +0 -5
- data/lib/marvin/irc/server/user_connection.rb +0 -134
- data/lib/marvin/irc/server/virtual_user_connection.rb +0 -80
- data/lib/marvin/irc/server.rb +0 -71
- data/lib/marvin/loader.rb +0 -149
- data/lib/marvin/logger.rb +0 -86
- data/lib/marvin/options.rb +0 -42
- data/lib/marvin/parsers/regexp_parser.rb +0 -93
- data/lib/marvin/status.rb +0 -72
- data/script/client +0 -3
- data/script/console +0 -3
- data/script/distributed_client +0 -3
- data/script/install +0 -1
- data/script/ring_server +0 -4
- data/script/server +0 -4
- data/script/status +0 -3
- data/spec/marvin/abstract_client_test.rb +0 -38
- data/spec/spec_helper.rb +0 -14
data/bin/marvin
CHANGED
@@ -1,167 +1,33 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
require 'rubygems'
|
3
|
-
require
|
4
|
-
require "thor"
|
3
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "marvin")
|
5
4
|
|
6
|
-
|
5
|
+
Marvin::Application.processing(ARGV) do |a|
|
7
6
|
|
8
|
-
|
7
|
+
a.banner = "Marvin v#{Marvin::VERSION} - An IRC Library for Ruby"
|
9
8
|
|
10
|
-
|
9
|
+
a.generator!
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
a.option :development, "Runs the app in development mode (handler reloading)", :shortcut => "D"
|
12
|
+
a.controller! :client, "Starts the actual Marvin client instance"
|
13
|
+
a.controller! :console, "Opens a friendly IRB prompt with Marvin pre-loaded"
|
14
|
+
a.controller! :distributed_client, "Starts a distributed client instance"
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if File.directory?(@dest)
|
21
|
-
STDOUT.puts "The given directory, \"#{path}\", already exists."
|
22
|
-
exit! 1
|
23
|
-
else
|
24
|
-
say "Creating Marvin app"
|
25
|
-
say " => Making directories"
|
26
|
-
mkdir @dest
|
27
|
-
mkdir source(@dest, "script")
|
28
|
-
mkdir source(@dest, "config")
|
29
|
-
mkdir source(@dest, "handlers")
|
30
|
-
mkdir_p source(@dest, "tmp/pids")
|
31
|
-
mkdir source(@dest, "log")
|
32
|
-
mkdir source(@dest, "lib")
|
33
|
-
say " => Copying files..."
|
34
|
-
copy "config/setup.rb"
|
35
|
-
copy "config/boot.rb"
|
36
|
-
copy "config/connections.yml.sample", "config/connections.yml"
|
37
|
-
copy "config/settings.yml.sample", "config/settings.yml"
|
38
|
-
copy "handlers/hello_world.rb"
|
39
|
-
copy "handlers/debug_handler.rb"
|
40
|
-
%w(client console distributed_client ring_server status).each do |c|
|
41
|
-
copy "script/#{c}"
|
42
|
-
FileUtils.chmod 0755, source(@dest, "script/#{c}")
|
43
|
-
end
|
44
|
-
say "Done!"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
map "cl" => :client, "st" => :status, "rs" => :ring_server,
|
49
|
-
"dc" => :distributed_client, "co" => :console
|
50
|
-
|
51
|
-
desc "start [PATH]", "starts client at the given path"
|
52
|
-
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
53
|
-
def start(path = ".")
|
54
|
-
@dest = File.expand_path(path)
|
55
|
-
start_script(:client)
|
56
|
-
end
|
57
|
-
|
58
|
-
desc "status [PATH]", "shows status of marvin app at a given location"
|
59
|
-
def status(path = ".")
|
60
|
-
@dest = File.expand_path(path)
|
61
|
-
start_script(:status)
|
62
|
-
end
|
63
|
-
|
64
|
-
desc "client [PATH]", "starts a client instance from the given location"
|
65
|
-
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
66
|
-
def client(path = ".")
|
67
|
-
@dest = File.expand_path(path)
|
68
|
-
start_script(:client)
|
69
|
-
end
|
70
|
-
|
71
|
-
desc "server [PATH]", "starts a server instance from the given location"
|
72
|
-
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
73
|
-
def server(path = ".")
|
74
|
-
@dest = File.expand_path(path)
|
75
|
-
start_script(:server)
|
76
|
-
end
|
77
|
-
|
78
|
-
desc "ring_server [PATH]", "starts a ring server from the given location"
|
79
|
-
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional, :kill => :boolean
|
80
|
-
def ring_server(path = ".")
|
81
|
-
@dest = File.expand_path(path)
|
82
|
-
start_script(:ring_server)
|
83
|
-
end
|
84
|
-
|
85
|
-
desc "distributed_client [PATH]", "starts a distributed client from the given location"
|
86
|
-
method_options :verbose => :boolean, :daemon => :boolean, :level => :optional,
|
87
|
-
:kill => :boolean, :nodes => :numeric
|
88
|
-
def distributed_client(path = ".")
|
89
|
-
@dest = File.expand_path(path)
|
90
|
-
start_script(:distributed_client)
|
91
|
-
end
|
92
|
-
|
93
|
-
desc "console [PATH]", "starts a marvin console from the given location"
|
94
|
-
def console(path = ".")
|
95
|
-
@dest = File.expand_path(path)
|
96
|
-
start_script(:console)
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
def source(*args)
|
102
|
-
File.expand_path(File.join(*args))
|
103
|
-
end
|
104
|
-
|
105
|
-
def copy(from, to = from)
|
106
|
-
s, d = source(GEM_ROOT, from), source(@dest, to)
|
107
|
-
say " --> cp #{s.gsub(" ", "\\ ")} #{d.gsub(" ", "\\ ")}" if @verbose
|
108
|
-
FileUtils.cp_r(s, d)
|
109
|
-
end
|
110
|
-
|
111
|
-
def mkdir(path)
|
112
|
-
say " --> mkdir #{path.gsub(" ", "\\ ")}" if @verbose
|
113
|
-
FileUtils.mkdir path
|
114
|
-
end
|
115
|
-
|
116
|
-
def mkdir_p(path)
|
117
|
-
say " --> mkdir #{path.gsub(" ", "\\ ")}" if @verbose
|
118
|
-
FileUtils.mkdir_p path
|
119
|
-
end
|
120
|
-
|
121
|
-
def say(text)
|
122
|
-
STDOUT.puts text
|
123
|
-
end
|
124
|
-
|
125
|
-
def marvin_repo?(path, type = client)
|
126
|
-
File.directory?(source(path, "script")) && File.exist?(source(path, "script/#{type}"))
|
127
|
-
end
|
128
|
-
|
129
|
-
def start_script(name)
|
130
|
-
if marvin_repo?(@dest, name)
|
131
|
-
extra_args = []
|
132
|
-
extra_args << "-k" if options[:kill]
|
133
|
-
extra_args << "-v" if options[:verbose]
|
134
|
-
extra_args << "-d" if options[:daemon]
|
135
|
-
extra_args << "--level=#{options[:level]}" if options[:level]
|
136
|
-
if options[:daemon] && options[:nodes]
|
137
|
-
nodes = options[:nodes]
|
138
|
-
else
|
139
|
-
nodes = 1
|
140
|
-
end
|
141
|
-
Dir.chdir(@dest) do
|
142
|
-
# Lets you start a number of different processes.
|
143
|
-
# uses system if there are more than 1 nodes, exec
|
144
|
-
# otherwise.
|
145
|
-
if nodes > 1
|
146
|
-
nodes.times { system("script/#{name}", *extra_args) }
|
147
|
-
else
|
148
|
-
exec("script/#{name}", *extra_args)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
else
|
152
|
-
STDOUT.puts "Woop! #{@dest.gsub(" ", "\\ ")} isn't a marvin app."
|
16
|
+
a.option :force, "force the creation of the application"
|
17
|
+
a.add "create PATH", "Creates a marvin application at the given location" do |path, options|
|
18
|
+
path = File.expand_path(path)
|
19
|
+
if File.exists?(path) && !options[:force]
|
20
|
+
die! "The path you tried to use, #{path}, already exists. Please try another or use the --force option"
|
153
21
|
end
|
22
|
+
setup_generator(path)
|
23
|
+
folders 'tmp', 'config', 'lib', 'handlers', 'test'
|
24
|
+
template 'boot.erb', 'config/boot.rb'
|
25
|
+
template 'setup.erb', 'config/setup.rb'
|
26
|
+
template 'settings.yml.erb', 'config/settings.yml'
|
27
|
+
template 'connections.yml.erb', 'config/connections.yml'
|
28
|
+
template 'debug_handler.erb', 'handlers/debug_handler.rb'
|
29
|
+
template 'hello_world.erb', 'handlers/hello_world.rb'
|
30
|
+
template 'rakefile.erb', 'Rakefile'
|
154
31
|
end
|
155
32
|
|
156
33
|
end
|
157
|
-
|
158
|
-
STDOUT.puts "Marvin - IRC Library / Framework for Ruby"
|
159
|
-
|
160
|
-
# Check if we have arguments, we run the normal
|
161
|
-
# thor task otherwise we just print the help
|
162
|
-
# message.
|
163
|
-
if ARGV.empty?
|
164
|
-
Marvin.new.help
|
165
|
-
else
|
166
|
-
Marvin.start
|
167
|
-
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class KeikiThwopper < Marvin::Base
|
2
|
+
|
3
|
+
FROM_REGEXP = /^(sutto)/i
|
4
|
+
THWOP_REGEXP = /(t+h+w+o+m*p+|stab|kill)/i
|
5
|
+
|
6
|
+
MESSAGES = [
|
7
|
+
"mwahahahaha",
|
8
|
+
"you totally deserved it",
|
9
|
+
"oi! leave 'em alone!",
|
10
|
+
"say hello to my little friend",
|
11
|
+
"you know, they could have liked that?"
|
12
|
+
]
|
13
|
+
|
14
|
+
on_event :incoming_action, :thwop_back
|
15
|
+
|
16
|
+
def thwop_back
|
17
|
+
return if !from || from !~ FROM_REGEXP || options.message !~ THWOP_REGEXP
|
18
|
+
action "#{$1}s #{from} (#{MESSAGES[rand(MESSAGES.length)]})"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/handlers/tweet_tweet.rb
CHANGED
@@ -1,30 +1,30 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
require 'active_support'
|
3
1
|
require "marvin/irc/event"
|
4
2
|
|
5
3
|
module Marvin
|
6
4
|
class AbstractClient
|
7
5
|
|
8
|
-
|
6
|
+
is :dispatchable, :loggable
|
9
7
|
|
10
|
-
def initialize(opts
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
8
|
+
def initialize(opts)
|
9
|
+
opts = opts.to_nash if opts.is_a?(Hash)
|
10
|
+
@connection_config = opts.dup # Copy the options so we can use them to reconnect.
|
11
|
+
@server = opts.server
|
12
|
+
@port = opts.port
|
13
|
+
@default_channels = opts.channels
|
14
|
+
@nicks = opts.nicks || []
|
15
|
+
@pass = opts.pass
|
17
16
|
end
|
18
17
|
|
19
|
-
cattr_accessor :events, :configuration, :
|
20
|
-
attr_accessor :channels, :nickname, :server, :port, :nicks, :pass,
|
18
|
+
cattr_accessor :events, :configuration, :is_setup, :connections, :development
|
19
|
+
attr_accessor :channels, :nickname, :server, :port, :nicks, :pass,
|
20
|
+
:disconnect_expected, :connection_config
|
21
21
|
|
22
22
|
# Set the default values for the variables
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
23
|
+
@@events = []
|
24
|
+
@@configuration = Marvin::Nash.new
|
25
|
+
@@connections = []
|
26
|
+
@@development = false
|
27
|
+
|
28
28
|
# Initializes the instance variables used for the
|
29
29
|
# current connection, dispatching a :client_connected event
|
30
30
|
# once it has finished. During this process, it will
|
@@ -32,78 +32,79 @@ module Marvin
|
|
32
32
|
def process_connect
|
33
33
|
self.class.setup
|
34
34
|
logger.info "Initializing the current instance"
|
35
|
-
|
36
|
-
|
35
|
+
@channels = []
|
36
|
+
connections << self
|
37
37
|
logger.info "Setting the client for each handler"
|
38
|
-
|
38
|
+
setup_handlers
|
39
39
|
logger.info "Dispatching the default :client_connected event"
|
40
40
|
dispatch :client_connected
|
41
41
|
end
|
42
42
|
|
43
43
|
def process_disconnect
|
44
|
-
logger.info "Handling disconnect for #{
|
45
|
-
|
44
|
+
logger.info "Handling disconnect for #{host_with_port}"
|
45
|
+
connections.delete(self)
|
46
46
|
dispatch :client_disconnected
|
47
|
-
unless
|
48
|
-
logger.warn "
|
49
|
-
self.class.add_reconnect
|
47
|
+
unless @disconnect_expected
|
48
|
+
logger.warn "Unexpectly lost connection to server; adding reconnect"
|
49
|
+
self.class.add_reconnect @connection_config
|
50
50
|
else
|
51
|
-
Marvin::Loader.stop! if
|
51
|
+
Marvin::Loader.stop! if connections.blank?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def setup_handlers
|
56
|
+
handlers.each { |h| h.client = self if h.respond_to?(:client=) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def process_development
|
60
|
+
if @@development
|
61
|
+
Marvin::Reloading.reload!
|
62
|
+
setup_handlers
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
66
|
+
def dispatch(*args)
|
67
|
+
process_development
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
55
71
|
# Sets the current class-wide settings of this IRC Client
|
56
72
|
# to either an OpenStruct or the results of #to_hash on
|
57
73
|
# any other value that is passed in.
|
58
74
|
def self.configuration=(config)
|
59
|
-
|
75
|
+
config = Marvin::Nash.new(config.to_hash) unless config.is_a?(Marvin::Nash)
|
76
|
+
@@configuration = config.normalized
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.setup?
|
80
|
+
@setup ||= false
|
60
81
|
end
|
61
82
|
|
62
|
-
# Initializes class-wide settings and those that
|
63
|
-
# are required such as the logger. by default, it
|
64
|
-
# will convert the channel option of the configuration
|
65
|
-
# to be channels - hence normalising it into a format
|
66
|
-
# that is more widely used throughout the client.
|
67
83
|
def self.setup
|
68
|
-
return if
|
69
|
-
|
70
|
-
|
71
|
-
|
84
|
+
return if setup?
|
85
|
+
configure
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.configure
|
89
|
+
config = Marvin::Nash.new
|
90
|
+
config.merge! Marvin::Settings.configuration
|
91
|
+
if block_given?
|
92
|
+
yield(nash = Marvin::Nash.new)
|
93
|
+
config.merge! nash
|
72
94
|
end
|
73
|
-
|
74
|
-
|
95
|
+
@@configuration = config
|
96
|
+
# Help is only currently available on an instance running
|
97
|
+
# distributed handler.
|
98
|
+
Marvin::CoreCommands.register! unless Marvin::Distributed::Handler.registered?
|
99
|
+
@setup = true
|
75
100
|
end
|
76
101
|
|
77
102
|
## Handling all of the the actual client stuff.
|
78
103
|
|
79
104
|
def receive_line(line)
|
80
105
|
dispatch :incoming_line, :line => line
|
81
|
-
event = Marvin::Settings.
|
82
|
-
dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
|
83
|
-
end
|
84
|
-
|
85
|
-
# Default handlers
|
86
|
-
|
87
|
-
# The default handler for all things initialization-related
|
88
|
-
# on the client. Usually, this will send the user command,
|
89
|
-
# set out nick, join all of the channels / rooms we wish
|
90
|
-
# to be in and if a password is specified in the configuration,
|
91
|
-
# it will also attempt to identify us.
|
92
|
-
def handle_client_connected(opts = {})
|
93
|
-
logger.info "About to handle client connected"
|
94
|
-
# If the pass is set
|
95
|
-
unless self.pass.blank?
|
96
|
-
logger.info "Sending pass for connection"
|
97
|
-
command :pass, self.pass
|
98
|
-
end
|
99
|
-
# IRC Connection is establish so we send all the required commands to the server.
|
100
|
-
logger.info "Setting default nickname"
|
101
|
-
default_nickname = self.nicks.shift
|
102
|
-
nick default_nickname
|
103
|
-
logger.info "sending user command"
|
104
|
-
command :user, self.configuration.user, "0", "*", Marvin::Util.last_param(self.configuration.name)
|
105
|
-
rescue Exception => e
|
106
|
-
Marvin::ExceptionTracker.log(e)
|
106
|
+
event = Marvin::Settings.parser.parse(line)
|
107
|
+
dispatch(event.to_incoming_event_name, event.to_hash) unless event.nil?
|
107
108
|
end
|
108
109
|
|
109
110
|
def default_channels
|
@@ -115,145 +116,30 @@ module Marvin
|
|
115
116
|
end
|
116
117
|
|
117
118
|
def host_with_port
|
118
|
-
@host_with_port ||= "#{
|
119
|
+
@host_with_port ||= "#{server}:#{port}"
|
119
120
|
end
|
120
121
|
|
121
122
|
def nicks
|
122
123
|
if @nicks.blank? && !@nicks_loaded
|
123
124
|
logger.info "Setting default nick list"
|
124
125
|
@nicks = []
|
125
|
-
@nicks <<
|
126
|
-
@nicks +=
|
126
|
+
@nicks << configuration.nick if configuration.nick?
|
127
|
+
@nicks += configuration.nicks.to_a if configuration.nicks?
|
127
128
|
@nicks.compact!
|
129
|
+
raise "No initial nicks for #{host_with_port}" if @nicks.blank?
|
128
130
|
@nicks_loaded = true
|
129
131
|
end
|
130
132
|
return @nicks
|
131
133
|
end
|
132
134
|
|
133
|
-
#
|
134
|
-
|
135
|
-
|
136
|
-
logger.info "Received Incoming Ping - Handling with a PONG"
|
137
|
-
pong(opts[:data])
|
138
|
-
end
|
139
|
-
|
140
|
-
# TODO: Get the correct mapping for a given
|
141
|
-
# Code.
|
142
|
-
def handle_incoming_numeric(opts = {})
|
143
|
-
case opts[:code]
|
144
|
-
when Marvin::IRC::Replies[:RPL_WELCOME]
|
145
|
-
handle_welcome
|
146
|
-
when Marvin::IRC::Replies[:ERR_NICKNAMEINUSE]
|
147
|
-
handle_nick_taken
|
148
|
-
end
|
149
|
-
code = opts[:code].to_i
|
150
|
-
args = Marvin::Util.arguments(opts[:data])
|
151
|
-
dispatch :incoming_numeric_processed, :code => code, :data => args
|
152
|
-
end
|
153
|
-
|
154
|
-
def handle_welcome
|
155
|
-
logger.info "Say hello to my little friend - Got welcome"
|
156
|
-
# If a password is specified, we will attempt to message
|
157
|
-
# NickServ to identify ourselves.
|
158
|
-
say ":IDENTIFY #{self.configuration.password}", "NickServ" unless self.configuration.password.blank?
|
159
|
-
# Join the default channels IF they're already set
|
160
|
-
# Note that Marvin::IRC::Client.connect will set them AFTER this stuff is run.
|
161
|
-
self.default_channels.each { |c| self.join(c) }
|
162
|
-
end
|
135
|
+
# Break it down into a couple of different files.
|
136
|
+
require 'marvin/client/default_handlers'
|
137
|
+
require 'marvin/client/actions'
|
163
138
|
|
164
|
-
|
165
|
-
# on the server. It will attempt to get the nicknickname from
|
166
|
-
# the nicknames part of the configuration (if available) and
|
167
|
-
# will then call #nick to change the nickname.
|
168
|
-
def handle_nick_taken
|
169
|
-
logger.info "Nickname '#{self.nickname}' on #{self.server} taken, trying next."
|
170
|
-
logger.info "Available Nicknames: #{self.nicks.empty? ? "None" : self.nicks.join(", ")}"
|
171
|
-
if !self.nicks.empty?
|
172
|
-
logger.info "Getting next nickname to switch"
|
173
|
-
next_nick = self.nicks.shift # Get the next nickname
|
174
|
-
logger.info "Attemping to set nickname to '#{next_nick}'"
|
175
|
-
nick next_nick
|
176
|
-
else
|
177
|
-
logger.fatal "No Nicknames available - QUITTING"
|
178
|
-
quit
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
## General IRC Functions
|
183
|
-
|
184
|
-
# Sends a specified command to the server.
|
185
|
-
# Takes name (e.g. :privmsg) and all of the args.
|
186
|
-
# Very simply formats them as a string correctly
|
187
|
-
# and calls send_data with the results.
|
188
|
-
def command(name, *args)
|
189
|
-
# First, get the appropriate command
|
190
|
-
name = name.to_s.upcase
|
191
|
-
args = args.flatten.compact
|
192
|
-
irc_command = "#{name} #{args.join(" ").strip}\r\n"
|
193
|
-
send_line irc_command
|
194
|
-
end
|
195
|
-
|
196
|
-
def join(channel)
|
197
|
-
channel = Marvin::Util.channel_name(channel)
|
198
|
-
# Record the fact we're entering the room.
|
199
|
-
# TODO: Refactor to only add the channel when we receive confirmation we've joined.
|
200
|
-
self.channels << channel
|
201
|
-
command :JOIN, channel
|
202
|
-
logger.info "Joined channel #{channel}"
|
203
|
-
dispatch :outgoing_join, :target => channel
|
204
|
-
end
|
205
|
-
|
206
|
-
def part(channel, reason = nil)
|
207
|
-
channel = Marvin::Util.channel_name(channel)
|
208
|
-
if self.channels.include?(channel)
|
209
|
-
command :part, channel, Marvin::Util.last_param(reason)
|
210
|
-
dispatch :outgoing_part, :target => channel, :reason => reason
|
211
|
-
logger.info "Parted from room #{channel}#{reason ? " - #{reason}" : ""}"
|
212
|
-
else
|
213
|
-
logger.warn "Tried to disconnect from #{channel} - which you aren't a part of"
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def quit(reason = nil)
|
218
|
-
self.disconnect_expected = true
|
219
|
-
logger.info "Preparing to part from #{self.channels.size} channels"
|
220
|
-
self.channels.to_a.each do |chan|
|
221
|
-
logger.info "Parting from #{chan}"
|
222
|
-
self.part chan, reason
|
223
|
-
end
|
224
|
-
logger.info "Parted from all channels, quitting"
|
225
|
-
command :quit
|
226
|
-
dispatch :quit
|
227
|
-
# Remove the connections from the pool
|
228
|
-
self.connections.delete(self)
|
229
|
-
logger.info "Quit from server"
|
230
|
-
end
|
231
|
-
|
232
|
-
def msg(target, message)
|
233
|
-
command :privmsg, target, Marvin::Util.last_param(message)
|
234
|
-
logger.info "Message sent to #{target} - #{message}"
|
235
|
-
dispatch :outgoing_message, :target => target, :message => message
|
236
|
-
end
|
237
|
-
|
238
|
-
def action(target, message)
|
239
|
-
action_text = Marvin::Util.last_param "\01ACTION #{message.strip}\01"
|
240
|
-
command :privmsg, target, action_text
|
241
|
-
dispatch :outgoing_action, :target => target, :message => message
|
242
|
-
logger.info "Action sent to #{target} - #{message}"
|
243
|
-
end
|
244
|
-
|
245
|
-
def pong(data)
|
246
|
-
command :pong, data
|
247
|
-
dispatch :outgoing_pong
|
248
|
-
logger.info "PONG sent to #{data}"
|
249
|
-
end
|
139
|
+
protected
|
250
140
|
|
251
|
-
def
|
252
|
-
|
253
|
-
command :nick, new_nick
|
254
|
-
self.nickname = new_nick
|
255
|
-
dispatch :outgoing_nick, :new_nick => new_nick
|
256
|
-
logger.info "Nickname changed to #{new_nick}"
|
141
|
+
def util
|
142
|
+
Marvin::Util
|
257
143
|
end
|
258
144
|
|
259
145
|
end
|
@@ -1,27 +1,25 @@
|
|
1
1
|
module Marvin
|
2
|
-
# An abstract class for an IRC protocol
|
3
|
-
# Parser. Used as a basis for expirimentation.
|
4
2
|
class AbstractParser
|
5
3
|
|
6
|
-
def self.parse(line)
|
7
|
-
return self.new(line.strip).to_event
|
8
|
-
end
|
9
|
-
|
10
4
|
attr_accessor :line, :command, :event
|
11
5
|
|
12
6
|
# Instantiates a parser instance, attempts to
|
13
7
|
# parse it for it's command and it's event.
|
14
8
|
def initialize(line)
|
15
|
-
|
16
|
-
|
17
|
-
|
9
|
+
@line = line
|
10
|
+
@command = self.class.parse!(line)
|
11
|
+
@event = @command.to_event unless @command.blank?
|
18
12
|
end
|
19
13
|
|
20
14
|
def to_event
|
21
|
-
|
15
|
+
@event
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.parse(line)
|
19
|
+
new(line.strip).to_event
|
22
20
|
end
|
23
21
|
|
24
|
-
|
22
|
+
protected
|
25
23
|
|
26
24
|
def self.parse!(line)
|
27
25
|
raise NotImplementedError, "Must be implemented in a subclass"
|