spox-mod_spox 0.3.1
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 +174 -0
- data/INSTALL +15 -0
- data/LICENSE +674 -0
- data/README.rdoc +73 -0
- data/bin/mod_spox +112 -0
- data/data/mod_spox/extras/AOLSpeak.rb +257 -0
- data/data/mod_spox/extras/AutoKick.rb +152 -0
- data/data/mod_spox/extras/AutoMode.rb +122 -0
- data/data/mod_spox/extras/AutoRejoin.rb +37 -0
- data/data/mod_spox/extras/Bash.rb +55 -0
- data/data/mod_spox/extras/Bouncer.rb +220 -0
- data/data/mod_spox/extras/Bullshit.rb +19 -0
- data/data/mod_spox/extras/Bytes.rb +11 -0
- data/data/mod_spox/extras/Confess.rb +244 -0
- data/data/mod_spox/extras/DCC.rb +182 -0
- data/data/mod_spox/extras/DevWatch.rb +153 -0
- data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
- data/data/mod_spox/extras/EightBall.rb +33 -0
- data/data/mod_spox/extras/FML.rb +35 -0
- data/data/mod_spox/extras/FloodKicker.rb +129 -0
- data/data/mod_spox/extras/Fortune.rb +76 -0
- data/data/mod_spox/extras/GoogleIt.rb +13 -0
- data/data/mod_spox/extras/Headers.rb +59 -0
- data/data/mod_spox/extras/Karma.rb +302 -0
- data/data/mod_spox/extras/Locator.rb +44 -0
- data/data/mod_spox/extras/Logger.rb +182 -0
- data/data/mod_spox/extras/LolSpeak.rb +21 -0
- data/data/mod_spox/extras/NickServ.rb +84 -0
- data/data/mod_spox/extras/PhpCli.rb +308 -0
- data/data/mod_spox/extras/PhpFuncLookup.rb +297 -0
- data/data/mod_spox/extras/Pinger.rb +11 -0
- data/data/mod_spox/extras/Quotes.rb +79 -0
- data/data/mod_spox/extras/RegexTracker.rb +158 -0
- data/data/mod_spox/extras/Roulette.rb +267 -0
- data/data/mod_spox/extras/RubyCli.rb +93 -0
- data/data/mod_spox/extras/Search.rb +49 -0
- data/data/mod_spox/extras/Seen.rb +150 -0
- data/data/mod_spox/extras/Slashdot.rb +35 -0
- data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
- data/data/mod_spox/extras/Talk.rb +32 -0
- data/data/mod_spox/extras/Topten.rb +103 -0
- data/data/mod_spox/extras/TracTicket.rb +66 -0
- data/data/mod_spox/extras/Translate.rb +132 -0
- data/data/mod_spox/extras/Twitter.rb +458 -0
- data/data/mod_spox/extras/UrbanDictionary.rb +55 -0
- data/data/mod_spox/extras/Weather.rb +55 -0
- data/data/mod_spox/plugins/Authenticator.rb +289 -0
- data/data/mod_spox/plugins/Banner.rb +585 -0
- data/data/mod_spox/plugins/BotNick.rb +18 -0
- data/data/mod_spox/plugins/Helper.rb +49 -0
- data/data/mod_spox/plugins/Initializer.rb +35 -0
- data/data/mod_spox/plugins/Joiner.rb +23 -0
- data/data/mod_spox/plugins/Nicker.rb +14 -0
- data/data/mod_spox/plugins/Parter.rb +23 -0
- data/data/mod_spox/plugins/Permissions.rb +60 -0
- data/data/mod_spox/plugins/PluginLoader.rb +180 -0
- data/data/mod_spox/plugins/Ponger.rb +70 -0
- data/data/mod_spox/plugins/PoolConfig.rb +52 -0
- data/data/mod_spox/plugins/Quitter.rb +15 -0
- data/data/mod_spox/plugins/Servers.rb +57 -0
- data/data/mod_spox/plugins/Status.rb +31 -0
- data/data/mod_spox/plugins/Triggers.rb +85 -0
- data/lib/mod_spox/BaseConfig.rb +51 -0
- data/lib/mod_spox/Bot.rb +604 -0
- data/lib/mod_spox/BotConfig.rb +65 -0
- data/lib/mod_spox/ConfigurationWizard.rb +180 -0
- data/lib/mod_spox/Database.rb +51 -0
- data/lib/mod_spox/Exceptions.rb +84 -0
- data/lib/mod_spox/Helpers.rb +122 -0
- data/lib/mod_spox/Loader.rb +60 -0
- data/lib/mod_spox/Logger.rb +37 -0
- data/lib/mod_spox/MessageFactory.rb +112 -0
- data/lib/mod_spox/Pipeline.rb +207 -0
- data/lib/mod_spox/Plugin.rb +97 -0
- data/lib/mod_spox/PluginHolder.rb +22 -0
- data/lib/mod_spox/PluginManager.rb +257 -0
- data/lib/mod_spox/PriorityQueue.rb +69 -0
- data/lib/mod_spox/Socket.rb +201 -0
- data/lib/mod_spox/Sockets.rb +226 -0
- data/lib/mod_spox/Timer.rb +60 -0
- data/lib/mod_spox/Version.rb +14 -0
- data/lib/mod_spox/handlers/BadNick.rb +19 -0
- data/lib/mod_spox/handlers/Bounce.rb +24 -0
- data/lib/mod_spox/handlers/Created.rb +27 -0
- data/lib/mod_spox/handlers/Handler.rb +39 -0
- data/lib/mod_spox/handlers/Invite.rb +28 -0
- data/lib/mod_spox/handlers/Join.rb +38 -0
- data/lib/mod_spox/handlers/Kick.rb +36 -0
- data/lib/mod_spox/handlers/LuserChannels.rb +19 -0
- data/lib/mod_spox/handlers/LuserClient.rb +18 -0
- data/lib/mod_spox/handlers/LuserMe.rb +16 -0
- data/lib/mod_spox/handlers/LuserOp.rb +19 -0
- data/lib/mod_spox/handlers/LuserUnknown.rb +19 -0
- data/lib/mod_spox/handlers/Mode.rb +62 -0
- data/lib/mod_spox/handlers/Motd.rb +38 -0
- data/lib/mod_spox/handlers/MyInfo.rb +24 -0
- data/lib/mod_spox/handlers/Names.rb +86 -0
- data/lib/mod_spox/handlers/Nick.rb +50 -0
- data/lib/mod_spox/handlers/NickInUse.rb +19 -0
- data/lib/mod_spox/handlers/Notice.rb +35 -0
- data/lib/mod_spox/handlers/Part.rb +39 -0
- data/lib/mod_spox/handlers/Ping.rb +25 -0
- data/lib/mod_spox/handlers/Pong.rb +23 -0
- data/lib/mod_spox/handlers/Privmsg.rb +39 -0
- data/lib/mod_spox/handlers/Quit.rb +29 -0
- data/lib/mod_spox/handlers/Topic.rb +38 -0
- data/lib/mod_spox/handlers/Welcome.rb +30 -0
- data/lib/mod_spox/handlers/Who.rb +83 -0
- data/lib/mod_spox/handlers/Whois.rb +117 -0
- data/lib/mod_spox/handlers/YourHost.rb +20 -0
- data/lib/mod_spox/messages/Messages.rb +6 -0
- data/lib/mod_spox/messages/incoming/BadNick.rb +16 -0
- data/lib/mod_spox/messages/incoming/Bounce.rb +18 -0
- data/lib/mod_spox/messages/incoming/Created.rb +15 -0
- data/lib/mod_spox/messages/incoming/Invite.rb +21 -0
- data/lib/mod_spox/messages/incoming/Join.rb +19 -0
- data/lib/mod_spox/messages/incoming/Kick.rb +26 -0
- data/lib/mod_spox/messages/incoming/LuserChannels.rb +15 -0
- data/lib/mod_spox/messages/incoming/LuserClient.rb +24 -0
- data/lib/mod_spox/messages/incoming/LuserMe.rb +18 -0
- data/lib/mod_spox/messages/incoming/LuserOp.rb +15 -0
- data/lib/mod_spox/messages/incoming/LuserUnknown.rb +15 -0
- data/lib/mod_spox/messages/incoming/Message.rb +22 -0
- data/lib/mod_spox/messages/incoming/Mode.rb +42 -0
- data/lib/mod_spox/messages/incoming/Motd.rb +18 -0
- data/lib/mod_spox/messages/incoming/MyInfo.rb +24 -0
- data/lib/mod_spox/messages/incoming/Names.rb +24 -0
- data/lib/mod_spox/messages/incoming/Nick.rb +26 -0
- data/lib/mod_spox/messages/incoming/NickInUse.rb +15 -0
- data/lib/mod_spox/messages/incoming/Notice.rb +9 -0
- data/lib/mod_spox/messages/incoming/Part.rb +21 -0
- data/lib/mod_spox/messages/incoming/Ping.rb +18 -0
- data/lib/mod_spox/messages/incoming/Pong.rb +9 -0
- data/lib/mod_spox/messages/incoming/Privmsg.rb +90 -0
- data/lib/mod_spox/messages/incoming/Quit.rb +18 -0
- data/lib/mod_spox/messages/incoming/Topic.rb +21 -0
- data/lib/mod_spox/messages/incoming/TopicInfo.rb +21 -0
- data/lib/mod_spox/messages/incoming/Welcome.rb +27 -0
- data/lib/mod_spox/messages/incoming/Who.rb +18 -0
- data/lib/mod_spox/messages/incoming/Whois.rb +49 -0
- data/lib/mod_spox/messages/incoming/YourHost.rb +18 -0
- data/lib/mod_spox/messages/internal/BotInitialized.rb +11 -0
- data/lib/mod_spox/messages/internal/ChangeNick.rb +15 -0
- data/lib/mod_spox/messages/internal/Connected.rb +20 -0
- data/lib/mod_spox/messages/internal/ConnectionFailed.rb +23 -0
- data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
- data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
- data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
- data/lib/mod_spox/messages/internal/Disconnected.rb +8 -0
- data/lib/mod_spox/messages/internal/Disconnecting.rb +8 -0
- data/lib/mod_spox/messages/internal/EstablishConnection.rb +22 -0
- data/lib/mod_spox/messages/internal/HaltBot.rb +8 -0
- data/lib/mod_spox/messages/internal/NickRequest.rb +9 -0
- data/lib/mod_spox/messages/internal/NickResponse.rb +15 -0
- data/lib/mod_spox/messages/internal/PluginLoadRequest.rb +21 -0
- data/lib/mod_spox/messages/internal/PluginLoadResponse.rb +17 -0
- data/lib/mod_spox/messages/internal/PluginModuleRequest.rb +14 -0
- data/lib/mod_spox/messages/internal/PluginModuleResponse.rb +18 -0
- data/lib/mod_spox/messages/internal/PluginReload.rb +18 -0
- data/lib/mod_spox/messages/internal/PluginRequest.rb +18 -0
- data/lib/mod_spox/messages/internal/PluginResponse.rb +21 -0
- data/lib/mod_spox/messages/internal/PluginUnloadRequest.rb +9 -0
- data/lib/mod_spox/messages/internal/PluginUnloadResponse.rb +9 -0
- 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/Request.rb +15 -0
- data/lib/mod_spox/messages/internal/Response.rb +15 -0
- data/lib/mod_spox/messages/internal/Shutdown.rb +8 -0
- data/lib/mod_spox/messages/internal/SignaturesUpdate.rb +8 -0
- data/lib/mod_spox/messages/internal/StatusRequest.rb +10 -0
- data/lib/mod_spox/messages/internal/StatusResponse.rb +18 -0
- data/lib/mod_spox/messages/internal/TimerAdd.rb +36 -0
- data/lib/mod_spox/messages/internal/TimerClear.rb +16 -0
- data/lib/mod_spox/messages/internal/TimerRemove.rb +23 -0
- data/lib/mod_spox/messages/internal/TimerResponse.rb +34 -0
- data/lib/mod_spox/messages/internal/TriggersUpdate.rb +8 -0
- data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
- data/lib/mod_spox/messages/outgoing/Admin.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Away.rb +11 -0
- data/lib/mod_spox/messages/outgoing/ChannelMode.rb +25 -0
- data/lib/mod_spox/messages/outgoing/Connect.rb +24 -0
- data/lib/mod_spox/messages/outgoing/Die.rb +9 -0
- data/lib/mod_spox/messages/outgoing/Info.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Invite.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Ison.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Join.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Kick.rb +23 -0
- data/lib/mod_spox/messages/outgoing/Kill.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Links.rb +19 -0
- data/lib/mod_spox/messages/outgoing/List.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Lusers.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Motd.rb +16 -0
- data/lib/mod_spox/messages/outgoing/Names.rb +20 -0
- data/lib/mod_spox/messages/outgoing/Nick.rb +16 -0
- data/lib/mod_spox/messages/outgoing/Notice.rb +12 -0
- data/lib/mod_spox/messages/outgoing/Oper.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Part.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Pass.rb +16 -0
- data/lib/mod_spox/messages/outgoing/Ping.rb +11 -0
- data/lib/mod_spox/messages/outgoing/Pong.rb +17 -0
- data/lib/mod_spox/messages/outgoing/Privmsg.rb +43 -0
- data/lib/mod_spox/messages/outgoing/Quit.rb +11 -0
- data/lib/mod_spox/messages/outgoing/Raw.rb +16 -0
- data/lib/mod_spox/messages/outgoing/Rehash.rb +9 -0
- data/lib/mod_spox/messages/outgoing/Restart.rb +9 -0
- data/lib/mod_spox/messages/outgoing/ServList.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Simple.rb +12 -0
- data/lib/mod_spox/messages/outgoing/Squery.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Squit.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Stats.rb +18 -0
- data/lib/mod_spox/messages/outgoing/Summon.rb +23 -0
- data/lib/mod_spox/messages/outgoing/Time.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Topic.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Trace.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Unaway.rb +9 -0
- data/lib/mod_spox/messages/outgoing/User.rb +23 -0
- data/lib/mod_spox/messages/outgoing/UserHost.rb +15 -0
- data/lib/mod_spox/messages/outgoing/UserMode.rb +19 -0
- data/lib/mod_spox/messages/outgoing/Users.rb +15 -0
- data/lib/mod_spox/messages/outgoing/Version.rb +16 -0
- data/lib/mod_spox/messages/outgoing/Who.rb +23 -0
- data/lib/mod_spox/messages/outgoing/WhoWas.rb +23 -0
- data/lib/mod_spox/messages/outgoing/Whois.rb +19 -0
- data/lib/mod_spox/migrations/001_initialize_models.rb +115 -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 +65 -0
- data/lib/mod_spox/models/AuthMask.rb +13 -0
- data/lib/mod_spox/models/Channel.rb +89 -0
- data/lib/mod_spox/models/Config.rb +30 -0
- data/lib/mod_spox/models/Group.rb +30 -0
- data/lib/mod_spox/models/Models.rb +4 -0
- data/lib/mod_spox/models/Nick.rb +195 -0
- data/lib/mod_spox/models/NickMode.rb +32 -0
- data/lib/mod_spox/models/Server.rb +27 -0
- data/lib/mod_spox/models/Setting.rb +52 -0
- data/lib/mod_spox/models/Signature.rb +52 -0
- data/lib/mod_spox/models/Trigger.rb +9 -0
- data/lib/mod_spox/rfc2812.rb +49 -0
- data/populate_gemspec.rb +15 -0
- 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 +39 -0
- data/tests/models/tc_Channel.rb +52 -0
- data/tests/models/tc_Config.rb +19 -0
- data/tests/models/tc_Nick.rb +144 -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 +6 -0
- metadata +362 -0
@@ -0,0 +1,207 @@
|
|
1
|
+
['mod_spox/models/Models.rb',
|
2
|
+
'mod_spox/Logger',
|
3
|
+
'mod_spox/Exceptions',
|
4
|
+
'mod_spox/messages/incoming/Privmsg',
|
5
|
+
'mod_spox/messages/incoming/Notice'].each{|f|require f}
|
6
|
+
module ModSpox
|
7
|
+
|
8
|
+
class Pipeline
|
9
|
+
|
10
|
+
# Create a new Pipeline
|
11
|
+
def initialize(pool)
|
12
|
+
@pool = pool
|
13
|
+
@hooks = Hash.new
|
14
|
+
@plugins = Hash.new
|
15
|
+
@admin = Models::Group.filter(:name => 'admin').first
|
16
|
+
@populate_lock = Mutex.new
|
17
|
+
populate_triggers
|
18
|
+
populate_signatures
|
19
|
+
hook(self, :populate_triggers, :Internal_TriggersUpdate)
|
20
|
+
hook(self, :populate_signatures, :Internal_SignaturesUpdate)
|
21
|
+
end
|
22
|
+
|
23
|
+
# message:: Message to send down pipeline
|
24
|
+
# Queues a message to send down pipeline
|
25
|
+
def <<(message)
|
26
|
+
Logger.info("Message added to pipeline queue: #{message}")
|
27
|
+
message_processor(message)
|
28
|
+
end
|
29
|
+
|
30
|
+
# plugin:: Plugin to hook to pipeline
|
31
|
+
# Hooks a plugin into the pipeline so it can be called
|
32
|
+
# directly when it matches a trigger
|
33
|
+
def hook_plugin(plugin)
|
34
|
+
Logger.info("Plugin #{plugin.name} hooking into pipeline")
|
35
|
+
@plugins[plugin.name.to_sym] = plugin
|
36
|
+
end
|
37
|
+
|
38
|
+
# plugin:: Plugin to unhook from pipeline
|
39
|
+
# Unhooks a plugin from the pipeline (This does not unhook
|
40
|
+
# it from the standard hooks)
|
41
|
+
def unhook_plugin(plugin)
|
42
|
+
Logger.info("Plugin #{plugin.name} unhooking from pipeline")
|
43
|
+
@plugins.delete(plugin.name.to_sym)
|
44
|
+
@hooks.each_pair do |type, things|
|
45
|
+
things.delete(plugin.name.to_sym) if things.has_key?(plugin.name.to_sym)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# plugin:: Plugin to hook to pipeline
|
50
|
+
# method:: Plugin method pipeline should call to process message
|
51
|
+
# type:: Type of message the plugin wants to process
|
52
|
+
# Hooks a plugin into the pipeline for a specific type of message
|
53
|
+
def hook(object, method, type)
|
54
|
+
Logger.info("Object #{object.class.to_s} hooking into messages of type: #{type}")
|
55
|
+
type = type.gsub(/::/, '_').to_sym unless type.is_a?(Symbol)
|
56
|
+
method = method.to_sym unless method.is_a?(Symbol)
|
57
|
+
name = object.class.to_s.gsub(/^.+:/, '')
|
58
|
+
@hooks[type] = Hash.new unless @hooks.has_key?(type)
|
59
|
+
@hooks[type][name.to_sym] = Array.new unless @hooks[type][name.to_sym].is_a?(Array)
|
60
|
+
@hooks[type][name.to_sym] << {:object => object, :method => method}
|
61
|
+
end
|
62
|
+
|
63
|
+
# plugin:: Plugin to unhook from pipeline
|
64
|
+
# type:: Type of message the plugin no longer wants to process
|
65
|
+
# This will remove the hook a plugin has for a specific message type
|
66
|
+
def unhook(object, method, type)
|
67
|
+
Logger.info("Object #{object.class.to_s} unhooking from messages of type: #{type}")
|
68
|
+
type = type.gsub(/::/, '_').to_sym unless type.is_a?(Symbol)
|
69
|
+
name = object.class.to_s.gsub(/^.+:/, '').to_sym
|
70
|
+
raise Exceptions::InvalidValue.new("Unknown hook type given: #{type.to_s}") unless @hooks.has_key?(type)
|
71
|
+
raise Exceptions::InvalidValue.new("Unknown object hooked: #{name.to_s}") unless @hooks[type].has_key?(name)
|
72
|
+
@hooks[type][name].each{|hook|
|
73
|
+
@hooks[type][name].delete(hook) if hook[:method] == method
|
74
|
+
}
|
75
|
+
@hooks[type].delete(name) if @hooks[type][name].empty
|
76
|
+
@hooks.delete(type) if @hooks[type].empty?
|
77
|
+
end
|
78
|
+
|
79
|
+
# Clears all hooks from the pipeline (Commonly used when reloading plugins)
|
80
|
+
def clear
|
81
|
+
Logger.info("All hooks have been cleared from pipeline")
|
82
|
+
@hooks.clear
|
83
|
+
@plugins.clear
|
84
|
+
end
|
85
|
+
|
86
|
+
# Repopulate the active trigger list
|
87
|
+
def populate_triggers(m=nil)
|
88
|
+
@populate_lock.synchronize do
|
89
|
+
@triggers = []
|
90
|
+
Models::Trigger.filter(:active => true).each{|t|@triggers << t.trigger}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Repopulate the active signatures list
|
95
|
+
def populate_signatures(m=nil)
|
96
|
+
@populate_lock.synchronize do
|
97
|
+
@signatures = {}
|
98
|
+
a = Models::Signature.filter(:enabled => false)
|
99
|
+
Logger.warn("Killing #{a.count} signatures")
|
100
|
+
a.destroy
|
101
|
+
Models::Signature.all.each do |s|
|
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
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# Processes messages
|
121
|
+
def message_processor(message)
|
122
|
+
begin
|
123
|
+
Logger.info("Pipeline is processing a message: #{message}")
|
124
|
+
parse(message)
|
125
|
+
type = message.class.to_s.gsub(/^(ModSpox::Messages::|#<.+?>::)/, '').gsub('::', '_').to_sym
|
126
|
+
mod = type.to_s.gsub(/_.+$/, '').to_sym
|
127
|
+
Logger.info("Pipeline determines that #{message} is of type: #{type}")
|
128
|
+
[type, mod, :all].each do |type|
|
129
|
+
if(@hooks.has_key?(type))
|
130
|
+
@hooks[type].each_value do |objects|
|
131
|
+
begin
|
132
|
+
objects.each do |v|
|
133
|
+
@pool.process do
|
134
|
+
begin
|
135
|
+
v[:object].send(v[:method].to_s, message)
|
136
|
+
rescue Object => boom
|
137
|
+
if(boom.class.to_s == 'SQLite3::BusyException')
|
138
|
+
Database.reset_connections
|
139
|
+
retry
|
140
|
+
else
|
141
|
+
raise boom
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
rescue Object => boom
|
147
|
+
Logger.warn("Plugin threw exception while attempting to process message: #{boom}\n#{boom.backtrace.join("\n")}")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
rescue Object => boom
|
153
|
+
Logger.warn("Pipeline encountered an exception while processing a message: #{boom}\n#{boom.backtrace.join("\n")}")
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# message:: Message to parse
|
158
|
+
# This will parse a message to see if it matches any valid
|
159
|
+
# trigger signatures. If matches are found, they will be sent
|
160
|
+
# to the proper plugin for processing
|
161
|
+
def parse(message)
|
162
|
+
return unless message.kind_of?(Messages::Incoming::Privmsg) || message.kind_of?(Messages::Incoming::Notice)
|
163
|
+
trigger = nil
|
164
|
+
@triggers.each{|t| trigger = t if message.message[0..t.size-1] == t}
|
165
|
+
if(!trigger.nil? || message.addressed?)
|
166
|
+
return if !trigger.nil? && message.message.length == trigger.length
|
167
|
+
Logger.info("Message has matched against a known trigger")
|
168
|
+
c = (message.addressed? && trigger.nil?) ? message.message[0].chr.downcase : message.message[trigger.length].chr.downcase
|
169
|
+
if(c =~ /^[a-z]$/)
|
170
|
+
type = c.to_sym
|
171
|
+
elsif(c =~ /^[0-9]$/)
|
172
|
+
type = :digit
|
173
|
+
else
|
174
|
+
type = :other
|
175
|
+
end
|
176
|
+
sig_check = @signatures.has_key?(type) ? @signatures[type] : []
|
177
|
+
sig_check = sig_check + @signatures[:other] if type != :other && @signatures.has_key?(:other)
|
178
|
+
sig_check.each do |sig|
|
179
|
+
Logger.info("Matching against: #{trigger}#{sig.signature}")
|
180
|
+
esc_trig = trigger.nil? ? '' : Regexp.escape(trigger)
|
181
|
+
res = message.message.scan(/^#{esc_trig}#{sig.signature}$/)
|
182
|
+
if(res.size > 0)
|
183
|
+
next unless message.source.in_group?(sig.group) || message.source.in_group?(@admin) || sig.group.nil?
|
184
|
+
next if sig.requirement == 'private' && message.is_public?
|
185
|
+
next if sig.requirement == 'public' && message.is_private?
|
186
|
+
params = Hash.new
|
187
|
+
sig.params.size.times do |i|
|
188
|
+
params[sig.params[i].to_sym] = res[0][i]
|
189
|
+
Logger.info("Signature params: #{sig.params[i].to_sym} = #{res[0][i]}")
|
190
|
+
end
|
191
|
+
if(@plugins.has_key?(sig.plugin.to_sym))
|
192
|
+
begin
|
193
|
+
@pool.process{ @plugins[sig.plugin.to_sym].send(sig.values[:method], message, params) }
|
194
|
+
rescue Object => boom
|
195
|
+
Logger.warn("Plugin threw exception while attempting to process message: #{boom}\n#{boom.backtrace.join("\n")}")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
else
|
201
|
+
Logger.info("Message failed to match any known trigger")
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
['mod_spox/Pipeline',
|
2
|
+
'mod_spox/Logger',
|
3
|
+
'mod_spox/Exceptions',
|
4
|
+
'mod_spox/messages/outgoing/Privmsg'].each{|f|require f}
|
5
|
+
module ModSpox
|
6
|
+
class Plugin
|
7
|
+
include Models
|
8
|
+
def initialize(args)
|
9
|
+
@pipeline = args[:pipeline]
|
10
|
+
@plugin_module = args[:plugin_module]
|
11
|
+
raise Exceptions::BotException.new('Plugin creation failed to supply message pipeline') unless @pipeline.is_a?(Pipeline)
|
12
|
+
@pipeline.hook_plugin(self)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Called before the object is destroyed by the ModSpox::PluginManager
|
16
|
+
def destroy
|
17
|
+
Logger.info("Destroy method for plugin #{name} has not been defined.")
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns the name of the class
|
21
|
+
def name
|
22
|
+
self.class.name.to_s.gsub(/^.+:/, '')
|
23
|
+
end
|
24
|
+
|
25
|
+
# target:: target for message
|
26
|
+
# message:: string message
|
27
|
+
# This is a helper method that will send an outgoing Privmsg
|
28
|
+
# to the given target
|
29
|
+
def reply(target, message)
|
30
|
+
@pipeline << Messages::Outgoing::Privmsg.new(target, message)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the nick model of the bot
|
34
|
+
def me
|
35
|
+
nick = Models::Nick.filter(:botnick => true).first
|
36
|
+
if(nick)
|
37
|
+
return nick
|
38
|
+
else
|
39
|
+
raise Exception.new("Fatal Error: I don't know who I am.")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns constant given from plugin module. Raises ModSpox::Exceptions::InvalidType
|
44
|
+
# exception if constant is not found within the module
|
45
|
+
# Note: Use _ for depth (ie: Foo::Bar::Fee if Fee is wanted give: :Foo_Bar_Fee)
|
46
|
+
def plugin_const(const)
|
47
|
+
klass = @plugin_module
|
48
|
+
begin
|
49
|
+
const.to_s.split('_').each do |part|
|
50
|
+
klass = klass.const_get(part.to_sym)
|
51
|
+
end
|
52
|
+
rescue NameError => boom
|
53
|
+
raise ModSpox::Exceptions::InvalidType.new("Requested constant has not been defined within the plugins module (#{const}): #{boom}")
|
54
|
+
end
|
55
|
+
if(klass.nil?)
|
56
|
+
raise ModSpox::Exceptions::InvalidType.new("Requested constant has not been defined within the plugins module (#{const})")
|
57
|
+
else
|
58
|
+
return klass
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Adds a new signature for the given plugin
|
63
|
+
# Required args: :sig and :method
|
64
|
+
# Optional args: :group, :req, :desc, and :params
|
65
|
+
def add_sig(args)
|
66
|
+
raise ModSpox::Exceptions::InvalidType.new('You must provide a hash for creating new signatures') unless args.is_a?(Hash)
|
67
|
+
args[:params] = nil unless args[:params]
|
68
|
+
sig = Signature.find_or_create(:signature => args[:sig], :plugin => name, :method => args[:method].to_s,
|
69
|
+
:params => args[:params], :group_id => args[:group].nil? ? nil : args[:group].pk)
|
70
|
+
sig.description = args[:desc] if args.has_key?(:desc)
|
71
|
+
sig.requirement = args[:req] if args.has_key?(:req)
|
72
|
+
sig.save
|
73
|
+
end
|
74
|
+
|
75
|
+
# to:: Where message is going
|
76
|
+
# message:: message
|
77
|
+
# Send an information message to target
|
78
|
+
def information(to, message)
|
79
|
+
reply to, "\2#{name} (info):\2 #{message}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# to:: Where message is going
|
83
|
+
# message:: message
|
84
|
+
# Send an warning message to target
|
85
|
+
def warning(to, message)
|
86
|
+
reply to, "\2#{name} (warn):\2 #{message}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# to:: Where message is going
|
90
|
+
# message:: message
|
91
|
+
# Send an error message to target
|
92
|
+
def error(to, message)
|
93
|
+
reply to, "\2#{name} (error):\2 #{message}"
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
@@ -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
|
@@ -0,0 +1,257 @@
|
|
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',
|
8
|
+
'mod_spox/Exceptions',
|
9
|
+
'mod_spox/messages/internal/QueueSocket',
|
10
|
+
'mod_spox/messages/internal/UnqueueSocket',
|
11
|
+
'mod_spox/messages/internal/PluginLoadResponse',
|
12
|
+
'mod_spox/messages/internal/SignaturesUpdate',
|
13
|
+
'mod_spox/messages/internal/PluginUnloadResponse',
|
14
|
+
'mod_spox/messages/internal/PluginModuleResponse',
|
15
|
+
'mod_spox/messages/internal/PluginResponse',
|
16
|
+
'mod_spox/messages/internal/TimerClear',
|
17
|
+
'mod_spox/messages/internal/PluginsReady'].each{|f|require f}
|
18
|
+
|
19
|
+
module ModSpox
|
20
|
+
|
21
|
+
class PluginManager
|
22
|
+
|
23
|
+
include Exceptions
|
24
|
+
|
25
|
+
# Hash of plugins. Defined by class name symbol (i.e. Trivia class: plugins[:Trivia])
|
26
|
+
attr_reader :plugins
|
27
|
+
|
28
|
+
# pipeline:: Pipeline for messages
|
29
|
+
# Create new PluginManager
|
30
|
+
def initialize(pipeline)
|
31
|
+
@plugins = Hash.new
|
32
|
+
@pipeline = pipeline
|
33
|
+
@pipeline.hook(self, :load_plugin, :Internal_PluginLoadRequest)
|
34
|
+
@pipeline.hook(self, :unload_plugin, :Internal_PluginUnloadRequest)
|
35
|
+
@pipeline.hook(self, :reload_plugins, :Internal_PluginReload)
|
36
|
+
@pipeline.hook(self, :send_modules, :Internal_PluginModuleRequest)
|
37
|
+
@pipeline.hook(self, :plugin_request, :Internal_PluginRequest)
|
38
|
+
@plugins_module = Module.new
|
39
|
+
@plugin_lock = Mutex.new
|
40
|
+
load_plugins
|
41
|
+
end
|
42
|
+
|
43
|
+
# message:: Messages::Internal::PluginReload
|
44
|
+
# Destroys and reinitializes plugins
|
45
|
+
def reload_plugins(message=nil)
|
46
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
47
|
+
begin
|
48
|
+
@plugin_lock.synchronize do
|
49
|
+
if(!message.nil? && (message.fresh && message.stale))
|
50
|
+
do_unload(message.stale)
|
51
|
+
FileUtils.remove_file(message.stale)
|
52
|
+
FileUtils.copy(message.fresh, BotConfig[:userpluginpath])
|
53
|
+
do_load(message.stale)
|
54
|
+
Logger.info("Completed reload of plugin: #{message.stale}")
|
55
|
+
else
|
56
|
+
unload_plugins
|
57
|
+
load_plugins
|
58
|
+
end
|
59
|
+
end
|
60
|
+
rescue Object => boom
|
61
|
+
Logger.error("PluginManager caught error on plugin reload: #{boom}")
|
62
|
+
ensure
|
63
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Destroys plugins
|
68
|
+
def destroy_plugins
|
69
|
+
unload_plugins
|
70
|
+
end
|
71
|
+
|
72
|
+
# message:: Messages::Internal::PluginLoadRequest
|
73
|
+
# Loads a plugin
|
74
|
+
def load_plugin(message)
|
75
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
76
|
+
begin
|
77
|
+
path = !message.name ? "#{BotConfig[:userpluginpath]}/#{message.path.gsub(/^.+\//, '')}" : "#{BotConfig[:userpluginpath]}/#{message.name}"
|
78
|
+
begin
|
79
|
+
File.symlink(message.path, path)
|
80
|
+
rescue NotImplementedError => boom
|
81
|
+
FileUtils.copy(message.path, path)
|
82
|
+
end
|
83
|
+
do_load(path)
|
84
|
+
@pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, true)
|
85
|
+
Logger.info("Loaded new plugin: #{message.path}")
|
86
|
+
rescue Object => boom
|
87
|
+
Logger.warn("Failed to load plugin: #{message.path} Reason: #{boom}")
|
88
|
+
@pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, false)
|
89
|
+
ensure
|
90
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
91
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# message:: Messages::Internal::PluginUnloadRequest
|
96
|
+
# Unloads a plugin
|
97
|
+
def unload_plugin(message)
|
98
|
+
@pipeline << Messages::Internal::QueueSocket.new
|
99
|
+
begin
|
100
|
+
do_unload(message.path)
|
101
|
+
unless(File.symlink?(message.path))
|
102
|
+
unless(message.name.nil?)
|
103
|
+
FileUtils.copy(message.path, "#{BotConfig[:userpluginpath]}/#{message.name}")
|
104
|
+
end
|
105
|
+
end
|
106
|
+
File.delete(message.path)
|
107
|
+
@pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, true)
|
108
|
+
Logger.info("Unloaded plugin: #{message.path}")
|
109
|
+
rescue Object => boom
|
110
|
+
Logger.warn("Failed to unload plugin: #{message.path} Reason: #{boom}")
|
111
|
+
@pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, false)
|
112
|
+
ensure
|
113
|
+
@pipeline << Messages::Internal::UnqueueSocket.new
|
114
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# message:: Messages::Internal::PluginModuleRequest
|
119
|
+
# Sends the plugins module to the requester
|
120
|
+
def send_modules(message)
|
121
|
+
@pipeline << Messages::Internal::PluginModuleResponse.new(message.requester, @plugins_module)
|
122
|
+
end
|
123
|
+
|
124
|
+
# message:: Messages::Internal::PluginRequest
|
125
|
+
# Returns a plugin to requesting object
|
126
|
+
def plugin_request(message)
|
127
|
+
if(@plugins.has_key?(message.plugin))
|
128
|
+
response = Messages::Internal::PluginResponse.new(message.requester, @plugins[message.plugin])
|
129
|
+
else
|
130
|
+
response = Messages::Internal::PluginResponse.new(message.requester, nil)
|
131
|
+
end
|
132
|
+
@pipeline << response
|
133
|
+
end
|
134
|
+
|
135
|
+
def upgrade_plugins
|
136
|
+
@plugins[:PluginLoader].plugin.extras_upgrade
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
# Loads and initializes plugins
|
142
|
+
def load_plugins
|
143
|
+
@pipeline << Messages::Internal::TimerClear.new
|
144
|
+
Models::Signature.set(:enabled => false)
|
145
|
+
[BotConfig[:pluginpath], BotConfig[:userpluginpath]].each do |path|
|
146
|
+
Dir.new(path).each do |file|
|
147
|
+
if(file =~ /^[^\.].+\.rb$/)
|
148
|
+
begin
|
149
|
+
do_load("#{path}/#{file}")
|
150
|
+
rescue Object => boom
|
151
|
+
Logger.warn("Failed to load file: #{path}/#{file}. Reason: #{boom}")
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
@pipeline << Messages::Internal::SignaturesUpdate.new
|
157
|
+
@pipeline << Messages::Internal::PluginsReady.new
|
158
|
+
end
|
159
|
+
|
160
|
+
# Destroys plugins
|
161
|
+
def unload_plugins
|
162
|
+
@plugins.each_pair do |sym, holder|
|
163
|
+
begin
|
164
|
+
holder.plugin.destroy unless holder.plugin.nil?
|
165
|
+
@pipeline.unhook_plugin(holder.plugin)
|
166
|
+
rescue Object => boom
|
167
|
+
Logger.warn("Plugin destruction error: #{boom}")
|
168
|
+
end
|
169
|
+
end
|
170
|
+
@plugins_module = Module.new
|
171
|
+
@pipeline << Messages::Internal::TimerClear.new
|
172
|
+
end
|
173
|
+
|
174
|
+
# path:: path to plugin file
|
175
|
+
# Loads a plugin into the plugin module
|
176
|
+
def do_load(path)
|
177
|
+
if(File.exists?(path))
|
178
|
+
plugins = discover_plugins(path)
|
179
|
+
raise PluginMissing.new("Plugin file at: #{path} does not contain a plugin class") if plugins.nil?
|
180
|
+
@plugins_module.module_eval(IO.readlines(path).join("\n"))
|
181
|
+
begin
|
182
|
+
plugins.each do |plugin|
|
183
|
+
klass = @plugins_module.const_get(plugin)
|
184
|
+
if(@plugins.has_key?(plugin.to_sym))
|
185
|
+
@plugins[plugin.to_sym].set_plugin(klass.new({:pipeline => @pipeline, :plugin_module => @plugins_module}))
|
186
|
+
else
|
187
|
+
@plugins[plugin.to_sym] = PluginHolder.new(klass.new({:pipeline => @pipeline, :plugin_module => @plugins_module}))
|
188
|
+
end
|
189
|
+
Logger.info("Properly initialized new plugin: #{plugin}")
|
190
|
+
Database.reset_connections
|
191
|
+
end
|
192
|
+
Logger.info("All plugins found at: #{path} have been loaded")
|
193
|
+
rescue Object => boom
|
194
|
+
Logger.warn("Plugin loading failed: #{boom}\n#{boom.backtrace.join("\n")}")
|
195
|
+
Logger.warn("All constants loaded from file: #{path} will now be unloaded")
|
196
|
+
do_unload(path)
|
197
|
+
end
|
198
|
+
else
|
199
|
+
raise PluginFileNotFound.new("Failed to find file at: #{path}")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# path:: path to plugin file
|
204
|
+
# Unloads a plugin and all constants from the plugin module
|
205
|
+
def do_unload(path)
|
206
|
+
if(File.exists?(path))
|
207
|
+
discover_plugins(path).each do |plugin|
|
208
|
+
if(@plugins.has_key?(plugin.to_sym))
|
209
|
+
@plugins[plugin.to_sym].plugin.destroy unless @plugins[plugin.to_sym].plugin.nil?
|
210
|
+
@pipeline.unhook_plugin(@plugins[plugin.to_sym].plugin)
|
211
|
+
@plugins[plugin.to_sym].set_plugin(nil)
|
212
|
+
@pipeline << Messages::Internal::TimerClear.new(plugin.to_sym)
|
213
|
+
end
|
214
|
+
Models::Signature.filter(:plugin => plugin.to_s).destroy
|
215
|
+
end
|
216
|
+
discover_consts(path).each do |const|
|
217
|
+
Logger.info("Removing constant: #{const}")
|
218
|
+
@plugins_module.send(:remove_const, const)
|
219
|
+
end
|
220
|
+
Logger.info("Removed all constants found in file: #{path}")
|
221
|
+
else
|
222
|
+
raise PluginFileNotFound.new("Failed to find file at: #{path}")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# path:: path to plugin
|
227
|
+
# Find class names of any plugins within the file at given path
|
228
|
+
def discover_plugins(path)
|
229
|
+
temp = Module.new
|
230
|
+
begin
|
231
|
+
temp.module_eval(IO.readlines(path).join("\n"))
|
232
|
+
klasses = []
|
233
|
+
temp.constants.each do |const|
|
234
|
+
klass = temp.const_get(const)
|
235
|
+
klasses << const if klass < Plugin
|
236
|
+
end
|
237
|
+
return klasses
|
238
|
+
rescue Object => boom
|
239
|
+
return nil
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# path:: path to plugin
|
244
|
+
# Find all constant names in given path
|
245
|
+
def discover_consts(path)
|
246
|
+
temp = Module.new
|
247
|
+
begin
|
248
|
+
temp.module_eval(IO.readlines(path).join("\n"))
|
249
|
+
return temp.constants
|
250
|
+
rescue Object => boom
|
251
|
+
return nil
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
@@ -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
|