mod_spox 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/CHANGELOG +31 -1
  2. data/LICENSE +674 -0
  3. data/README.rdoc +73 -0
  4. data/bin/mod_spox +28 -28
  5. data/data/mod_spox/extras/AOLSpeak.rb +2 -3
  6. data/data/mod_spox/extras/AutoKick.rb +10 -23
  7. data/data/mod_spox/extras/AutoMode.rb +12 -23
  8. data/data/mod_spox/extras/Bash.rb +55 -0
  9. data/data/mod_spox/extras/Bouncer.rb +85 -57
  10. data/data/mod_spox/extras/Bullshit.rb +1 -1
  11. data/data/mod_spox/extras/Bytes.rb +1 -2
  12. data/data/mod_spox/extras/Confess.rb +27 -29
  13. data/data/mod_spox/extras/DCC.rb +11 -20
  14. data/data/mod_spox/extras/DevWatch.rb +21 -23
  15. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  16. data/data/mod_spox/extras/EightBall.rb +1 -1
  17. data/data/mod_spox/extras/FML.rb +35 -0
  18. data/data/mod_spox/extras/Headers.rb +31 -50
  19. data/data/mod_spox/extras/Karma.rb +81 -29
  20. data/data/mod_spox/extras/Logger.rb +2 -2
  21. data/data/mod_spox/extras/LolSpeak.rb +1 -2
  22. data/data/mod_spox/extras/PhpCli.rb +138 -8
  23. data/data/mod_spox/extras/PhpFuncLookup.rb +20 -23
  24. data/data/mod_spox/extras/Pinger.rb +1 -1
  25. data/data/mod_spox/extras/Quotes.rb +8 -10
  26. data/data/mod_spox/extras/RegexTracker.rb +2 -4
  27. data/data/mod_spox/extras/Roulette.rb +20 -27
  28. data/data/mod_spox/extras/RubyCli.rb +93 -0
  29. data/data/mod_spox/extras/Search.rb +17 -3
  30. data/data/mod_spox/extras/Seen.rb +150 -0
  31. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  32. data/data/mod_spox/extras/Talk.rb +2 -4
  33. data/data/mod_spox/extras/Topten.rb +10 -12
  34. data/data/mod_spox/extras/TracTicket.rb +3 -5
  35. data/data/mod_spox/extras/Translate.rb +20 -22
  36. data/data/mod_spox/extras/Twitter.rb +118 -33
  37. data/data/mod_spox/extras/UrbanDictionary.rb +8 -17
  38. data/data/mod_spox/extras/Weather.rb +1 -2
  39. data/data/mod_spox/plugins/Authenticator.rb +93 -98
  40. data/data/mod_spox/plugins/Banner.rb +26 -56
  41. data/data/mod_spox/plugins/Helper.rb +5 -6
  42. data/data/mod_spox/plugins/Initializer.rb +4 -14
  43. data/data/mod_spox/plugins/Joiner.rb +1 -1
  44. data/data/mod_spox/plugins/Nicker.rb +13 -0
  45. data/data/mod_spox/plugins/Parter.rb +2 -2
  46. data/data/mod_spox/plugins/Permissions.rb +60 -0
  47. data/data/mod_spox/plugins/PluginLoader.rb +7 -12
  48. data/data/mod_spox/plugins/Ponger.rb +51 -0
  49. data/data/mod_spox/plugins/Quitter.rb +1 -2
  50. data/data/mod_spox/plugins/Servers.rb +57 -0
  51. data/data/mod_spox/plugins/Status.rb +3 -2
  52. data/data/mod_spox/plugins/Triggers.rb +9 -9
  53. data/lib/mod_spox/Bot.rb +109 -33
  54. data/lib/mod_spox/BotConfig.rb +2 -2
  55. data/lib/mod_spox/ConfigurationWizard.rb +12 -12
  56. data/lib/mod_spox/Database.rb +1 -4
  57. data/lib/mod_spox/Exceptions.rb +26 -0
  58. data/lib/mod_spox/Helpers.rb +29 -68
  59. data/lib/mod_spox/Loader.rb +23 -24
  60. data/lib/mod_spox/Logger.rb +19 -17
  61. data/lib/mod_spox/MessageFactory.rb +50 -24
  62. data/lib/mod_spox/Pipeline.rb +21 -7
  63. data/lib/mod_spox/Plugin.rb +27 -3
  64. data/lib/mod_spox/PluginManager.rb +28 -15
  65. data/lib/mod_spox/PriorityQueue.rb +69 -0
  66. data/lib/mod_spox/Socket.rb +93 -51
  67. data/lib/mod_spox/Sockets.rb +76 -63
  68. data/lib/mod_spox/Timer.rb +21 -141
  69. data/lib/mod_spox/Version.rb +14 -0
  70. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  71. data/lib/mod_spox/handlers/Bounce.rb +5 -5
  72. data/lib/mod_spox/handlers/Created.rb +13 -5
  73. data/lib/mod_spox/handlers/Handler.rb +12 -3
  74. data/lib/mod_spox/handlers/Invite.rb +14 -8
  75. data/lib/mod_spox/handlers/Join.rb +24 -20
  76. data/lib/mod_spox/handlers/Kick.rb +22 -13
  77. data/lib/mod_spox/handlers/Mode.rb +42 -36
  78. data/lib/mod_spox/handlers/Motd.rb +4 -0
  79. data/lib/mod_spox/handlers/Names.rb +66 -39
  80. data/lib/mod_spox/handlers/Nick.rb +20 -14
  81. data/lib/mod_spox/handlers/Part.rb +25 -8
  82. data/lib/mod_spox/handlers/Ping.rb +11 -5
  83. data/lib/mod_spox/handlers/Pong.rb +9 -5
  84. data/lib/mod_spox/handlers/Privmsg.rb +25 -17
  85. data/lib/mod_spox/handlers/Quit.rb +13 -8
  86. data/lib/mod_spox/handlers/Topic.rb +4 -0
  87. data/lib/mod_spox/handlers/Welcome.rb +16 -24
  88. data/lib/mod_spox/handlers/Who.rb +64 -48
  89. data/lib/mod_spox/handlers/Whois.rb +92 -60
  90. data/lib/mod_spox/messages/incoming/Nick.rb +2 -2
  91. data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -1
  92. data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
  93. data/lib/mod_spox/messages/internal/EstablishConnection.rb +1 -1
  94. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  95. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  96. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  97. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  98. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  99. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  100. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  101. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  102. data/lib/mod_spox/models/Auth.rb +16 -46
  103. data/lib/mod_spox/models/AuthMask.rb +13 -0
  104. data/lib/mod_spox/models/Channel.rb +46 -27
  105. data/lib/mod_spox/models/Config.rb +10 -19
  106. data/lib/mod_spox/models/Group.rb +20 -8
  107. data/lib/mod_spox/models/Models.rb +1 -1
  108. data/lib/mod_spox/models/Nick.rb +105 -113
  109. data/lib/mod_spox/models/NickMode.rb +23 -9
  110. data/lib/mod_spox/models/Server.rb +12 -1
  111. data/lib/mod_spox/models/Setting.rb +12 -16
  112. data/lib/mod_spox/models/Signature.rb +28 -8
  113. data/tests/BotHolder.rb +24 -0
  114. data/tests/handlers/tc_BadNick.rb +21 -0
  115. data/tests/handlers/tc_Created.rb +24 -0
  116. data/tests/handlers/tc_Invite.rb +50 -0
  117. data/tests/handlers/tc_Join.rb +33 -0
  118. data/tests/handlers/tc_Kick.rb +32 -0
  119. data/tests/handlers/tc_Mode.rb +85 -0
  120. data/tests/handlers/tc_Names.rb +35 -0
  121. data/tests/handlers/tc_Nick.rb +55 -0
  122. data/tests/handlers/tc_Part.rb +44 -0
  123. data/tests/handlers/tc_Ping.rb +40 -0
  124. data/tests/handlers/tc_Pong.rb +28 -0
  125. data/tests/handlers/tc_Privmsg.rb +85 -0
  126. data/tests/handlers/tc_Quit.rb +40 -0
  127. data/tests/handlers/tc_Who.rb +50 -0
  128. data/tests/handlers/tc_Whois.rb +61 -0
  129. data/tests/models/tc_Auth.rb +34 -0
  130. data/tests/models/tc_Channel.rb +52 -0
  131. data/tests/models/tc_Config.rb +19 -0
  132. data/tests/models/tc_Nick.rb +142 -0
  133. data/tests/models/tc_NickMode.rb +40 -0
  134. data/tests/models/tc_Setting.rb +21 -0
  135. data/tests/models/tc_Signature.rb +14 -0
  136. data/tests/run_tests.rb +4 -0
  137. metadata +284 -212
  138. data/README +0 -36
  139. data/lib/mod_spox/Cache.rb +0 -57
  140. data/lib/mod_spox/Monitors.rb +0 -84
  141. data/lib/mod_spox/Pool.rb +0 -164
  142. data/lib/mod_spox/models/AuthGroup.rb +0 -16
  143. data/lib/mod_spox/models/ChannelMode.rb +0 -14
  144. data/lib/mod_spox/models/NickChannel.rb +0 -45
  145. data/lib/mod_spox/models/NickGroup.rb +0 -16
