mod_spox 0.2.0 → 0.3.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/CHANGELOG +31 -1
- data/LICENSE +674 -0
- data/README.rdoc +73 -0
- data/bin/mod_spox +28 -28
- data/data/mod_spox/extras/AOLSpeak.rb +2 -3
- data/data/mod_spox/extras/AutoKick.rb +10 -23
- data/data/mod_spox/extras/AutoMode.rb +12 -23
- data/data/mod_spox/extras/Bash.rb +55 -0
- data/data/mod_spox/extras/Bouncer.rb +85 -57
- data/data/mod_spox/extras/Bullshit.rb +1 -1
- data/data/mod_spox/extras/Bytes.rb +1 -2
- data/data/mod_spox/extras/Confess.rb +27 -29
- data/data/mod_spox/extras/DCC.rb +11 -20
- data/data/mod_spox/extras/DevWatch.rb +21 -23
- data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
- data/data/mod_spox/extras/EightBall.rb +1 -1
- data/data/mod_spox/extras/FML.rb +35 -0
- data/data/mod_spox/extras/Headers.rb +31 -50
- data/data/mod_spox/extras/Karma.rb +81 -29
- data/data/mod_spox/extras/Logger.rb +2 -2
- data/data/mod_spox/extras/LolSpeak.rb +1 -2
- data/data/mod_spox/extras/PhpCli.rb +138 -8
- data/data/mod_spox/extras/PhpFuncLookup.rb +20 -23
- data/data/mod_spox/extras/Pinger.rb +1 -1
- data/data/mod_spox/extras/Quotes.rb +8 -10
- data/data/mod_spox/extras/RegexTracker.rb +2 -4
- data/data/mod_spox/extras/Roulette.rb +20 -27
- data/data/mod_spox/extras/RubyCli.rb +93 -0
- data/data/mod_spox/extras/Search.rb +17 -3
- data/data/mod_spox/extras/Seen.rb +150 -0
- data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
- data/data/mod_spox/extras/Talk.rb +2 -4
- data/data/mod_spox/extras/Topten.rb +10 -12
- data/data/mod_spox/extras/TracTicket.rb +3 -5
- data/data/mod_spox/extras/Translate.rb +20 -22
- data/data/mod_spox/extras/Twitter.rb +118 -33
- data/data/mod_spox/extras/UrbanDictionary.rb +8 -17
- data/data/mod_spox/extras/Weather.rb +1 -2
- data/data/mod_spox/plugins/Authenticator.rb +93 -98
- data/data/mod_spox/plugins/Banner.rb +26 -56
- data/data/mod_spox/plugins/Helper.rb +5 -6
- data/data/mod_spox/plugins/Initializer.rb +4 -14
- data/data/mod_spox/plugins/Joiner.rb +1 -1
- data/data/mod_spox/plugins/Nicker.rb +13 -0
- data/data/mod_spox/plugins/Parter.rb +2 -2
- data/data/mod_spox/plugins/Permissions.rb +60 -0
- data/data/mod_spox/plugins/PluginLoader.rb +7 -12
- data/data/mod_spox/plugins/Ponger.rb +51 -0
- data/data/mod_spox/plugins/Quitter.rb +1 -2
- data/data/mod_spox/plugins/Servers.rb +57 -0
- data/data/mod_spox/plugins/Status.rb +3 -2
- data/data/mod_spox/plugins/Triggers.rb +9 -9
- data/lib/mod_spox/Bot.rb +109 -33
- data/lib/mod_spox/BotConfig.rb +2 -2
- data/lib/mod_spox/ConfigurationWizard.rb +12 -12
- data/lib/mod_spox/Database.rb +1 -4
- data/lib/mod_spox/Exceptions.rb +26 -0
- data/lib/mod_spox/Helpers.rb +29 -68
- data/lib/mod_spox/Loader.rb +23 -24
- data/lib/mod_spox/Logger.rb +19 -17
- data/lib/mod_spox/MessageFactory.rb +50 -24
- data/lib/mod_spox/Pipeline.rb +21 -7
- data/lib/mod_spox/Plugin.rb +27 -3
- data/lib/mod_spox/PluginManager.rb +28 -15
- data/lib/mod_spox/PriorityQueue.rb +69 -0
- data/lib/mod_spox/Socket.rb +93 -51
- data/lib/mod_spox/Sockets.rb +76 -63
- data/lib/mod_spox/Timer.rb +21 -141
- data/lib/mod_spox/Version.rb +14 -0
- data/lib/mod_spox/handlers/BadNick.rb +1 -1
- data/lib/mod_spox/handlers/Bounce.rb +5 -5
- data/lib/mod_spox/handlers/Created.rb +13 -5
- data/lib/mod_spox/handlers/Handler.rb +12 -3
- data/lib/mod_spox/handlers/Invite.rb +14 -8
- data/lib/mod_spox/handlers/Join.rb +24 -20
- data/lib/mod_spox/handlers/Kick.rb +22 -13
- data/lib/mod_spox/handlers/Mode.rb +42 -36
- data/lib/mod_spox/handlers/Motd.rb +4 -0
- data/lib/mod_spox/handlers/Names.rb +66 -39
- data/lib/mod_spox/handlers/Nick.rb +20 -14
- data/lib/mod_spox/handlers/Part.rb +25 -8
- data/lib/mod_spox/handlers/Ping.rb +11 -5
- data/lib/mod_spox/handlers/Pong.rb +9 -5
- data/lib/mod_spox/handlers/Privmsg.rb +25 -17
- data/lib/mod_spox/handlers/Quit.rb +13 -8
- data/lib/mod_spox/handlers/Topic.rb +4 -0
- data/lib/mod_spox/handlers/Welcome.rb +16 -24
- data/lib/mod_spox/handlers/Who.rb +64 -48
- data/lib/mod_spox/handlers/Whois.rb +92 -60
- data/lib/mod_spox/messages/incoming/Nick.rb +2 -2
- data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -1
- data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
- data/lib/mod_spox/messages/internal/EstablishConnection.rb +1 -1
- data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
- data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
- data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
- data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
- data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
- data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
- data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
- data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
- data/lib/mod_spox/models/Auth.rb +16 -46
- data/lib/mod_spox/models/AuthMask.rb +13 -0
- data/lib/mod_spox/models/Channel.rb +46 -27
- data/lib/mod_spox/models/Config.rb +10 -19
- data/lib/mod_spox/models/Group.rb +20 -8
- data/lib/mod_spox/models/Models.rb +1 -1
- data/lib/mod_spox/models/Nick.rb +105 -113
- data/lib/mod_spox/models/NickMode.rb +23 -9
- data/lib/mod_spox/models/Server.rb +12 -1
- data/lib/mod_spox/models/Setting.rb +12 -16
- data/lib/mod_spox/models/Signature.rb +28 -8
- data/tests/BotHolder.rb +24 -0
- data/tests/handlers/tc_BadNick.rb +21 -0
- data/tests/handlers/tc_Created.rb +24 -0
- data/tests/handlers/tc_Invite.rb +50 -0
- data/tests/handlers/tc_Join.rb +33 -0
- data/tests/handlers/tc_Kick.rb +32 -0
- data/tests/handlers/tc_Mode.rb +85 -0
- data/tests/handlers/tc_Names.rb +35 -0
- data/tests/handlers/tc_Nick.rb +55 -0
- data/tests/handlers/tc_Part.rb +44 -0
- data/tests/handlers/tc_Ping.rb +40 -0
- data/tests/handlers/tc_Pong.rb +28 -0
- data/tests/handlers/tc_Privmsg.rb +85 -0
- data/tests/handlers/tc_Quit.rb +40 -0
- data/tests/handlers/tc_Who.rb +50 -0
- data/tests/handlers/tc_Whois.rb +61 -0
- data/tests/models/tc_Auth.rb +34 -0
- data/tests/models/tc_Channel.rb +52 -0
- data/tests/models/tc_Config.rb +19 -0
- data/tests/models/tc_Nick.rb +142 -0
- data/tests/models/tc_NickMode.rb +40 -0
- data/tests/models/tc_Setting.rb +21 -0
- data/tests/models/tc_Signature.rb +14 -0
- data/tests/run_tests.rb +4 -0
- metadata +284 -212
- data/README +0 -36
- data/lib/mod_spox/Cache.rb +0 -57
- data/lib/mod_spox/Monitors.rb +0 -84
- data/lib/mod_spox/Pool.rb +0 -164
- data/lib/mod_spox/models/AuthGroup.rb +0 -16
- data/lib/mod_spox/models/ChannelMode.rb +0 -14
- data/lib/mod_spox/models/NickChannel.rb +0 -45
- data/lib/mod_spox/models/NickGroup.rb +0 -16
data/lib/mod_spox/Pipeline.rb
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
['mod_spox/models/Models.rb',
|
|
2
2
|
'mod_spox/Logger',
|
|
3
|
-
'mod_spox/Pool',
|
|
4
3
|
'mod_spox/Exceptions'].each{|f|require f}
|
|
5
4
|
module ModSpox
|
|
6
5
|
|
|
7
6
|
class Pipeline
|
|
8
7
|
|
|
9
8
|
# Create a new Pipeline
|
|
10
|
-
def initialize
|
|
9
|
+
def initialize(pool)
|
|
10
|
+
@pool = pool
|
|
11
11
|
@hooks = Hash.new
|
|
12
12
|
@plugins = Hash.new
|
|
13
13
|
@admin = Models::Group.filter(:name => 'admin').first
|
|
@@ -93,6 +93,9 @@ module ModSpox
|
|
|
93
93
|
def populate_signatures(m=nil)
|
|
94
94
|
@populate_lock.synchronize do
|
|
95
95
|
@signatures = {}
|
|
96
|
+
a = Models::Signature.filter(:enabled => false)
|
|
97
|
+
Logger.warn("Killing #{a.count} signatures")
|
|
98
|
+
a.destroy
|
|
96
99
|
Models::Signature.all.each do |s|
|
|
97
100
|
c = s.signature[0].chr.downcase
|
|
98
101
|
if(c =~ /^[a-z]$/)
|
|
@@ -117,7 +120,7 @@ module ModSpox
|
|
|
117
120
|
begin
|
|
118
121
|
Logger.info("Pipeline is processing a message: #{message}")
|
|
119
122
|
parse(message)
|
|
120
|
-
type = message.class.to_s.gsub(/^(ModSpox::Messages::|#<.+?>::)/, '').gsub(
|
|
123
|
+
type = message.class.to_s.gsub(/^(ModSpox::Messages::|#<.+?>::)/, '').gsub('::', '_').to_sym
|
|
121
124
|
mod = type.to_s.gsub(/_.+$/, '').to_sym
|
|
122
125
|
Logger.info("Pipeline determines that #{message} is of type: #{type}")
|
|
123
126
|
[type, mod, :all].each do |type|
|
|
@@ -125,7 +128,18 @@ module ModSpox
|
|
|
125
128
|
@hooks[type].each_value do |objects|
|
|
126
129
|
begin
|
|
127
130
|
objects.each do |v|
|
|
128
|
-
|
|
131
|
+
@pool.process do
|
|
132
|
+
begin
|
|
133
|
+
v[:object].send(v[:method].to_s, message)
|
|
134
|
+
rescue Object => boom
|
|
135
|
+
if(boom.class.to_s == 'SQLite3::BusyException')
|
|
136
|
+
Database.reset_connections
|
|
137
|
+
retry
|
|
138
|
+
else
|
|
139
|
+
raise boom
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
129
143
|
end
|
|
130
144
|
rescue Object => boom
|
|
131
145
|
Logger.warn("Plugin threw exception while attempting to process message: #{boom}\n#{boom.backtrace.join("\n")}")
|
|
@@ -145,7 +159,7 @@ module ModSpox
|
|
|
145
159
|
def parse(message)
|
|
146
160
|
return unless message.kind_of?(Messages::Incoming::Privmsg) || message.kind_of?(Messages::Incoming::Notice)
|
|
147
161
|
trigger = nil
|
|
148
|
-
@triggers.each{|t| trigger = t if message.message
|
|
162
|
+
@triggers.each{|t| trigger = t if message.message[0..t.size-1] == t}
|
|
149
163
|
if(!trigger.nil? || message.addressed?)
|
|
150
164
|
return if !trigger.nil? && message.message.length == trigger.length
|
|
151
165
|
Logger.info("Message has matched against a known trigger")
|
|
@@ -164,7 +178,7 @@ module ModSpox
|
|
|
164
178
|
esc_trig = trigger.nil? ? '' : Regexp.escape(trigger)
|
|
165
179
|
res = message.message.scan(/^#{esc_trig}#{sig.signature}$/)
|
|
166
180
|
if(res.size > 0)
|
|
167
|
-
next unless message.source.
|
|
181
|
+
next unless message.source.in_group?(sig.group) || message.source.in_group?(@admin) || sig.group.nil?
|
|
168
182
|
next if sig.requirement == 'private' && message.is_public?
|
|
169
183
|
next if sig.requirement == 'public' && message.is_private?
|
|
170
184
|
params = Hash.new
|
|
@@ -174,7 +188,7 @@ module ModSpox
|
|
|
174
188
|
end
|
|
175
189
|
if(@plugins.has_key?(sig.plugin.to_sym))
|
|
176
190
|
begin
|
|
177
|
-
|
|
191
|
+
@pool.process{ @plugins[sig.plugin.to_sym].send(sig.values[:method], message, params) }
|
|
178
192
|
rescue Object => boom
|
|
179
193
|
Logger.warn("Plugin threw exception while attempting to process message: #{boom}\n#{boom.backtrace.join("\n")}")
|
|
180
194
|
end
|
data/lib/mod_spox/Plugin.rb
CHANGED
|
@@ -58,15 +58,39 @@ module ModSpox
|
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
61
|
+
# Adds a new signature for the given plugin
|
|
62
|
+
# Required args: :sig and :method
|
|
63
|
+
# Optional args: :group, :req, :desc, and :params
|
|
61
64
|
def add_sig(args)
|
|
62
65
|
raise ModSpox::Exceptions::InvalidType.new('You must provide a hash for creating new signatures') unless args.is_a?(Hash)
|
|
63
|
-
|
|
66
|
+
args[:params] = nil unless args[:params]
|
|
67
|
+
sig = Signature.find_or_create(:signature => args[:sig], :plugin => name, :method => args[:method].to_s,
|
|
68
|
+
:params => args[:params], :group_id => args[:group].nil? ? nil : args[:group].pk)
|
|
64
69
|
sig.description = args[:desc] if args.has_key?(:desc)
|
|
65
|
-
sig.group_id = args[:group].pk if args.has_key?(:group)
|
|
66
70
|
sig.requirement = args[:req] if args.has_key?(:req)
|
|
67
|
-
sig.params = args[:params] if args.has_key?(:params)
|
|
68
71
|
sig.save
|
|
69
72
|
end
|
|
73
|
+
|
|
74
|
+
# to:: Where message is going
|
|
75
|
+
# message:: message
|
|
76
|
+
# Send an information message to target
|
|
77
|
+
def information(to, message)
|
|
78
|
+
reply to, "\2#{name} (info):\2 #{message}"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# to:: Where message is going
|
|
82
|
+
# message:: message
|
|
83
|
+
# Send an warning message to target
|
|
84
|
+
def warning(to, message)
|
|
85
|
+
reply to, "\2#{name} (warn):\2 #{message}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# to:: Where message is going
|
|
89
|
+
# message:: message
|
|
90
|
+
# Send an error message to target
|
|
91
|
+
def error(to, message)
|
|
92
|
+
reply to, "\2#{name} (error):\2 #{message}"
|
|
93
|
+
end
|
|
70
94
|
|
|
71
95
|
end
|
|
72
96
|
end
|
|
@@ -30,18 +30,24 @@ module ModSpox
|
|
|
30
30
|
# message:: Messages::Internal::PluginReload
|
|
31
31
|
# Destroys and reinitializes plugins
|
|
32
32
|
def reload_plugins(message=nil)
|
|
33
|
-
@
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
33
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
|
34
|
+
begin
|
|
35
|
+
@plugin_lock.synchronize do
|
|
36
|
+
if(!message.nil? && (message.fresh && message.stale))
|
|
37
|
+
do_unload(message.stale)
|
|
38
|
+
FileUtils.remove_file(message.stale)
|
|
39
|
+
FileUtils.copy(message.fresh, BotConfig[:userpluginpath])
|
|
40
|
+
do_load(message.stale)
|
|
41
|
+
Logger.info("Completed reload of plugin: #{message.stale}")
|
|
42
|
+
else
|
|
43
|
+
unload_plugins
|
|
44
|
+
load_plugins
|
|
45
|
+
end
|
|
43
46
|
end
|
|
44
|
-
|
|
47
|
+
rescue Object => boom
|
|
48
|
+
Logger.error("PluginManager caught error on plugin reload: #{boom}")
|
|
49
|
+
ensure
|
|
50
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
|
45
51
|
end
|
|
46
52
|
end
|
|
47
53
|
|
|
@@ -53,6 +59,7 @@ module ModSpox
|
|
|
53
59
|
# message:: Messages::Internal::PluginLoadRequest
|
|
54
60
|
# Loads a plugin
|
|
55
61
|
def load_plugin(message)
|
|
62
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
|
56
63
|
begin
|
|
57
64
|
path = !message.name ? "#{BotConfig[:userpluginpath]}/#{message.path.gsub(/^.+\//, '')}" : "#{BotConfig[:userpluginpath]}/#{message.name}"
|
|
58
65
|
begin
|
|
@@ -66,13 +73,16 @@ module ModSpox
|
|
|
66
73
|
rescue Object => boom
|
|
67
74
|
Logger.warn("Failed to load plugin: #{message.path} Reason: #{boom}")
|
|
68
75
|
@pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, false)
|
|
76
|
+
ensure
|
|
77
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
78
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
|
69
79
|
end
|
|
70
|
-
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
71
80
|
end
|
|
72
81
|
|
|
73
82
|
# message:: Messages::Internal::PluginUnloadRequest
|
|
74
83
|
# Unloads a plugin
|
|
75
84
|
def unload_plugin(message)
|
|
85
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
|
76
86
|
begin
|
|
77
87
|
do_unload(message.path)
|
|
78
88
|
unless(File.symlink?(message.path))
|
|
@@ -86,8 +96,10 @@ module ModSpox
|
|
|
86
96
|
rescue Object => boom
|
|
87
97
|
Logger.warn("Failed to unload plugin: #{message.path} Reason: #{boom}")
|
|
88
98
|
@pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, false)
|
|
99
|
+
ensure
|
|
100
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
|
101
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
89
102
|
end
|
|
90
|
-
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
91
103
|
end
|
|
92
104
|
|
|
93
105
|
# message:: Messages::Internal::PluginModuleRequest
|
|
@@ -116,7 +128,7 @@ module ModSpox
|
|
|
116
128
|
# Loads and initializes plugins
|
|
117
129
|
def load_plugins
|
|
118
130
|
@pipeline << Messages::Internal::TimerClear.new
|
|
119
|
-
Models::Signature.
|
|
131
|
+
Models::Signature.set(:enabled => false)
|
|
120
132
|
[BotConfig[:pluginpath], BotConfig[:userpluginpath]].each do |path|
|
|
121
133
|
Dir.new(path).each do |file|
|
|
122
134
|
if(file =~ /^[^\.].+\.rb$/)
|
|
@@ -129,11 +141,11 @@ module ModSpox
|
|
|
129
141
|
end
|
|
130
142
|
end
|
|
131
143
|
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
144
|
+
@pipeline << Messages::Internal::PluginsReady.new
|
|
132
145
|
end
|
|
133
146
|
|
|
134
147
|
# Destroys plugins
|
|
135
148
|
def unload_plugins
|
|
136
|
-
Models::Signature.destroy_all
|
|
137
149
|
@plugins.each_pair do |sym, holder|
|
|
138
150
|
begin
|
|
139
151
|
holder.plugin.destroy unless holder.plugin.nil?
|
|
@@ -162,6 +174,7 @@ module ModSpox
|
|
|
162
174
|
@plugins[plugin.to_sym] = PluginHolder.new(klass.new({:pipeline => @pipeline, :plugin_module => @plugins_module}))
|
|
163
175
|
end
|
|
164
176
|
Logger.info("Properly initialized new plugin: #{plugin}")
|
|
177
|
+
Database.reset_connections
|
|
165
178
|
end
|
|
166
179
|
Logger.info("All plugins found at: #{path} have been loaded")
|
|
167
180
|
rescue Object => boom
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module ModSpox
|
|
2
|
+
# This class provides some simple logic for message output. It
|
|
3
|
+
# is basically a priority based queue with some round robin
|
|
4
|
+
# thrown in, just to keep things interesting. This queue provides
|
|
5
|
+
# protection on message output from extreme lag to one target when
|
|
6
|
+
# another target is expecting large quantities out output
|
|
7
|
+
# NOTE: Design help from the great Ryan "pizza_" Flynn
|
|
8
|
+
class PriorityQueue
|
|
9
|
+
|
|
10
|
+
# Create a priority queue
|
|
11
|
+
def initialize
|
|
12
|
+
@target_queues = {}
|
|
13
|
+
@queues = {:PRIORITY => Queue.new, :NEW => Queue.new, :NORMAL => Queue.new, :WHOCARES => Queue.new}
|
|
14
|
+
@lock = Mutex.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# target:: message target (targets starting with * will be labelled WHOCARES
|
|
18
|
+
# message:: message to send
|
|
19
|
+
# This prioritizes output to help reduce lag when lots of output
|
|
20
|
+
# is being sent to another target. This will automatically decide
|
|
21
|
+
# how to queue the message based on the target
|
|
22
|
+
def priority_queue(target, message)
|
|
23
|
+
@lock.synchronize do
|
|
24
|
+
target.downcase!
|
|
25
|
+
@target_queues[target] = Queue.new unless @target_queues[target]
|
|
26
|
+
if(target[0].chr == '*')
|
|
27
|
+
@target_queues[target] << message
|
|
28
|
+
@queues[:WHOCARES] << @target_queues[target]
|
|
29
|
+
else
|
|
30
|
+
@target_queues[target] << message
|
|
31
|
+
if(@target_queues[target].size < 2)
|
|
32
|
+
@queues[:NEW] << @target_queues[target]
|
|
33
|
+
else
|
|
34
|
+
@queues[:NORMAL] << @target_queues[target]
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# message:: message to send
|
|
41
|
+
# This will add messages to the PRIORITY queue which gets
|
|
42
|
+
# sent before all other messages.
|
|
43
|
+
def direct_queue(message)
|
|
44
|
+
@lock.synchronize do
|
|
45
|
+
@target_queues[:general] = Queue.new unless @target_queues[:general]
|
|
46
|
+
@target_queues[:general] << message
|
|
47
|
+
@queues[:PRIORITY] << @target_queues[:general]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Returns the next message to send. This method decides what
|
|
52
|
+
# message to send based on the priority of the message. It
|
|
53
|
+
# will throw an Exceptions::EmptyQueue when there are no messages
|
|
54
|
+
# left.
|
|
55
|
+
def pop
|
|
56
|
+
m = nil
|
|
57
|
+
@lock.synchronize do
|
|
58
|
+
[:PRIORITY, :NEW, :NORMAL, :WHOCARES].each do |k|
|
|
59
|
+
unless(@queues[k].empty?)
|
|
60
|
+
m = @queues[k].pop.pop
|
|
61
|
+
break
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
raise Exceptions::EmptyQueue.new if m.nil?
|
|
66
|
+
return m
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/mod_spox/Socket.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
['iconv',
|
|
2
2
|
'mod_spox/Logger',
|
|
3
|
-
'mod_spox/Pool',
|
|
4
3
|
'mod_spox/Exceptions',
|
|
5
4
|
'mod_spox/messages/Messages',
|
|
6
5
|
'mod_spox/models/Models',
|
|
7
|
-
'mod_spox/Pipeline'
|
|
6
|
+
'mod_spox/Pipeline',
|
|
7
|
+
'mod_spox/PriorityQueue'].each{|f|require f}
|
|
8
8
|
|
|
9
9
|
module ModSpox
|
|
10
10
|
|
|
@@ -18,6 +18,7 @@ module ModSpox
|
|
|
18
18
|
attr_reader :server
|
|
19
19
|
attr_reader :port
|
|
20
20
|
attr_reader :socket
|
|
21
|
+
attr_reader :connected_at
|
|
21
22
|
|
|
22
23
|
# factory:: MessageFactory to parse messages
|
|
23
24
|
# server:: Server to connect to
|
|
@@ -26,12 +27,13 @@ module ModSpox
|
|
|
26
27
|
# burst_in:: Number of seconds allowed to burst
|
|
27
28
|
# burst:: Number of lines allowed to be sent within the burst_in time limit
|
|
28
29
|
# Create a new Socket
|
|
29
|
-
def initialize(bot, server, port, delay=2, burst_in=2, burst=4)
|
|
30
|
+
def initialize(bot, server=nil, port=nil, delay=2, burst_in=2, burst=4)
|
|
31
|
+
@pool = bot.pool
|
|
30
32
|
@factory = bot.factory
|
|
31
33
|
@pipeline = bot.pipeline
|
|
32
34
|
@dcc = bot.dcc_sockets
|
|
33
35
|
@server = server
|
|
34
|
-
@port = port
|
|
36
|
+
@port = port
|
|
35
37
|
@sent = 0
|
|
36
38
|
@received = 0
|
|
37
39
|
@delay = delay.to_f > 0 ? delay.to_f : 2.0
|
|
@@ -41,19 +43,35 @@ module ModSpox
|
|
|
41
43
|
@time_check = nil
|
|
42
44
|
@check_burst = 0
|
|
43
45
|
@pause = false
|
|
44
|
-
@sendq =
|
|
46
|
+
@sendq = PriorityQueue.new
|
|
45
47
|
@lock = Mutex.new
|
|
46
48
|
@ic = Iconv.new('UTF-8//IGNORE', 'UTF-8')
|
|
49
|
+
@connected_at = nil
|
|
50
|
+
@empty_lines = 0
|
|
51
|
+
@max_empty = 5
|
|
52
|
+
@servers = Array.new
|
|
53
|
+
@connect_locker = Mutex.new
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
# Connects to the IRC server
|
|
50
57
|
def connect
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
return unless @connect_locker.try_lock
|
|
59
|
+
begin
|
|
60
|
+
populate_servers if @servers.empty?
|
|
61
|
+
s = @servers.pop
|
|
62
|
+
@server = s.host
|
|
63
|
+
@port = s.port.to_i
|
|
64
|
+
Logger.info("Establishing connection to #{@server}:#{@port}")
|
|
65
|
+
@socket = TCPSocket.new(@server, @port)
|
|
66
|
+
@socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true)
|
|
67
|
+
@empty_lines = 0
|
|
68
|
+
s.connected = true
|
|
69
|
+
s.save
|
|
70
|
+
@connected_at = Time.now
|
|
71
|
+
@pipeline << Messages::Internal::Connected.new(@server, @port)
|
|
72
|
+
ensure
|
|
73
|
+
@connect_locker.unlock
|
|
74
|
+
end
|
|
57
75
|
end
|
|
58
76
|
|
|
59
77
|
# new_delay:: Seconds to delay between bursts
|
|
@@ -87,65 +105,81 @@ module ModSpox
|
|
|
87
105
|
# Sends a string to the IRC server
|
|
88
106
|
def write(message)
|
|
89
107
|
return if message.nil?
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
begin
|
|
109
|
+
@socket.puts(message + "\n")
|
|
110
|
+
@socket.flush
|
|
111
|
+
Logger.info("<< #{message}")
|
|
112
|
+
@last_send = Time.new
|
|
113
|
+
@sent += 1
|
|
114
|
+
@check_burst += 1
|
|
115
|
+
@time_check = Time.now.to_i if @time_check.nil?
|
|
116
|
+
rescue Object => boom
|
|
117
|
+
Logger.warn("Failed to write message to server. #{boom}")
|
|
118
|
+
@pipeline << Messages::Internal::Disconnected.new
|
|
119
|
+
raise Exceptions::Disconnected.new
|
|
120
|
+
end
|
|
96
121
|
end
|
|
97
|
-
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
122
|
+
|
|
123
|
+
# string:: string to be processed
|
|
124
|
+
# Process a string
|
|
125
|
+
def process(string)
|
|
126
|
+
string.strip!
|
|
127
|
+
Logger.info(">> #{string}")
|
|
128
|
+
if(string[0,5] == 'ERROR')
|
|
102
129
|
@pipeline << Messages::Internal::Disconnected.new
|
|
103
|
-
|
|
104
|
-
server = Models::Server.find_or_create(:host => @server, :port => @port)
|
|
105
|
-
server.connected = false
|
|
106
|
-
server.save
|
|
107
|
-
elsif(tainted_message.length > 0)
|
|
108
|
-
message = @ic.iconv(tainted_message + ' ')[0..-2]
|
|
109
|
-
message.strip!
|
|
110
|
-
Logger.info(">> #{message}")
|
|
111
|
-
@received += 1
|
|
112
|
-
begin
|
|
113
|
-
message.strip!
|
|
114
|
-
rescue Object => boom
|
|
115
|
-
#do nothing#
|
|
116
|
-
ensure
|
|
117
|
-
@factory << message
|
|
118
|
-
end
|
|
130
|
+
raise Exceptions::Disconnected.new
|
|
119
131
|
end
|
|
132
|
+
@received += 1
|
|
133
|
+
@factory << string
|
|
120
134
|
end
|
|
121
135
|
|
|
122
136
|
# message:: String to be sent to server
|
|
123
137
|
# Queues a message up to be sent to the IRC server
|
|
124
138
|
def <<(message)
|
|
125
|
-
@sendq
|
|
126
|
-
|
|
139
|
+
@sendq.direct_queue(message)
|
|
140
|
+
@pool.process{ processor }
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# target:: Target for outgoing message
|
|
144
|
+
# message:: Message to send
|
|
145
|
+
# This queues a message to be sent out of a prioritized
|
|
146
|
+
# queue. This allows for even message distribution rather
|
|
147
|
+
# than only on target at a time being flooded.
|
|
148
|
+
def prioritize_message(target, message)
|
|
149
|
+
@sendq.priority_queue(target, message)
|
|
150
|
+
@pool.process{ processor }
|
|
127
151
|
end
|
|
128
152
|
|
|
129
153
|
# Starts the thread for sending messages to the server
|
|
130
154
|
def processor
|
|
131
|
-
@lock.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@check_burst
|
|
155
|
+
return unless @lock.try_lock
|
|
156
|
+
did_write = false
|
|
157
|
+
begin
|
|
158
|
+
loop do
|
|
159
|
+
write(@sendq.pop)
|
|
160
|
+
did_write = true
|
|
161
|
+
if((Time.now.to_i - @time_check) > @burst_in)
|
|
162
|
+
@time_check = nil
|
|
163
|
+
@check_burst = 0
|
|
164
|
+
elsif((Time.now.to_i - @time_check) <= @burst_in && @check_burst >= @burst)
|
|
165
|
+
Logger.warn("Burst limit hit. Output paused for: #{@delay} seconds")
|
|
166
|
+
sleep(@delay)
|
|
167
|
+
@time_check = nil
|
|
168
|
+
@check_burst = 0
|
|
169
|
+
end
|
|
141
170
|
end
|
|
171
|
+
rescue Exceptions::EmptyQueue => boom
|
|
172
|
+
Logger.info('Socket reached an empty queue.')
|
|
173
|
+
ensure
|
|
174
|
+
@lock.unlock
|
|
175
|
+
@pool.process{ processor } if did_write
|
|
142
176
|
end
|
|
143
177
|
end
|
|
144
178
|
|
|
145
179
|
# restart:: Reconnect after closing connection
|
|
146
180
|
# Closes connection to IRC server
|
|
147
181
|
def shutdown(restart=false)
|
|
148
|
-
@socket.close unless @socket.closed?
|
|
182
|
+
@socket.close unless @socket.nil? || @socket.closed?
|
|
149
183
|
@kill = true
|
|
150
184
|
server = Models::Server.find_or_create(:host => @server, :port => @port)
|
|
151
185
|
server.connected = false
|
|
@@ -154,6 +188,14 @@ module ModSpox
|
|
|
154
188
|
connect if restart
|
|
155
189
|
end
|
|
156
190
|
|
|
191
|
+
private
|
|
192
|
+
|
|
193
|
+
def populate_servers
|
|
194
|
+
Models::Server.reverse_order(:priority).each{|s|
|
|
195
|
+
@servers << s
|
|
196
|
+
}
|
|
197
|
+
end
|
|
198
|
+
|
|
157
199
|
end
|
|
158
200
|
|
|
159
201
|
end
|