mod_spox 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|