@@ -20,11 +20,11 @@ module ModSpox
20
20
  # :userconfigpath => path to the user configuration file
21
21
  def BotConfig.populate(createdir=true)
22
22
  gemname, gem = Gem.source_index.find{|name, spec|
23
- spec.name == 'mod_spox' && spec.version.version = $BOTVERSION
23
+ spec.name == 'mod_spox' && spec.version.version = ModSpox.botversion
24
24
  }
25
25
  if(gem)
26
26
  p = gem.full_gem_path
27
- up = $MOD_SPOX_PATH.nil? ? Etc.getpwnam(Etc.getlogin).dir : $MOD_SPOX_PATH
27
+ up = ModSpox.mod_spox_path.nil? ? Etc.getpwnam(Etc.getlogin).dir : ModSpox.mod_spox.path
28
28
  @@config = {:basepath => p,
29
29
  :libpath => "#{p}/lib/mod_spox",
30
30
  :datapath => "#{p}/data/mod_spox",
@@ -44,7 +44,7 @@ module ModSpox
44
44
  config[:memcache] = get_input('Use memcache (EXPERIMENTAL): ', '(yes|no)', 'no')
45
45
  valid_connection = false
46
46
  until valid_connection do
47
- config[:db_adapter] = get_input('Database type (pgsql): ', '(pgsql)', 'pgsql')
47
+ config[:db_adapter] = get_input('Database type (pgsql|sqlite|mysql): ', '(pgsql|sqlite|mysql)', 'sqlite')
48
48
  unless(config[:db_adapter] == 'sqlite')
49
49
  config[:db_username] = get_input('Database username: ', '.+', 'mod_spox')
50
50
  config[:db_password] = get_input('Database password: ', '.*', nil)
@@ -63,8 +63,7 @@ module ModSpox
63
63
  rescue Object => boom
64
64
  puts 'Failed'
65
65
  puts 'Error: Unexpected error encountered.'
66
- puts "Info: #{boom.class} #{boom}\n#{boom.backtrace.join("\n")}"
67
- exit 1
66
+ puts "Info: #{boom}"
68
67
  ensure
69
68
  $stdout.flush
70
69
  end
@@ -76,7 +75,7 @@ module ModSpox
76
75
  puts 'mod_spox is now configured and ready for use'
77
76
  rescue Object => boom
78
77
  puts 'Failed'
79
- puts "Error: #{boom}\n#{boom.backtrace.join("\n")}"
78
+ puts "Error: #{boom}"
80
79
  puts 'Please try running the configuration again'
81
80
  end
82
81
  end
@@ -89,11 +88,11 @@ module ModSpox
89
88
 
90
89
  def test_connection(type, username=nil, password=nil, host=nil, name=nil)
91
90
  case type
92
- # when 'mysql'
93
- # c = Sequel.mysql(name, :user => username, :password => password, :host => host)
94
- # c.test_connection
91
+ when 'mysql'
92
+ c = Sequel.mysql(name, :user => username, :password => password, :host => host)
93
+ c.test_connection
95
94
  when 'pgsql'
96
- c = Sequel.connect("#{$JDBC ? 'jdbc:' : ''}postgres://#{username}:#{password}@#{host}/#{name}")
95
+ c = Sequel.connect("#{ModSpox.jdbc ? 'jdbc:' : ''}postgres://#{username}:#{password}@#{host}/#{name}")
97
96
  c.test_connection
98
97
  when 'sqlite'
99
98
  return true
@@ -107,7 +106,7 @@ module ModSpox
107
106
  config[key] = value if key.to_s =~ /^(db|memcache)/
108
107
  end
109
108
  config.write_configuration
110
- initialize_bot
109
+ ModSpox.initialize_bot
111
110
  require 'mod_spox/models/Models'
112
111
  require 'mod_spox/Helpers'
113
112
  Sequel::Migrator.apply(Database.db, BotConfig[:libpath] + '/migrations')
@@ -121,11 +120,12 @@ module ModSpox
121
120
  s = Models::Server.find_or_create(:host => uconfig[:irc_server], :port => uconfig[:irc_port])
122
121
  n = Models::Nick.find_or_create(:nick => uconfig[:admin_nick])
123
122
  a = Models::Auth.find_or_create(:nick_id => n.pk)
124
- a.group = Models::Group.find_or_create(:name => 'admin')
123
+ g = Models::Group.find_or_create(:name => 'admin')
124
+ a.add_group(g)
125
125
  a.password = uconfig[:admin_password]
126
126
  a.save
127
127
  t = Models::Trigger.find_or_create(:trigger => uconfig[:trigger])
128
- t.update_with_params(:active => true)
128
+ t.active = true
129
129
  t.save
130
130
  end
131
131
 
@@ -177,4 +177,4 @@ module ModSpox
177
177
 
178
178
  end
179
179
 
180
- end
180
+ end
@@ -30,10 +30,7 @@ module ModSpox
30
30
  end
31
31
 
32
32
  def Database.reset_connections
33
- Logger.warn('Resetting database connections. Any active connections are being closed.')
34
- Database.db.pool.allocated.each_pair do |thread, connection|
35
- thread.kill
36
- end
33
+ @@db.disconnect
37
34
  end
38
35
 
39
36
  def Database.reconnect
@@ -30,6 +30,32 @@ module ModSpox
30
30
 
31
31
  class TimerInUse < BotException
32
32
  end
33
+
34
+ class EmptyQueue < BotException
35
+ end
36
+
37
+ class Disconnected < BotException
38
+ end
39
+
40
+ class NotInChannel < BotException
41
+ attr_reader :channel
42
+ def initialize(channel)
43
+ @channel = channel
44
+ end
45
+ def to_s
46
+ "Bot is not currently in channel: #{@channel}"
47
+ end
48
+ end
49
+
50
+ class QuietChannel < BotException
51
+ attr_reader :channel
52
+ def initialize(channel)
53
+ @channel = channel
54
+ end
55
+ def to_s
56
+ "Bot is not allowed to speak in channel: #{@channel}"
57
+ end
58
+ end
33
59
 
34
60
  end
35
61
  end
@@ -3,7 +3,7 @@
3
3
  'mod_spox/models/Nick',
4
4
  'mod_spox/models/Channel',
5
5
  'mod_spox/models/Server',
6
- 'mod_spox/Cache',
6
+ 'mod_spox/models/Models',
7
7
  'mod_spox/Logger'].each{|f|require f}
