Sutto-marvin 0.4.0 → 0.8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
|
3
|
-
module Marvin
|
4
|
-
module IRC
|
5
|
-
module Server
|
6
|
-
class BaseConnection < EventMachine::Protocols::LineAndTextProtocol
|
7
|
-
|
8
|
-
attr_accessor :port, :host, :started_at
|
9
|
-
|
10
|
-
# Our initialize method
|
11
|
-
def initialize(opts = {})
|
12
|
-
super
|
13
|
-
@buffer = []
|
14
|
-
@port = opts[:port]
|
15
|
-
@host = opts[:host]
|
16
|
-
@started_at = opts[:started_at] || Time.now
|
17
|
-
end
|
18
|
-
|
19
|
-
attr_accessor :connection_implementation, :buffer
|
20
|
-
|
21
|
-
# Receive the line, processing as it needs to be.
|
22
|
-
# Not that we have a conditional check to setup
|
23
|
-
# the correct connection
|
24
|
-
def receive_line(line)
|
25
|
-
Marvin::Logger.debug "<< #{line}"
|
26
|
-
if !@connection_implementation.nil?
|
27
|
-
@connection_implementation.receive_line(line)
|
28
|
-
elsif line[0..3] == "USER"
|
29
|
-
@buffer << line
|
30
|
-
self.connection_implementation = UserConnection.new(self, @buffer)
|
31
|
-
@buffer = nil
|
32
|
-
elsif line[0..5] == "SERVER"
|
33
|
-
@buffer << line
|
34
|
-
self.connection_implementation = ServerConnection.new(self, @buffer)
|
35
|
-
@buffer = nil
|
36
|
-
else
|
37
|
-
@buffer << line
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def send_line(line)
|
42
|
-
Marvin::Logger.debug ">> #{line.strip}"
|
43
|
-
line += "\r\n" unless line[-2..-1] == "\r\n"
|
44
|
-
send_data line
|
45
|
-
end
|
46
|
-
|
47
|
-
def kill_connection!
|
48
|
-
close_connection_after_writing
|
49
|
-
end
|
50
|
-
|
51
|
-
# Do things on the unbind
|
52
|
-
def unbind
|
53
|
-
super # Call the old version
|
54
|
-
@connection_implementation.process_disconnect
|
55
|
-
end
|
56
|
-
|
57
|
-
# Do things on the connection implementation
|
58
|
-
def post_init
|
59
|
-
super
|
60
|
-
send_line "NOTICE AUTH :Marvin Server v#{Marvin.version} initialized, welcome."
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,115 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class Channel
|
3
|
-
include Marvin::Dispatchable
|
4
|
-
|
5
|
-
cattr_accessor :logger
|
6
|
-
self.logger = Marvin::Logger
|
7
|
-
|
8
|
-
attr_accessor :name, :members, :name, :topic, :operators, :mode
|
9
|
-
|
10
|
-
def inspect
|
11
|
-
"#<Marvin::IRC::Server::Channel name='#{name}' topic='#{@topic}' members=[#{self.members.map { |m| m.nick.inspect}.join(", ")}]>"
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(name)
|
15
|
-
@name = name
|
16
|
-
@members = []
|
17
|
-
@operators = []
|
18
|
-
@topic = ""
|
19
|
-
@mode = ""
|
20
|
-
logger.info "Created the channel #{name}"
|
21
|
-
dispatch :channel_created, :channel => self
|
22
|
-
end
|
23
|
-
|
24
|
-
def member?(user)
|
25
|
-
@members.include?(user)
|
26
|
-
end
|
27
|
-
|
28
|
-
def each_member(&blk)
|
29
|
-
members.each(&blk)
|
30
|
-
end
|
31
|
-
|
32
|
-
def add(user)
|
33
|
-
logger.info "Adding user #{user.nick} to #{@name}"
|
34
|
-
@operators << user if needs_op?
|
35
|
-
@members << user
|
36
|
-
end
|
37
|
-
|
38
|
-
def remove(user)
|
39
|
-
@members.delete(user)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Ind. operations on the room
|
43
|
-
|
44
|
-
def join(user)
|
45
|
-
return false if member?(user)
|
46
|
-
# Otherwise, we add a user
|
47
|
-
add user
|
48
|
-
@members.each { |m| m.notify :join, @name, :prefix => user.prefix }
|
49
|
-
dispatch :outgoing_join, :target => @name, :nick => user.nick
|
50
|
-
return true
|
51
|
-
end
|
52
|
-
|
53
|
-
def part(user, message = nil)
|
54
|
-
logger.debug "Getting part from #{user.inspect} w/ #{message}"
|
55
|
-
return false if !member?(user)
|
56
|
-
@members.each { |m| m.notify :part, @name, user.nick, message, :prefix => user.prefix }
|
57
|
-
remove user
|
58
|
-
# TODO: Remove channel from ChannelStore if it's empty.
|
59
|
-
dispatch :outgoing_part, :target => @name, :user => user, :message => message
|
60
|
-
check_emptyness!
|
61
|
-
return true
|
62
|
-
end
|
63
|
-
|
64
|
-
def quit(user, message = nil)
|
65
|
-
remove user
|
66
|
-
@members.each { |m| m.notify :quit, @name, message, :prefix => user.prefix }
|
67
|
-
# TODO: Remove channel from the store if it's empty
|
68
|
-
dispatch :outgoing_quit, :target => @name, :user => user, :message => message
|
69
|
-
check_emptyness!
|
70
|
-
end
|
71
|
-
|
72
|
-
def message(user, message, virtual = false)
|
73
|
-
@members.each do |m|
|
74
|
-
if virtual || user != m
|
75
|
-
m.notify(:privmsg, @name, ":#{message}", :prefix => user.prefix, :virtual => virtual)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
dispatch :outgoing_message, :target => self, :user => user, :message => message, :virtual => virtual
|
79
|
-
end
|
80
|
-
|
81
|
-
def notice(user, message)
|
82
|
-
@members.each { |m| m.notify :notice, @name, ":#{message}", :prefix => user.prefix unless user == m }
|
83
|
-
dispatch :outgoing_notice, :target => self, :user => user, :message => message
|
84
|
-
end
|
85
|
-
|
86
|
-
def topic(user = nil, t = nil)
|
87
|
-
return @topic if t.blank?
|
88
|
-
logger.info "Getting topic for '#{@name}' - #{t.inspect}"
|
89
|
-
@topic = t
|
90
|
-
@members.each { |m| m.notify :topic, @name, ":#{t}", :prefix => user.prefix }
|
91
|
-
dispatch :outgoing_topic, :target => @name, :user => user, :topic => t
|
92
|
-
return @topic
|
93
|
-
end
|
94
|
-
|
95
|
-
def mode(user)
|
96
|
-
@operators.include?(user) ? "@" : ""
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
def needs_op?
|
102
|
-
@operators.empty? && @members.empty?
|
103
|
-
end
|
104
|
-
|
105
|
-
def check_emptyness!
|
106
|
-
destroy if @members.empty?
|
107
|
-
end
|
108
|
-
|
109
|
-
def destroy
|
110
|
-
Marvin::IRC::Server::ChannelStore.delete(@name)
|
111
|
-
dispatch :channel_destroyed, :channel => self
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class NamedStore
|
3
|
-
|
4
|
-
def self.new(key_plural, ref_value, &blk)
|
5
|
-
klass = Class.new(Hash) do
|
6
|
-
alias_method :"each_#{ref_value}", :each_value
|
7
|
-
alias_method key_plural.to_sym, :keys
|
8
|
-
end
|
9
|
-
klass.class_eval(&blk) unless blk.blank?
|
10
|
-
return klass.new
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'drb'
|
2
|
-
require 'rinda/ring'
|
3
|
-
module Marvin
|
4
|
-
module IRC
|
5
|
-
module Server
|
6
|
-
|
7
|
-
# Make sure that a proxy object is used vs. the real thing.
|
8
|
-
[Channel, AbstractConnection, User, NamedStore].each do |c|
|
9
|
-
c.class_eval { include DRbUndumped }
|
10
|
-
end
|
11
|
-
|
12
|
-
# A DRb interface to post / receive messages from the
|
13
|
-
# a running server instance. Used for things such as
|
14
|
-
# posting status updated directly on the server.
|
15
|
-
class RemoteInterface
|
16
|
-
include DRbUndumped
|
17
|
-
|
18
|
-
# Attempts to find a running IRC server,
|
19
|
-
# returning an instance of it if it exists.
|
20
|
-
def self.primary
|
21
|
-
DRb.start_service
|
22
|
-
begin
|
23
|
-
rs = Rinda::RingFinger.primary
|
24
|
-
server = rs.read_all([:marvin_server, Marvin::Settings.distributed_namespace, nil])
|
25
|
-
if server.empty?
|
26
|
-
return nil
|
27
|
-
else
|
28
|
-
# Return the first element in the list of servers, getting it's servers instance.
|
29
|
-
return server.first.last
|
30
|
-
end
|
31
|
-
rescue
|
32
|
-
return nil
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.start
|
37
|
-
DRb.start_service
|
38
|
-
instance = self.new # Create the new instance
|
39
|
-
begin
|
40
|
-
rs = Rinda::RingFinger.primary
|
41
|
-
renewer = Rinda::SimpleRenewer.new
|
42
|
-
tuple = [:marvin_server, Marvin::Settings.distributed_namespace, instance]
|
43
|
-
Marvin::Logger.info "Publishing information about service to the tuplespace"
|
44
|
-
Marvin::Logger.debug "Pushing #{tuple.inspect} to #{rs.__drburi}"
|
45
|
-
rs.write(tuple, renewer)
|
46
|
-
rescue
|
47
|
-
Marvin::Logger.warn "No ring server found - remote interface not running"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# Returns an array of all channels
|
52
|
-
def channels
|
53
|
-
Marvin::IRC::Server::ChannelStore.values
|
54
|
-
end
|
55
|
-
|
56
|
-
# Returns the names of all channels
|
57
|
-
def channel_names
|
58
|
-
Marvin::IRC::Server::ChannelStore.keys
|
59
|
-
end
|
60
|
-
|
61
|
-
# Returns the channel with the given name.
|
62
|
-
def channel(name)
|
63
|
-
Marvin::IRC::Server::ChannelStore[name]
|
64
|
-
end
|
65
|
-
|
66
|
-
# Send an action from a user to a specific
|
67
|
-
# channel, using from nick as a facade.
|
68
|
-
def message(from_nick, target, contents)
|
69
|
-
u = (Marvin::IRC::Server::UserStore[from_nick.to_s.downcase] ||= VirtualUserConnection.new(from_nick))
|
70
|
-
Marvin::Logger.info "#{from_nick} (#{u.inspect}) messaging #{target}: #{contents}"
|
71
|
-
u.send_message(target, contents) unless u.blank?
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,140 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server::User::HandleMixin
|
2
|
-
|
3
|
-
def handle_incoming_pass(opts = {})
|
4
|
-
@password = opts[:password]
|
5
|
-
end
|
6
|
-
|
7
|
-
def handle_incoming_user(opts = {})
|
8
|
-
@user = opts[:user]
|
9
|
-
@mode = opts[:mode]
|
10
|
-
@real_name = opts[:real_name]
|
11
|
-
welcome_if_complete!
|
12
|
-
end
|
13
|
-
|
14
|
-
def handle_incoming_nick(opts = {})
|
15
|
-
nick = opts[:new_nick]
|
16
|
-
if !nick.blank? && !Marvin::IRC::Server::UserStore.nick_taken?(nick.downcase)
|
17
|
-
if !(new_nick = @nick.nil?)
|
18
|
-
logger.info "Reclaiming nick (if taken)"
|
19
|
-
Marvin::IRC::Server::UserStore.reclaim(nick)
|
20
|
-
logger.debug "Notifying all users of nick change: #{@nick} => #{nick}"
|
21
|
-
# Get all users and let them now we've changed nick from @nick to nick
|
22
|
-
users = [self]
|
23
|
-
@channels.each do |c|
|
24
|
-
users += c.members
|
25
|
-
end
|
26
|
-
users.uniq.each { |u| u.notify :NICK, nick, :prefix => prefix }
|
27
|
-
dispatch :outgoing_nick, :nick => @nick, :new_nick => nick
|
28
|
-
end
|
29
|
-
# Update the store values
|
30
|
-
Marvin::IRC::Server::UserStore.delete(@nick.downcase) unless @nick.blank?
|
31
|
-
Marvin::IRC::Server::UserStore[nick.downcase] = self
|
32
|
-
# Change the nick and reset the number of attempts
|
33
|
-
@nick = nick
|
34
|
-
@nick_attempts = 0
|
35
|
-
# Finally, update the prefix.
|
36
|
-
update_prefix!
|
37
|
-
welcome_if_complete! if new_nick
|
38
|
-
elsif Marvin::IRC::Server::UserStore[nick.downcase] != self
|
39
|
-
# The nick is taken
|
40
|
-
# TODO: Remove hard coded nick attempts limit
|
41
|
-
if @nick_attempts > 5
|
42
|
-
# Handle abort here.
|
43
|
-
logger.debug "User has gone over nick attempt limits - Killing connection."
|
44
|
-
kill_connection!
|
45
|
-
dispatch :outgoing_nick_killed, :client => self
|
46
|
-
else
|
47
|
-
logger.debug "Noting users nick is taken, warning"
|
48
|
-
err :NICKNAMEINUSE, "*", nick, ":Nickname is already in use."
|
49
|
-
@nick_attempts += 1
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def handle_incoming_join(opts = {})
|
55
|
-
return if @prefix.blank?
|
56
|
-
opts[:target].split(",").each do |channel|
|
57
|
-
# If the channel name is invalud, let the user known and dispatch
|
58
|
-
# the correct event.
|
59
|
-
if channel !~ Marvin::IRC::Server::UserConnection::CHANNEL
|
60
|
-
logger.debug "Attempted to join invalid channel name '#{channel}'"
|
61
|
-
err :NOSUCHCHANNEL, channel, ":That channel doesn't exist"
|
62
|
-
dispatch :invalid_channel_name, :channel => channel, :client => self
|
63
|
-
return
|
64
|
-
end
|
65
|
-
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
66
|
-
if chan.join(self)
|
67
|
-
rpl :TOPIC, channel, ":#{chan.topic.blank? ? "There is no topic" : chan.topic}"
|
68
|
-
rpl :NAMREPLY, "=", channel, ":#{chan.members.map { |m| m.nick }.join(" ")}"
|
69
|
-
rpl :ENDOFNAMES, channel, ":End of /NAMES list."
|
70
|
-
@channels << chan
|
71
|
-
else
|
72
|
-
logger.debug "Couldn't join channel '#{channel}'"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def handle_incoming_ping(opts = {})
|
78
|
-
command :PONG, ":#{opts[:data]}"
|
79
|
-
end
|
80
|
-
|
81
|
-
def handle_incoming_pong(opts = {})
|
82
|
-
# Decrease the ping count.
|
83
|
-
@ping_count -= 1
|
84
|
-
@ping_count = 0 if @ping_count < 0
|
85
|
-
logger.debug "Got pong: #{opts[:data]}"
|
86
|
-
end
|
87
|
-
|
88
|
-
def handle_incoming_message(opts = {})
|
89
|
-
return if @prefix.blank?
|
90
|
-
unless (t = target_from(opts[:target])).blank?
|
91
|
-
t.message self, opts[:message]
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def handle_incoming_notice(opts = {})
|
96
|
-
return if @prefix.blank?
|
97
|
-
unless (t = target_from(opts[:target])).blank?
|
98
|
-
t.notice self, opts[:message]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def handle_incoming_part(opts = {})
|
103
|
-
t = opts[:target].downcase
|
104
|
-
if !(chan = Marvin::IRC::Server::ChannelStore[t]).blank?
|
105
|
-
if chan.part(self, opts[:message])
|
106
|
-
@channels.delete(chan)
|
107
|
-
else
|
108
|
-
err :NOTONCHANNEL, opts[:target], ":Not a member of that channel"
|
109
|
-
end
|
110
|
-
else
|
111
|
-
err :NOSUCHNICK, opts[:target], ":No such nick/channel"
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def handle_incoming_quit(opts = {})
|
116
|
-
return unless @alive
|
117
|
-
@alive = false
|
118
|
-
@channels.each { |c| c.quit(self, opts[:message]) }
|
119
|
-
kill_connection!
|
120
|
-
end
|
121
|
-
|
122
|
-
def handle_incoming_topic(opts = {})
|
123
|
-
return if @prefix.blank? || opts[:target].blank?
|
124
|
-
c = Marvin::IRC::Server::ChannelStore[opts[:target].downcase]
|
125
|
-
return if c.blank?
|
126
|
-
if !@channels.include?(c)
|
127
|
-
err :NOTONCHANNEL, opts[:target], ":Not a member of that channel"
|
128
|
-
elsif opts[:topic].blank?
|
129
|
-
t = c.topic
|
130
|
-
if t.blank?
|
131
|
-
rpl :NOTOPIC, c.name, ":No topic is set"
|
132
|
-
else
|
133
|
-
rpl :TOPIC, c.name, ":#{t}"
|
134
|
-
end
|
135
|
-
else
|
136
|
-
c.topic self, opts[:topic].strip
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
@@ -1,134 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class UserConnection < AbstractConnection
|
3
|
-
USER_MODES = "aAbBcCdDeEfFGhHiIjkKlLmMnNopPQrRsStUvVwWxXyYzZ0123459*@"
|
4
|
-
CHANNEL_MODES = "bcdefFhiIklmnoPqstv"
|
5
|
-
CHANNEL = /^[\&\#]+/
|
6
|
-
|
7
|
-
include User::HandleMixin
|
8
|
-
|
9
|
-
attr_accessor :nick, :host, :user, :prefix, :password, :mode,
|
10
|
-
:real_name, :nick_attempts, :channels, :ping_count
|
11
|
-
|
12
|
-
def inspect
|
13
|
-
"#<Marvin::IRC::Server::UserConnection nick='#{@nick}' host='#{@host}' real_name='#{@real_name}' channels=[#{self.channels.map { |c| c.name.inspect}.join(", ")}]>"
|
14
|
-
end
|
15
|
-
|
16
|
-
def initialize(base, buffer = [])
|
17
|
-
super
|
18
|
-
@nick_attempts = 0
|
19
|
-
@channels = []
|
20
|
-
@ping_count = 0
|
21
|
-
end
|
22
|
-
|
23
|
-
# Notify is essentially command BUT it
|
24
|
-
# requires that the prefix is set.
|
25
|
-
def notify(command, *args)
|
26
|
-
opts = args.extract_options!
|
27
|
-
return if opts[:prefix].blank?
|
28
|
-
command command, *(args << opts)
|
29
|
-
end
|
30
|
-
|
31
|
-
# Notification messages
|
32
|
-
|
33
|
-
def send_message(target, message)
|
34
|
-
t = target_from(target)
|
35
|
-
logger.debug "Sending #{t.inspect} #{message.inspect} from #{self.inspect}"
|
36
|
-
t.message(self, message) unless t.blank?
|
37
|
-
end
|
38
|
-
|
39
|
-
def message(user, message, virtual = false)
|
40
|
-
notify :PRIVMSG, @nick, ":#{message}", :prefix => user.prefix, :virtual => virtual
|
41
|
-
dispatch :outgoing_message, :user => user, :message => message, :target => self, :virtual => virtual
|
42
|
-
end
|
43
|
-
|
44
|
-
def notice(user, message)
|
45
|
-
notify :NOTICE, @nick, ":#{message}", :prefix => user.prefix
|
46
|
-
dispatch :outgoing_notice, :user => user, :message => message, :target => self
|
47
|
-
end
|
48
|
-
|
49
|
-
# Get the user / channel targeted by a particular request.
|
50
|
-
|
51
|
-
def target_from(target)
|
52
|
-
case target
|
53
|
-
when CHANNEL
|
54
|
-
chan = Marvin::IRC::Server::ChannelStore[target.downcase]
|
55
|
-
if chan.nil?
|
56
|
-
rpl :NOSUCHNICK, target, ":No such nick/channel"
|
57
|
-
elsif !chan.member?(self)
|
58
|
-
err :CANNOTSENDTOCHAN, target, ":Cannot send to channel"
|
59
|
-
else
|
60
|
-
return chan
|
61
|
-
end
|
62
|
-
else
|
63
|
-
user = Marvin::IRC::Server::UserStore[target.downcase]
|
64
|
-
if user.nil?
|
65
|
-
err :NOSUCHNICK, target, ":No suck nick/channel"
|
66
|
-
else
|
67
|
-
return user
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Implementations for connect / disconnect
|
73
|
-
|
74
|
-
def process_connect
|
75
|
-
super
|
76
|
-
end
|
77
|
-
|
78
|
-
def process_disconnect
|
79
|
-
super
|
80
|
-
end
|
81
|
-
|
82
|
-
def kill_connection!
|
83
|
-
@connection.kill_connection!
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def welcome_if_complete!
|
89
|
-
update_prefix!
|
90
|
-
# Next, send the MOTD and other misc. stuff
|
91
|
-
return if @welcomed || @prefix.blank?
|
92
|
-
rpl :WELCOME, @nick, ":Welcome to Marvin Server - #{@prefix}"
|
93
|
-
rpl :YOURHOST, @nick, ":Your host is #{server_host}, running version #{Marvin.version}"
|
94
|
-
rpl :CREATED, @nick, ":This server was created #{@connection.started_at}"
|
95
|
-
rpl :MYINFO, @nick, ":#{server_host} #{Marvin.version} #{USER_MODES} #{CHANNEL_MODES}"
|
96
|
-
rpl :MOTDSTART, @nick, ":- MOTD"
|
97
|
-
rpl :MOTD, @nick, ":- Welcome to Marvin Server, a Ruby + EventMachine ircd."
|
98
|
-
rpl :ENDOFMOTD, @nick, ":- End of /MOTD command."
|
99
|
-
@welcomed = true
|
100
|
-
end
|
101
|
-
|
102
|
-
def update_prefix!
|
103
|
-
@prefix = "#{@nick}!n=#{@user}@#{peer_name}" if details_complete?
|
104
|
-
end
|
105
|
-
|
106
|
-
def details_complete?
|
107
|
-
!@nick.nil? && !@user.nil?
|
108
|
-
end
|
109
|
-
|
110
|
-
def server_host
|
111
|
-
@connection.host
|
112
|
-
end
|
113
|
-
|
114
|
-
def server_port
|
115
|
-
@connection.port
|
116
|
-
end
|
117
|
-
|
118
|
-
def rpl(number, *args)
|
119
|
-
numeric Marvin::IRC::Replies["RPL_#{number.to_s.upcase}"], *args
|
120
|
-
end
|
121
|
-
|
122
|
-
def err(number, *args)
|
123
|
-
numeric Marvin::IRC::Replies["ERR_#{number.to_s.upcase}"], *args
|
124
|
-
end
|
125
|
-
|
126
|
-
def numeric(number, *args)
|
127
|
-
args << {} unless args[-1].is_a?(Hash)
|
128
|
-
args[-1][:prefix] ||= server_host
|
129
|
-
args.unshift(@nick) unless args.first == @nick
|
130
|
-
command(number.to_s, *args)
|
131
|
-
end
|
132
|
-
|
133
|
-
end
|
134
|
-
end
|
@@ -1,80 +0,0 @@
|
|
1
|
-
module Marvin::IRC::Server
|
2
|
-
class VirtualUserConnection
|
3
|
-
include Marvin::Dispatchable
|
4
|
-
|
5
|
-
CHANNEL = /^[\&\#]+/
|
6
|
-
|
7
|
-
attr_accessor :nick, :channels
|
8
|
-
|
9
|
-
def initialize(nick)
|
10
|
-
self.nick = nick
|
11
|
-
self.channels = []
|
12
|
-
end
|
13
|
-
|
14
|
-
def prefix
|
15
|
-
"#{@nick}!n=rruser@relayrelay.com"
|
16
|
-
end
|
17
|
-
|
18
|
-
def notify(*args)
|
19
|
-
Marvin::Logger.debug "Virtual User #{self.nick} got notify w/ #{args.inspect}"
|
20
|
-
end
|
21
|
-
|
22
|
-
# Notify the remote handler we've received a message
|
23
|
-
def message(user, message, virtual = false)
|
24
|
-
dispatch :received_message, :user => user, :message => message, :target => self unless virtual
|
25
|
-
end
|
26
|
-
|
27
|
-
def send_message(target, message)
|
28
|
-
t = target_from(target)
|
29
|
-
Marvin::Logger.debug "DRb Message from #{self.nick} to #{t.inspect}: #{message.inspect}"
|
30
|
-
if t.blank?
|
31
|
-
Marvin::Logger.debug "Target not found"
|
32
|
-
return nil
|
33
|
-
else
|
34
|
-
Marvin::Logger.debug "Sending message to #{t.inspect}"
|
35
|
-
return t.message(self, message, true)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def reclaim!
|
40
|
-
self.channels.each { |c| c.part(self, "Reclaiming nick for virtual user...") }
|
41
|
-
Marvin::IRC::Server::UserStore.delete(self.nick.downcase)
|
42
|
-
end
|
43
|
-
|
44
|
-
def join(channel)
|
45
|
-
return nil if channel !~ CHANNEL
|
46
|
-
chan = (Marvin::IRC::Server::ChannelStore[channel.downcase] ||= Marvin::IRC::Server::Channel.new(channel))
|
47
|
-
if chan.join(self)
|
48
|
-
@channels << channel
|
49
|
-
return chan
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class << self
|
54
|
-
|
55
|
-
def claimed?(nick)
|
56
|
-
Marvin::IRC::Server::UserStore.virtual?(nick)
|
57
|
-
end
|
58
|
-
|
59
|
-
def claim(nick)
|
60
|
-
unless Marvin::IRC::Server::UserStore[nick.downcase].blank?
|
61
|
-
return(Marvin::IRC::Server::UserStore[nick.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(nick))
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def target_from(target)
|
70
|
-
if target =~ CHANNEL
|
71
|
-
c = Marvin::IRC::Server::ChannelStore[target.downcase]
|
72
|
-
c = join(target) if c.nil? || !c.member?(self)
|
73
|
-
return c
|
74
|
-
else
|
75
|
-
return Marvin::IRC::Server::UserStore[target.downcase] ||= Marvin::IRC::Server::VirtualUserConnection.new(target)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
end
|
80
|
-
end
|