mod_spox 0.0.4 → 0.0.5
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 +16 -0
- data/INSTALL +4 -1
- data/bin/mod_spox +3 -1
- data/data/mod_spox/extras/AOLSpeak.rb +2 -2
- data/data/mod_spox/extras/AutoKick.rb +3 -8
- data/data/mod_spox/extras/AutoMode.rb +135 -0
- data/data/mod_spox/extras/EightBall.rb +1 -0
- data/data/mod_spox/extras/Headers.rb +4 -3
- data/data/mod_spox/extras/PhpFuncLookup.rb +14 -11
- data/data/mod_spox/extras/Roulette.rb +3 -3
- data/data/mod_spox/extras/Search.rb +3 -2
- data/data/mod_spox/extras/Talk.rb +1 -9
- data/data/mod_spox/extras/Translate.rb +3 -3
- data/data/mod_spox/extras/UrbanDictionary.rb +5 -3
- data/data/mod_spox/extras/Weather.rb +5 -4
- data/data/mod_spox/plugins/Authenticator.rb +2 -2
- data/data/mod_spox/plugins/Banner.rb +207 -2
- data/data/mod_spox/plugins/Helper.rb +1 -1
- data/data/mod_spox/plugins/PluginLoader.rb +22 -6
- data/data/mod_spox/plugins/Triggers.rb +6 -4
- data/lib/mod_spox/Action.rb +2 -0
- data/lib/mod_spox/BaseConfig.rb +2 -0
- data/lib/mod_spox/Bot.rb +32 -6
- data/lib/mod_spox/BotConfig.rb +3 -0
- data/lib/mod_spox/Cache.rb +57 -0
- data/lib/mod_spox/ConfigurationWizard.rb +6 -2
- data/lib/mod_spox/Helpers.rb +36 -18
- data/lib/mod_spox/Loader.rb +5 -54
- data/lib/mod_spox/Logger.rb +49 -3
- data/lib/mod_spox/MessageFactory.rb +5 -0
- data/lib/mod_spox/Monitors.rb +14 -12
- data/lib/mod_spox/Pipeline.rb +38 -6
- data/lib/mod_spox/Plugin.rb +3 -0
- data/lib/mod_spox/PluginHolder.rb +22 -0
- data/lib/mod_spox/PluginManager.rb +123 -25
- data/lib/mod_spox/Pool.rb +52 -23
- data/lib/mod_spox/Socket.rb +21 -10
- data/lib/mod_spox/Timer.rb +32 -6
- data/lib/mod_spox/handlers/BadNick.rb +2 -0
- data/lib/mod_spox/handlers/Bounce.rb +3 -0
- data/lib/mod_spox/handlers/Created.rb +2 -0
- data/lib/mod_spox/handlers/Handler.rb +5 -0
- data/lib/mod_spox/handlers/Invite.rb +2 -0
- data/lib/mod_spox/handlers/Join.rb +21 -5
- data/lib/mod_spox/handlers/Kick.rb +2 -0
- data/lib/mod_spox/handlers/LuserChannels.rb +2 -0
- data/lib/mod_spox/handlers/LuserClient.rb +1 -0
- data/lib/mod_spox/handlers/LuserMe.rb +1 -0
- data/lib/mod_spox/handlers/LuserOp.rb +2 -0
- data/lib/mod_spox/handlers/LuserUnknown.rb +2 -0
- data/lib/mod_spox/handlers/Mode.rb +2 -0
- data/lib/mod_spox/handlers/Motd.rb +5 -2
- data/lib/mod_spox/handlers/MyInfo.rb +2 -0
- data/lib/mod_spox/handlers/Names.rb +5 -1
- data/lib/mod_spox/handlers/Nick.rb +2 -0
- data/lib/mod_spox/handlers/NickInUse.rb +2 -0
- data/lib/mod_spox/handlers/Notice.rb +16 -4
- data/lib/mod_spox/handlers/Part.rb +2 -0
- data/lib/mod_spox/handlers/Ping.rb +2 -0
- data/lib/mod_spox/handlers/Pong.rb +2 -0
- data/lib/mod_spox/handlers/Privmsg.rb +16 -4
- data/lib/mod_spox/handlers/Quit.rb +2 -0
- data/lib/mod_spox/handlers/Topic.rb +2 -0
- data/lib/mod_spox/handlers/Welcome.rb +3 -0
- data/lib/mod_spox/handlers/Who.rb +3 -1
- data/lib/mod_spox/handlers/Whois.rb +8 -0
- data/lib/mod_spox/handlers/YourHost.rb +2 -0
- data/lib/mod_spox/messages/Messages.rb +6 -0
- data/lib/mod_spox/messages/incoming/BadNick.rb +1 -0
- data/lib/mod_spox/messages/incoming/Bounce.rb +1 -0
- data/lib/mod_spox/messages/incoming/Created.rb +1 -0
- data/lib/mod_spox/messages/incoming/Invite.rb +1 -0
- data/lib/mod_spox/messages/incoming/Join.rb +1 -0
- data/lib/mod_spox/messages/incoming/Kick.rb +1 -0
- data/lib/mod_spox/messages/incoming/LuserChannels.rb +1 -0
- data/lib/mod_spox/messages/incoming/LuserClient.rb +1 -0
- data/lib/mod_spox/messages/incoming/LuserMe.rb +1 -0
- data/lib/mod_spox/messages/incoming/LuserOp.rb +1 -0
- data/lib/mod_spox/messages/incoming/LuserUnknown.rb +1 -0
- data/lib/mod_spox/messages/incoming/Mode.rb +1 -0
- data/lib/mod_spox/messages/incoming/Motd.rb +1 -0
- data/lib/mod_spox/messages/incoming/MyInfo.rb +1 -0
- data/lib/mod_spox/messages/incoming/Names.rb +1 -0
- data/lib/mod_spox/messages/incoming/Nick.rb +1 -0
- data/lib/mod_spox/messages/incoming/NickInUse.rb +1 -0
- data/lib/mod_spox/messages/incoming/Notice.rb +1 -0
- data/lib/mod_spox/messages/incoming/Part.rb +1 -0
- data/lib/mod_spox/messages/incoming/Ping.rb +1 -0
- data/lib/mod_spox/messages/incoming/Pong.rb +1 -0
- data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -0
- data/lib/mod_spox/messages/incoming/Quit.rb +1 -0
- data/lib/mod_spox/messages/incoming/Topic.rb +1 -0
- data/lib/mod_spox/messages/incoming/TopicInfo.rb +1 -0
- data/lib/mod_spox/messages/incoming/Welcome.rb +1 -0
- data/lib/mod_spox/messages/incoming/Who.rb +1 -0
- data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
- data/lib/mod_spox/messages/incoming/YourHost.rb +1 -0
- data/lib/mod_spox/messages/internal/NickRequest.rb +1 -0
- data/lib/mod_spox/messages/internal/NickResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginLoadRequest.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginLoadResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginModuleRequest.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginModuleResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginReload.rb +10 -0
- data/lib/mod_spox/messages/internal/PluginRequest.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginUnloadRequest.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginUnloadResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/StatusResponse.rb +1 -0
- data/lib/mod_spox/messages/internal/TimerAdd.rb +1 -0
- data/lib/mod_spox/messages/internal/TimerClear.rb +8 -0
- data/lib/mod_spox/messages/internal/TimerResponse.rb +1 -0
- data/lib/mod_spox/messages/outgoing/Away.rb +1 -0
- data/lib/mod_spox/messages/outgoing/Notice.rb +1 -0
- data/lib/mod_spox/messages/outgoing/Ping.rb +1 -0
- data/lib/mod_spox/messages/outgoing/Quit.rb +1 -0
- data/lib/mod_spox/messages/outgoing/Raw.rb +16 -0
- data/lib/mod_spox/models/Models.rb +4 -0
- data/lib/mod_spox/models/Nick.rb +9 -0
- data/lib/mod_spox/models/Setting.rb +3 -5
- data/lib/mod_spox/models/Signature.rb +2 -3
- metadata +8 -2
data/lib/mod_spox/Logger.rb
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
require 'mod_spox/Pool'
|
|
2
|
+
|
|
1
3
|
module ModSpox
|
|
2
4
|
|
|
3
5
|
class Logger
|
|
6
|
+
|
|
7
|
+
def self.do_initialization
|
|
8
|
+
Logger.fd(nil) unless Logger.class_variable_defined?(:@@fd)
|
|
9
|
+
Logger.severity unless Logger.class_variable_defined?(:@@severity)
|
|
10
|
+
@@lock = Mutex.new unless Logger.class_variable_defined?(:@@lock)
|
|
11
|
+
@@lock.synchronize do
|
|
12
|
+
@@writer = LogWriter.new(@@fd) unless Logger.class_variable_defined?(:@@writer)
|
|
13
|
+
@@initialized = true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
4
16
|
|
|
5
17
|
# severity:: minimum severity for visible logging
|
|
6
18
|
# Sets the maximum level of visible logs
|
|
@@ -21,9 +33,43 @@ module ModSpox
|
|
|
21
33
|
# severity level of a message, the better chance it has of
|
|
22
34
|
# being outputted
|
|
23
35
|
def self.log(message, severity=1)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
36
|
+
do_initialization unless Logger.class_variable_defined?(:@@initialized)
|
|
37
|
+
@@writer.log(message) unless @@severity < severity
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.kill
|
|
41
|
+
@@writer.kill
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class LogWriter
|
|
47
|
+
|
|
48
|
+
attr_reader :fd
|
|
49
|
+
|
|
50
|
+
def initialize(fd)
|
|
51
|
+
@fd = fd
|
|
52
|
+
@kill = false
|
|
53
|
+
@queue = Queue.new
|
|
54
|
+
@thread = Thread.new do
|
|
55
|
+
until(@kill)
|
|
56
|
+
processor
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def kill
|
|
62
|
+
@kill = true
|
|
63
|
+
@queue << "Logger has been told to shut down"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def log(message)
|
|
67
|
+
@queue << message
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def processor
|
|
71
|
+
message = @queue.pop
|
|
72
|
+
@fd.puts("LOGGER [#{Time.now}]: #{message}")
|
|
27
73
|
end
|
|
28
74
|
|
|
29
75
|
end
|
data/lib/mod_spox/Monitors.rb
CHANGED
|
@@ -12,7 +12,13 @@ module ModSpox
|
|
|
12
12
|
|
|
13
13
|
# Force the monitor to wake everyone up
|
|
14
14
|
def wakeup
|
|
15
|
-
@threads.each
|
|
15
|
+
@threads.each do |t|
|
|
16
|
+
begin
|
|
17
|
+
t.wakeup
|
|
18
|
+
rescue Object => boom
|
|
19
|
+
# thread was dead #
|
|
20
|
+
end
|
|
21
|
+
end
|
|
16
22
|
@threads.clear
|
|
17
23
|
end
|
|
18
24
|
|
|
@@ -40,24 +46,20 @@ module ModSpox
|
|
|
40
46
|
# Stop waiting
|
|
41
47
|
def wakeup
|
|
42
48
|
return if @threads.empty?
|
|
43
|
-
@threads.each do |
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
Logger.log("Calling thread is: #{Thread.current}", 5)
|
|
49
|
-
else
|
|
50
|
-
Logger.log("Thread to wakeup has been killed: #{thread}")
|
|
49
|
+
@threads.each do |t|
|
|
50
|
+
begin
|
|
51
|
+
t.wakeup
|
|
52
|
+
rescue Object => boom
|
|
53
|
+
# thread was dead #
|
|
51
54
|
end
|
|
52
|
-
@threads.delete(thread)
|
|
53
55
|
end
|
|
56
|
+
@threads.clear
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
# Start waiting
|
|
57
60
|
def wait
|
|
58
61
|
@threads << Thread.current
|
|
59
|
-
|
|
60
|
-
Thread.stop
|
|
62
|
+
sleep
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
# Returns if a thread is currently waiting in this monitor
|
data/lib/mod_spox/Pipeline.rb
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
['mod_spox/models/Models.rb',
|
|
2
|
+
'mod_spox/Logger',
|
|
3
|
+
'mod_spox/Pool',
|
|
4
|
+
'mod_spox/Exceptions'].each{|f|require f}
|
|
1
5
|
module ModSpox
|
|
2
6
|
|
|
3
7
|
class Pipeline < Pool
|
|
@@ -10,6 +14,7 @@ module ModSpox
|
|
|
10
14
|
@hooks = Hash.new
|
|
11
15
|
@plugins = Hash.new
|
|
12
16
|
@admin = Models::Group.filter(:name => 'admin').first
|
|
17
|
+
@populate_lock = Mutex.new
|
|
13
18
|
populate_triggers
|
|
14
19
|
populate_signatures
|
|
15
20
|
hook(self, :populate_triggers, :Internal_TriggersUpdate)
|
|
@@ -36,7 +41,7 @@ module ModSpox
|
|
|
36
41
|
# Unhooks a plugin from the pipeline (This does not unhook
|
|
37
42
|
# it from the standard hooks)
|
|
38
43
|
def unhook_plugin(plugin)
|
|
39
|
-
Logger.log("Plugin #{plugin.name} unhooking from
|
|
44
|
+
Logger.log("Plugin #{plugin.name} unhooking from pipeline", 10)
|
|
40
45
|
@plugins.delete(plugin.name.to_sym)
|
|
41
46
|
@hooks.each_pair do |type, things|
|
|
42
47
|
things.delete(plugin.name.to_sym) if things.has_key?(plugin.name.to_sym)
|
|
@@ -82,14 +87,32 @@ module ModSpox
|
|
|
82
87
|
|
|
83
88
|
# Repopulate the active trigger list
|
|
84
89
|
def populate_triggers(m=nil)
|
|
85
|
-
@
|
|
86
|
-
|
|
90
|
+
@populate_lock.synchronize do
|
|
91
|
+
@triggers = []
|
|
92
|
+
Models::Trigger.filter(:active => true).each{|t|@triggers << t.trigger}
|
|
93
|
+
end
|
|
87
94
|
end
|
|
88
95
|
|
|
89
96
|
# Repopulate the active signatures list
|
|
90
97
|
def populate_signatures(m=nil)
|
|
91
|
-
@
|
|
92
|
-
|
|
98
|
+
@populate_lock.synchronize do
|
|
99
|
+
@signatures = {}
|
|
100
|
+
Models::Signature.all.each do |s|
|
|
101
|
+
Logger.log("Signature being processed: #{s.signature}")
|
|
102
|
+
c = s.signature[0].chr.downcase
|
|
103
|
+
if(c =~ /^[a-z]$/)
|
|
104
|
+
type = c.to_sym
|
|
105
|
+
elsif(c =~ /^[0-9]$/)
|
|
106
|
+
type = :digit
|
|
107
|
+
else
|
|
108
|
+
type = :other
|
|
109
|
+
end
|
|
110
|
+
@signatures[type] = [] unless @signatures[type]
|
|
111
|
+
unless @signatures.include?(s)
|
|
112
|
+
@signatures[type] << s
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
93
116
|
end
|
|
94
117
|
|
|
95
118
|
private
|
|
@@ -133,7 +156,16 @@ module ModSpox
|
|
|
133
156
|
@triggers.each{|t| trigger = t if message.message =~ /^#{t}/}
|
|
134
157
|
if(!trigger.nil? || message.addressed?)
|
|
135
158
|
Logger.log("Message has matched against a known trigger", 15)
|
|
136
|
-
|
|
159
|
+
c = message.addressed? ? message.message[0].chr.downcase : message.message[1].chr.downcase
|
|
160
|
+
if(c =~ /^[a-z]$/)
|
|
161
|
+
type = c.to_sym
|
|
162
|
+
elsif(c =~ /^[0-9]$/)
|
|
163
|
+
type = :digit
|
|
164
|
+
else
|
|
165
|
+
type = :other
|
|
166
|
+
end
|
|
167
|
+
return unless @signatures[type]
|
|
168
|
+
@signatures[type].each do |sig|
|
|
137
169
|
Logger.log("Matching against: #{trigger}#{sig.signature}")
|
|
138
170
|
res = message.message.scan(/^#{trigger}#{sig.signature}$/)
|
|
139
171
|
if(res.size > 0)
|
data/lib/mod_spox/Plugin.rb
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module ModSpox
|
|
2
|
+
# Holder for plugin
|
|
3
|
+
class PluginHolder
|
|
4
|
+
# Create a new holder with a plugin
|
|
5
|
+
def initialize(plugin)
|
|
6
|
+
@plugin = plugin
|
|
7
|
+
@lock = Mutex.new
|
|
8
|
+
end
|
|
9
|
+
# plugin:: Plugin to set into this holder
|
|
10
|
+
def set_plugin(plugin)
|
|
11
|
+
@lock.synchronize do
|
|
12
|
+
@plugin = plugin
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
# Returns the plugin this holder contains
|
|
16
|
+
def plugin
|
|
17
|
+
@lock.synchronize do
|
|
18
|
+
return @plugin
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
['fileutils',
|
|
2
|
+
'mod_spox/Logger',
|
|
3
|
+
'mod_spox/Pipeline',
|
|
4
|
+
'mod_spox/models/Models',
|
|
5
|
+
'mod_spox/messages/Messages',
|
|
6
|
+
'mod_spox/Plugin',
|
|
7
|
+
'mod_spox/PluginHolder'].each{|f|require f}
|
|
2
8
|
module ModSpox
|
|
3
9
|
|
|
4
10
|
class PluginManager
|
|
@@ -17,14 +23,26 @@ module ModSpox
|
|
|
17
23
|
@pipeline.hook(self, :send_modules, :Internal_PluginModuleRequest)
|
|
18
24
|
@pipeline.hook(self, :plugin_request, :Internal_PluginRequest)
|
|
19
25
|
@plugins_module = Module.new
|
|
26
|
+
@plugin_lock = Mutex.new
|
|
20
27
|
load_plugins
|
|
21
28
|
end
|
|
22
29
|
|
|
23
30
|
# message:: Messages::Internal::PluginReload
|
|
24
31
|
# Destroys and reinitializes plugins
|
|
25
|
-
def reload_plugins(
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
def reload_plugins(message=nil)
|
|
33
|
+
@plugin_lock.synchronize do
|
|
34
|
+
if(message.fresh && message.stale)
|
|
35
|
+
do_unload(message.stale)
|
|
36
|
+
FileUtils.remove_file(message.stale)
|
|
37
|
+
FileUtils.copy(message.fresh, BotConfig[:userpluginpath])
|
|
38
|
+
do_load(message.stale)
|
|
39
|
+
Logger.log("Completed reload of plugin: #{message.stale}")
|
|
40
|
+
else
|
|
41
|
+
unload_plugins
|
|
42
|
+
load_plugins
|
|
43
|
+
end
|
|
44
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
45
|
+
end
|
|
28
46
|
end
|
|
29
47
|
|
|
30
48
|
# Destroys plugins
|
|
@@ -36,32 +54,34 @@ module ModSpox
|
|
|
36
54
|
# Loads a plugin
|
|
37
55
|
def load_plugin(message)
|
|
38
56
|
begin
|
|
39
|
-
path = !message.name ? BotConfig[:userpluginpath] : "#{BotConfig[:userpluginpath]}/#{message.name}"
|
|
57
|
+
path = !message.name ? "#{BotConfig[:userpluginpath]}/#{message.path.gsub(/^.+\//, '')}" : "#{BotConfig[:userpluginpath]}/#{message.name}"
|
|
40
58
|
FileUtils.copy(message.path, path)
|
|
41
|
-
|
|
59
|
+
do_load(path)
|
|
42
60
|
@pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, true)
|
|
43
61
|
Logger.log("Loaded new plugin: #{message.path}", 10)
|
|
44
62
|
rescue Object => boom
|
|
45
63
|
Logger.log("Failed to load plugin: #{message.path} Reason: #{boom}", 10)
|
|
46
64
|
@pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, false)
|
|
47
65
|
end
|
|
66
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
48
67
|
end
|
|
49
68
|
|
|
50
69
|
# message:: Messages::Internal::PluginUnloadRequest
|
|
51
70
|
# Unloads a plugin
|
|
52
71
|
def unload_plugin(message)
|
|
53
72
|
begin
|
|
73
|
+
do_unload(message.path)
|
|
54
74
|
unless(message.name.nil?)
|
|
55
75
|
FileUtils.copy(message.path, "#{BotConfig[:userpluginpath]}/#{message.name}")
|
|
56
76
|
end
|
|
57
77
|
FileUtils.remove_file(message.path)
|
|
58
|
-
reload_plugins
|
|
59
78
|
@pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, true)
|
|
60
79
|
Logger.log("Unloaded plugin: #{message.path}", 10)
|
|
61
80
|
rescue Object => boom
|
|
62
81
|
Logger.log("Failed to unload plugin: #{message.path} Reason: #{boom}", 10)
|
|
63
82
|
@pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, false)
|
|
64
83
|
end
|
|
84
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
65
85
|
end
|
|
66
86
|
|
|
67
87
|
# message:: Messages::Internal::PluginModuleRequest
|
|
@@ -86,39 +106,117 @@ module ModSpox
|
|
|
86
106
|
# Loads and initializes plugins
|
|
87
107
|
def load_plugins
|
|
88
108
|
@pipeline << Messages::Internal::TimerClear.new
|
|
89
|
-
|
|
90
|
-
|
|
109
|
+
Models::Signature.destroy_all
|
|
110
|
+
[BotConfig[:pluginpath], BotConfig[:userpluginpath]].each do |path|
|
|
111
|
+
Dir.new(path).each do |file|
|
|
91
112
|
if(file =~ /^[^\.].+\.rb$/)
|
|
92
113
|
begin
|
|
93
|
-
|
|
114
|
+
do_load("#{path}/#{file}")
|
|
94
115
|
rescue Object => boom
|
|
95
116
|
Logger.log("Failed to load file: #{path}/#{file}. Reason: #{boom}")
|
|
96
117
|
end
|
|
97
118
|
end
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
@plugins_module.constants.each{|const|
|
|
101
|
-
klass = @plugins_module.const_get(const)
|
|
102
|
-
if(klass < Plugin)
|
|
103
|
-
begin
|
|
104
|
-
@plugins[const.to_sym] = klass.new(@pipeline)
|
|
105
|
-
Logger.log("Initialized new plugin: #{const}", 15)
|
|
106
|
-
rescue Object => boom
|
|
107
|
-
Logger.log("Failed to initialize plugin #{const}. Reason: #{boom}")
|
|
108
|
-
end
|
|
109
119
|
end
|
|
110
|
-
|
|
120
|
+
end
|
|
111
121
|
@pipeline << Messages::Internal::SignaturesUpdate.new
|
|
112
122
|
end
|
|
113
123
|
|
|
114
124
|
# Destroys plugins
|
|
115
125
|
def unload_plugins
|
|
116
|
-
@plugins.each_pair
|
|
117
|
-
|
|
118
|
-
|
|
126
|
+
@plugins.each_pair do |sym, holder|
|
|
127
|
+
holder.plugin.destroy
|
|
128
|
+
@pipeline.unhook_plugin(holder.plugin)
|
|
129
|
+
end
|
|
130
|
+
Models::Signature.destroy_all
|
|
119
131
|
@plugins_module = Module.new
|
|
120
132
|
@pipeline << Messages::Internal::TimerClear.new
|
|
121
133
|
end
|
|
134
|
+
|
|
135
|
+
# path:: path to plugin file
|
|
136
|
+
# Loads a plugin into the plugin module
|
|
137
|
+
def do_load(path)
|
|
138
|
+
if(File.exists?(path))
|
|
139
|
+
plugins = discover_plugins(path)
|
|
140
|
+
raise PluginMissing.new("Plugin file at: #{path} does not contain a plugin class") if plugins.nil?
|
|
141
|
+
@plugins_module.module_eval(IO.readlines(path).join("\n"))
|
|
142
|
+
begin
|
|
143
|
+
plugins.each do |plugin|
|
|
144
|
+
klass = @plugins_module.const_get(plugin)
|
|
145
|
+
if(@plugins.has_key?(plugin.to_sym))
|
|
146
|
+
@plugins[plugin.to_sym].set_plugin(klass.new(@pipeline))
|
|
147
|
+
else
|
|
148
|
+
@plugins[plugin.to_sym] = PluginHolder.new(klass.new(@pipeline))
|
|
149
|
+
end
|
|
150
|
+
Logger.log("Properly initialized new plugin: #{plugin}", 25)
|
|
151
|
+
end
|
|
152
|
+
Logger.log("All plugins found at: #{path} have been loaded")
|
|
153
|
+
rescue Object => boom
|
|
154
|
+
Logger.log("Plugin loading failed: #{boom}\n#{boom.backtrace.join("\n")}", 25)
|
|
155
|
+
Logger.log("All constants loaded from file: #{path} will now be unloaded")
|
|
156
|
+
do_unload(path)
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
raise PluginFileNotFound.new("Failed to find file at: #{path}")
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# path:: path to plugin file
|
|
164
|
+
# Unloads a plugin and all constants from the plugin module
|
|
165
|
+
def do_unload(path)
|
|
166
|
+
if(File.exists?(path))
|
|
167
|
+
discover_plugins(path).each do |plugin|
|
|
168
|
+
if(@plugins.has_key?(plugin.to_sym))
|
|
169
|
+
@plugins[plugin.to_sym].plugin.destroy
|
|
170
|
+
@pipeline.unhook_plugin(@plugins[plugin.to_sym].plugin)
|
|
171
|
+
@plugins[plugin.to_sym].set_plugin(nil)
|
|
172
|
+
@pipeline << Messages::Internal::TimerClear.new(plugin.to_sym)
|
|
173
|
+
end
|
|
174
|
+
Models::Signature.filter(:plugin => plugin).destroy
|
|
175
|
+
end
|
|
176
|
+
discover_consts(path).each do |const|
|
|
177
|
+
Logger.log("Removing constant: #{const}")
|
|
178
|
+
@plugins_module.send(:remove_const, const)
|
|
179
|
+
end
|
|
180
|
+
Logger.log("Removed all constants found in file: #{path}")
|
|
181
|
+
else
|
|
182
|
+
raise PluginFileNotFound.new("Failed to find file at: #{path}")
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# path:: path to plugin
|
|
187
|
+
# Find class names of any plugins within the file at given path
|
|
188
|
+
def discover_plugins(path)
|
|
189
|
+
temp = Module.new
|
|
190
|
+
begin
|
|
191
|
+
temp.module_eval(IO.readlines(path).join("\n"))
|
|
192
|
+
klasses = []
|
|
193
|
+
temp.constants.each do |const|
|
|
194
|
+
klass = temp.const_get(const)
|
|
195
|
+
klasses << const if klass < Plugin
|
|
196
|
+
end
|
|
197
|
+
return klasses
|
|
198
|
+
rescue Object => boom
|
|
199
|
+
return nil
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# path:: path to plugin
|
|
204
|
+
# Find all constant names in given path
|
|
205
|
+
def discover_consts(path)
|
|
206
|
+
temp = Module.new
|
|
207
|
+
begin
|
|
208
|
+
temp.module_eval(IO.readlines(path).join("\n"))
|
|
209
|
+
return temp.constants
|
|
210
|
+
rescue Object => boom
|
|
211
|
+
return nil
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
class PluginMissing < Exceptions::BotException
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
class PluginFileNotFound < Exceptions::BotException
|
|
219
|
+
end
|
|
122
220
|
|
|
123
221
|
end
|
|
124
222
|
|
data/lib/mod_spox/Pool.rb
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
|
+
['mod_spox/Logger',
|
|
2
|
+
'mod_spox/Exceptions',
|
|
3
|
+
'mod_spox/Monitors',
|
|
4
|
+
'timeout'].each{|f|require f}
|
|
5
|
+
|
|
1
6
|
module ModSpox
|
|
2
7
|
|
|
3
8
|
# The Pool class is used to reduce thread creation. It provides
|
|
4
|
-
# an easy way to process many
|
|
9
|
+
# an easy way to process many actions in an asynchronous manner.
|
|
5
10
|
class Pool
|
|
6
|
-
|
|
11
|
+
|
|
7
12
|
# Action thread is to perform
|
|
8
13
|
attr_reader :proc
|
|
9
14
|
# Storage space that the pool will be processing
|
|
10
15
|
attr_reader :queue
|
|
11
16
|
|
|
12
|
-
# Create a new
|
|
17
|
+
# Create a new pool
|
|
13
18
|
def initialize
|
|
14
19
|
@proc = Proc.new{ run_processor }
|
|
15
20
|
@queue = PoolQueue.new
|
|
@@ -31,10 +36,12 @@ module ModSpox
|
|
|
31
36
|
begin
|
|
32
37
|
processor
|
|
33
38
|
rescue Object => boom
|
|
34
|
-
Logger.log("Pool encountered an error processing code block: #{boom}")
|
|
39
|
+
Logger.log("Pool encountered an error processing code block: #{boom}", 99)
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
|
|
43
|
+
# Action the pool is responsible for. This is the method
|
|
44
|
+
# the child class should override
|
|
38
45
|
def processor
|
|
39
46
|
raise Exceptions::NotImplemented.new('Processor method has not been implemented')
|
|
40
47
|
end
|
|
@@ -43,21 +50,30 @@ module ModSpox
|
|
|
43
50
|
@@pools = Array.new
|
|
44
51
|
# Threads running in pool
|
|
45
52
|
@@threads = Array.new
|
|
46
|
-
#
|
|
47
|
-
@@
|
|
53
|
+
# Schedule lock for thread safety
|
|
54
|
+
@@schedule_lock = Mutex.new
|
|
55
|
+
# Thread creation lock
|
|
56
|
+
@@thread_lock = Mutex.new
|
|
48
57
|
# Maximum number of seconds a thread may spend waiting for an action
|
|
49
58
|
@@max_exec_time = 60
|
|
59
|
+
# Maximum number of threads to process Pool
|
|
60
|
+
@@max_threads = 10
|
|
61
|
+
# Maxium wait time (max time for threads to wait for new action to process)
|
|
62
|
+
@@max_wait_time = 20
|
|
63
|
+
# Monitor for threads to wait in
|
|
64
|
+
@@stop_point = Monitors::Timer.new
|
|
50
65
|
# Informs threads to halt
|
|
51
66
|
@@kill = false
|
|
52
67
|
|
|
53
68
|
# Adds a new thread to the pool
|
|
54
|
-
def Pool.add_thread
|
|
55
|
-
@@threads
|
|
56
|
-
|
|
69
|
+
def Pool.add_thread(force=false)
|
|
70
|
+
if(force || @@threads.size < @@max_threads)
|
|
71
|
+
thr = Thread.new do
|
|
57
72
|
Pool.schedule_thread
|
|
58
73
|
end
|
|
59
|
-
@@threads
|
|
74
|
+
@@threads << thr
|
|
60
75
|
end
|
|
76
|
+
@@stop_point.wakeup
|
|
61
77
|
end
|
|
62
78
|
|
|
63
79
|
# Returns the largest queue size of all available pools
|
|
@@ -72,12 +88,15 @@ module ModSpox
|
|
|
72
88
|
# Schedules a thread within the pool
|
|
73
89
|
def Pool.schedule_thread
|
|
74
90
|
run_pool = nil
|
|
75
|
-
@@
|
|
91
|
+
@@schedule_lock.synchronize do
|
|
76
92
|
@@pools.each do |pool|
|
|
77
93
|
run_pool = pool if (run_pool.nil? && pool.queue.size > 0) || (!run_pool.nil? && (run_pool.queue.size < pool.queue.size))
|
|
78
94
|
end
|
|
79
95
|
end
|
|
80
|
-
|
|
96
|
+
if(run_pool.nil?)
|
|
97
|
+
@@threads.delete(Thread.current)
|
|
98
|
+
return
|
|
99
|
+
else
|
|
81
100
|
begin
|
|
82
101
|
Timeout::timeout(@@max_exec_time) do
|
|
83
102
|
run_pool.proc.call
|
|
@@ -88,14 +107,23 @@ module ModSpox
|
|
|
88
107
|
Logger.log("Thread encountered error processing pool item: #{boom}")
|
|
89
108
|
end
|
|
90
109
|
end
|
|
110
|
+
start = Time.now
|
|
111
|
+
@@stop_point.wait(@@max_wait_time) if Pool.max_queue_size < 1
|
|
112
|
+
if((Time.now - start).to_i < @@max_wait_time)
|
|
113
|
+
Pool.schedule_thread
|
|
114
|
+
else
|
|
115
|
+
@@threads.delete(Thread.current)
|
|
116
|
+
@@threads.each do |thread|
|
|
117
|
+
@@threads.delete(thread) unless thread.alive?
|
|
118
|
+
end
|
|
119
|
+
end
|
|
91
120
|
end
|
|
92
121
|
|
|
93
122
|
# Forces sleeping threads to wake up
|
|
94
123
|
def Pool.process
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Logger.log("Total number of threads in use system-wide: #{Thread.list.size}")
|
|
124
|
+
@@thread_lock.synchronize do
|
|
125
|
+
Pool.add_thread if Pool.max_queue_size > 0
|
|
126
|
+
end
|
|
99
127
|
end
|
|
100
128
|
|
|
101
129
|
# Adds a Pool to the master Pool list
|
|
@@ -106,8 +134,12 @@ module ModSpox
|
|
|
106
134
|
# Removes a Pool from the master Pool list
|
|
107
135
|
def Pool.remove_pool(pool)
|
|
108
136
|
@@pools.delete(pool)
|
|
109
|
-
|
|
110
|
-
|
|
137
|
+
if(@@pools.empty?)
|
|
138
|
+
@@kill = true
|
|
139
|
+
@@stop_point.wakeup
|
|
140
|
+
sleep(0.1)
|
|
141
|
+
@@threads.each{|t| t.kill if t.alive?}
|
|
142
|
+
end
|
|
111
143
|
end
|
|
112
144
|
|
|
113
145
|
# Modified Queue to properly interact with Pool
|
|
@@ -119,17 +151,14 @@ module ModSpox
|
|
|
119
151
|
end
|
|
120
152
|
|
|
121
153
|
def <<(val)
|
|
122
|
-
|
|
123
|
-
super
|
|
124
|
-
Pool.process
|
|
125
|
-
end
|
|
154
|
+
push(val)
|
|
126
155
|
end
|
|
127
156
|
|
|
128
157
|
def push(val)
|
|
129
158
|
@lock.synchronize do
|
|
130
159
|
super
|
|
131
|
-
Pool.process
|
|
132
160
|
end
|
|
161
|
+
Pool.process
|
|
133
162
|
end
|
|
134
163
|
|
|
135
164
|
def pop
|
data/lib/mod_spox/Socket.rb
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
['mod_spox/Logger',
|
|
2
|
+
'mod_spox/Pool',
|
|
3
|
+
'mod_spox/Exceptions',
|
|
4
|
+
'mod_spox/messages/Messages',
|
|
5
|
+
'mod_spox/models/Models',
|
|
6
|
+
'mod_spox/Pipeline'].each{|f|require f}
|
|
7
|
+
|
|
1
8
|
module ModSpox
|
|
2
9
|
|
|
3
10
|
class Socket < Pool
|
|
@@ -34,6 +41,7 @@ module ModSpox
|
|
|
34
41
|
@check_burst = 0
|
|
35
42
|
@pause = false
|
|
36
43
|
@sendq = @queue
|
|
44
|
+
@lock = Mutex.new
|
|
37
45
|
start_pool
|
|
38
46
|
end
|
|
39
47
|
|
|
@@ -96,7 +104,7 @@ module ModSpox
|
|
|
96
104
|
# Retrieves a string from the server
|
|
97
105
|
def read
|
|
98
106
|
message = @socket.gets
|
|
99
|
-
if(message.nil?) # || message =~ /^ERROR/)
|
|
107
|
+
if(message.nil? || @socket.closed?) # || message =~ /^ERROR/)
|
|
100
108
|
@pipeline << Messages::Internal::Disconnected.new
|
|
101
109
|
shutdown
|
|
102
110
|
server = Models::Server.find_or_create(:host => @server, :port => @port)
|
|
@@ -118,15 +126,18 @@ module ModSpox
|
|
|
118
126
|
|
|
119
127
|
# Starts the thread for sending messages to the server
|
|
120
128
|
def processor
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@time_check
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
@lock.synchronize do
|
|
130
|
+
write(@sendq.pop)
|
|
131
|
+
if((Time.now.to_i - @time_check) > @burst_in)
|
|
132
|
+
@time_check = nil
|
|
133
|
+
@check_burst = 0
|
|
134
|
+
elsif((Time.now.to_i - @time_check) <= @burst_in && @check_burst >= @burst)
|
|
135
|
+
Logger.log("Burst limit hit. Output paused for: #{@delay} seconds", 70)
|
|
136
|
+
sleep(@delay)
|
|
137
|
+
@time_check = nil
|
|
138
|
+
@check_burst = 0
|
|
139
|
+
end
|
|
140
|
+
end
|
|
130
141
|
end
|
|
131
142
|
|
|
132
143
|
# Starts the thread for reading messages from the server
|