8
8
 
9
9
  module ModSpox
@@ -33,20 +33,20 @@ module ModSpox
33
33
  # Converts bytes into easy human readable form
34
34
  # O(1) version by Ryan "pizza_milkshake" Flynn
35
35
  Suff = [
36
- "", # 1000^0
37
- "Kilo", # 1000^1
38
- "Mega", # 1000^2
39
- "Giga", # 1000^3
40
- "Tera", # 1000^4
41
- "Peta", # 1000^5
42
- "Exa", # 1000^6
43
- "Zetta", # 1000^7
44
- "Yotta" # 1000^8
36
+ "", # 1024^0
37
+ "Kilo", # 1024^1
38
+ "Mega", # 1024^2
39
+ "Giga", # 1024^3
40
+ "Tera", # 1024^4
41
+ "Peta", # 1024^5
42
+ "Exa", # 1024^6
43
+ "Zetta", # 1024^7
44
+ "Yotta" # 1024^8
45
45
  ]
46
46
  def Helpers.format_size(bytes)
47
- mag = (Math.log(bytes) / Math.log(1000)).floor
47
+ mag = (Math.log(bytes) / Math.log(1024)).floor
48
48
  mag = [ Suff.length - 1, mag ].min
49
- val = bytes.to_f / (1000 ** mag)
49
+ val = bytes.to_f / (1024 ** mag)
50
50
  "%7.3f %sbyte%s" % [ val, Suff[mag], val == 1 ? "" : "s" ]
51
51
  end
52
52
 
@@ -87,68 +87,29 @@ module ModSpox
87
87
  # or channel name. If the string given does not match the required
88
88
  # pattern for a channel or nick, the string is returned.
89
89
  def Helpers.find_model(string, create=true)
90
- Helpers.initialize_caches
90
+ result = nil
91
91
  if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
92
- nick = nil
93
- if(@@nick_cache.has_key?(string.downcase.to_sym))
94
- begin
95
- nick = Models::Nick[@@nick_cache[string.downcase.to_sym]]
96
- if(nick.nick.downcase != string.downcase)
97
- Logger.warn("Nick returned from cache invalid. Expecting #{string} but got #{nick.nick}")
98
- nick = nil
99
- end
100
- rescue Object => boom
101
- Logger.info("Failed to grab cached nick: #{boom}")
102
- end
103
- end
104
- unless(nick)
105
- begin
106
- nick = Models::Nick.locate(string, create)
107
- if(nick.nil?)
108
- Database.reconnect
109
- return string
110
- end
111
- rescue Object => boom
112
- Logger.warn("Caught an error. Assuming the database barfed: #{boom}")
113
- Database.reconnect
114
- end
115
- @@nick_cache[string.downcase.to_sym] = nick.pk if nick.is_a?(Models::Nick)
116
- Logger.info('Nick was retrieved from database')
117
- end
118
- return nick
119
- elsif(string =~ /^[&#+!]/)
120
- if(@@channel_cache.has_key?(string.downcase.to_sym))
121
- begin
122
- channel = Models::Channel[@@channel_cache[string.downcase.to_sym]]
123
- if(string.downcase != channel.name.downcase)
124
- Logger.warn("Channel returned from cache invalid. Expecting #{string} but got #{channel.name}")
125
- channel = nil
126
- end
127
- rescue Object => boom
128
- Logger.info("Failed to grab cached channel: #{boom}")
129
- end
130
- end
131
- unless(channel)
132
- channel = Models::Channel.locate(string, create)
133
- if(channel.nil?)
134
- Database.reconnect
135
- return string
136
- end
137
- @@channel_cache[string.downcase.to_sym] = channel.pk if channel.is_a?(Models::Channel)
138
- Logger.info('Channel was retrieved from database')
139
- end
140
- return channel
141
- elsif(model = Models::Server.filter(:host => string, :connected => true).first)
142
- return model
92
+ result = Models::Nick.find_or_create(:nick => string.downcase)
93
+ elsif(['&', '#', '+', '!'].include?(string[0]))
94
+ result = Models::Channel.find_or_create(:name => string.downcase)
95
+ elsif(Models::Server.filter(:host => string, :connected => true).count > 0)
96
+ result = Models::Server.filter(:host => string, :connected => true).first
143
97
  else
144
98
  Logger.warn("Failed to match string to model: #{string} -> No match")
145
- return string
146
99
  end
100
+ return result
147
101
  end
148
102
 
149
- def Helpers.initialize_caches
150
- @@nick_cache = Cache.new(20) unless Helpers.class_variable_defined?(:@@nick_cache)
151
- @@channel_cache = Cache.new(5) unless Helpers.class_variable_defined?(:@@channel_cache)
103
+ # string:: string to convert
104
+ # Converts HTML entities found in a string
105
+ def Helpers.convert_entities(string)
106
+ begin
107
+ require 'htmlentities'
108
+ @@coder = HTMLEntities.new unless Helpers.class_variable_defined?(:@@coder)
109
+ return @@coder.decode(string)
110
+ rescue Object
111
+ return string
112
+ end
152
113
  end
153
114
  end
154
115
  end
@@ -7,13 +7,13 @@
7
7
  module ModSpox
8
8
 
9
9
  # Loads all files needed by the bot
10
- def initialize_bot
11
- setup_adapter
10
+ def self.initialize_bot(db=nil)
11
+ setup_adapter(db)
12
12
  check_upgrade
13
13
  end
14
14
 
15
15
  # Setup the DataMapper adapter
16
- def setup_adapter
16
+ def self.setup_adapter(db=nil)
17
17
  memcache = false
18
18
  config = BaseConfig.new(BotConfig[:userconfigpath])
19
19
  if(config[:memcache] == 'on')
@@ -26,36 +26,35 @@ module ModSpox
26
26
  # do nothing #
27
27
  end
28
28
  end
29
- case config[:db_adapter]
30
- when 'mysql'
31
- Database.db = Sequel.mysql(config[:db_database], :user => config[:db_username],
32
- :password => config[:db_password], :host => config[:db_host], :max_connections => 20)
33
- Database.type = :mysql
34
- when 'pgsql'
35
- Database.db = Sequel.connect("#{$JDBC ? 'jdbc:' : ''}postgres://#{config[:db_username]}:#{config[:db_password]}@#{config[:db_host]}/#{config[:db_database]}")
36
- Database.type = :pgsql
37
- when 'sqlite'
38
- Database.db = Sequel.sqlite("#{BotConfig[:userpath]}/mod_spox.db")
39
- Database.type = :sqlite
29
+ unless(db.nil?)
30
+ Database.db = db
31
+ else
32
+ case config[:db_adapter]
33
+ when 'mysql'
34
+ Database.db = Sequel.mysql(config[:db_database], :user => config[:db_username],
35
+ :password => config[:db_password], :host => config[:db_host], :max_connections => 20)
36
+ Database.type = :mysql
37
+ when 'pgsql'
38
+ Database.db = Sequel.connect("#{ModSpox.jdbc ? 'jdbc:' : ''}postgres://#{config[:db_username]}:#{config[:db_password]}@#{config[:db_host]}/#{config[:db_database]}")
39
+ Database.type = :pgsql
40
+ when 'sqlite'
41
+ Database.db = Sequel.sqlite("#{BotConfig[:userpath]}/mod_spox.db", :pool_timeout => 20, :timeout => 5000)
42
+ Database.type = :sqlite
43
+ end
40
44
  end
41
45
  end
42
46
 
43
47
  # check if the bot has been upgraded
44
- def check_upgrade
48
+ def self.check_upgrade
49
+ Sequel::Migrator.apply(Database.db, BotConfig[:libpath] + '/migrations')
45
50
  config = BaseConfig.new(BotConfig[:userconfigpath])
46
51
  config[:plugin_upgrade] = 'no'
47
52
  begin
48
- do_upgrade(config) if config[:last_version] != $BOTVERSION
53
+ config[:plugin_upgrade] = 'yes' if config[:last_version] != ModSpox.botversion
49
54
  rescue Exceptions::UnknownKey => boom
50
- do_upgrade(config)
55
+ config[:plugin_upgrade] = 'yes'
51
56
  end
52
- config[:last_version] = $BOTVERSION
53
- end
54
-
55
- # perform upgrade tasks
56
- def do_upgrade(config)
57
- Sequel::Migrator.apply(Database.db, BotConfig[:libpath] + '/migrations')
58
- config[:plugin_upgrade] = 'yes'
57
+ config[:last_version] = ModSpox.botversion
59
58
  end
60
59
 
61
60
  end
@@ -3,32 +3,34 @@ module ModSpox
3
3
 
4
4
  class Logger
5
5
 
6
- def Logger.initialize(output=nil, level=:fatal)
7
- if(output.nil?)
8
- @@log = nil
9
- else
10
- levels = {:info => Object::Logger::INFO, :warn => Object::Logger::WARN, :fatal => Object::Logger::FATAL}
11
- @@log = Object::Logger.new(output)
12
- @@log.level = levels.has_key?(level) ? levels[level] : Object::Logger::WARN
13
- end
6
+ def Logger.initialize(logger, level)
7
+ l = {:info => ::Logger::INFO, :error => ::Logger::ERROR, :warn => ::Logger::WARN, :fatal => ::Logger::FATAL}
8
+ @@log = logger.is_a?(::Logger) ? logger : nil
9
+ @@log.level = l[level]
14
10
  end
15
11
 
16
12
  def Logger.warn(s)
17
- unless @@log.nil?
18
- Pool << lambda{@@log.warn(s)}
19
- end
13
+ @@log.warn(s) if Logger.log?
20
14
  end
21
15
 
22
16
  def Logger.info(s)
23
- unless @@log.nil?
24
- Pool << lambda{@@log.info(s)}
25
- end
17
+ @@log.info(s) if Logger.log?
26
18
  end
27
19
 
28
20
  def Logger.fatal(s)
29
- unless @@log.nil?
30
- Pool << lambda{@@log.fatal(s)}
31
- end
21
+ @@log.fatal(s) if Logger.log?
22
+ end
23
+
24
+ def Logger.error(s)
25
+ @@log.error(s) if Logger.log?
26
+ end
27
+
28
+ def Logger.log?
29
+ Logger.class_variable_defined?(:@@log)
30
+ end
31
+
32
+ def Logger.raw
33
+ Logger.log? ? @@log : nil
32
34
  end
33
35
 
34
36
  end
@@ -1,18 +1,21 @@
1
1
  ['mod_spox/handlers/Handler',
2
2
  'mod_spox/Logger',
3
- 'mod_spox/Pipeline',
4
- 'mod_spox/Pool'].each{|f|require f}
3
+ 'mod_spox/Pipeline'].each{|f|require f}
5
4
 
6
5
  module ModSpox
7
6
 
8
7
  class MessageFactory
9
8
 
9
+ # access to handlers. (only really needed for testing)
10
+ attr_reader :handlers
11
+
10
12
  # pipeline:: Message pipeline
11
13
  # Create a new MessageFactory
12
- def initialize(pipeline)
14
+ def initialize(pipeline, pool)
13
15
  @pipeline = pipeline
16
+ @pool = pool
17
+ @sync_pool = ActionPool::Pool.new(1, 1, nil, 2, Logger.raw)
14
18
  @handlers = Hash.new
15
- @lock = Mutex.new
16
19
  build_handlers
17
20
  @sync = [RPL_MOTDSTART, RPL_MOTD, RPL_ENDOFMOTD, RPL_WHOREPLY, RPL_ENDOFWHO,
18
21
  RPL_NAMREPLY, RPL_ENDOFNAMES, RPL_WHOISUSER, RPL_WHOISSERVER, RPL_WHOISOPERATOR,
@@ -24,7 +27,28 @@ module ModSpox
24
27
  # be processed thus there is now wait for processing to be
25
28
  # completed.
26
29
  def <<(string)
27
- Pool << lambda{ parse_message(string) }
30
+ @pool.process{ parse_message(string) }
31
+ end
32
+
33
+ # s:: string from server
34
+ # determine type of message from server
35
+ def find_key(s)
36
+ s = s.dup
37
+ begin
38
+ key = nil
39
+ if(s[0].chr == ':')
40
+ s.slice!(0..s.index(' '))
41
+ key = s.slice!(0..s.index(' ')-1)
42
+ else
43
+ key = s.slice(0..s.index(' ')-1)
44
+ end
45
+ key.strip!
46
+ key = key.to_sym if key.to_i == 0
47
+ return key
48
+ rescue Object
49
+ Logger.info("Failed to find key for message: #{s}")
50
+ raise Exceptions::UnknownKey.new
51
+ end
28
52
  end
29
53
 
30
54
  private
@@ -55,29 +79,31 @@ module ModSpox
55
79
  def parse_message(message)
56
80
  Logger.info("Processing message: #{message}")
57
81
  begin
58
- if(message =~ /^:\S+ (\S+)/ || message =~ /^([A-Za-z0-9]+)\s/)
59
- key = $1
60
- key = key.to_sym unless key[0].chr =~ /\d/
61
- if(@handlers.has_key?(key))
62
- Logger.info("Message of type #{key} is now being handled by #{@handlers[key]}")
63
- if(@sync.include?(key))
64
- Logger.info("Message of type #{key} requires synchronized processing")
65
- Pool << lambda do
66
- @lock.synchronize do
67
- message = @handlers[key].process(message)
68
- @pipeline << message unless message.nil?
69
- end
70
- end
71
- else
72
- Pool << lambda do
73
- message = @handlers[key].process(message)
74
- @pipeline << message unless message.nil?
75
- end
82
+ key = find_key(message)
83
+ if(@handlers.has_key?(key))
84
+ Logger.info("Message of type #{key} is now being handled by #{@handlers[key]}")
85
+ if(@sync.include?(key))
86
+ Logger.info("Message of type #{key} requires synchronized processing")
87
+ @sync_pool.process do
88
+ message = @handlers[key].process(message)
89
+ @pipeline << message unless message.nil?
90
+ end
91
+ else
92
+ @pool.process do
93
+ message = @handlers[key].process(message)
94
+ @pipeline << message unless message.nil?
76
95
  end
77
96
  end
97
+ else
98
+ Logger.error("No handler was found to process message of type: #{key} Message: #{message}")
78
99
  end
79
100
  rescue Object => boom
80
- Logger.warn("Failed to parse message from server: #{boom}\n#{boom.backtrace.join("\n")}")
101
+ if(boom.class.to_s == 'SQLite3::BusyException' || boom.class.to_s == 'PGError')
102
+ Database.reset_connections
103
+ retry
104
+ else
105
+ Logger.warn("Failed to parse message from server: #{boom}\n#{boom.backtrace.join("\n")}")
106
+ end
81
107
  end
82
108
  end
83
109