mod_spox 0.1.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGELOG +36 -0
  2. data/INSTALL +2 -2
  3. data/README +0 -1
  4. data/bin/mod_spox +51 -12
  5. data/data/mod_spox/extras/AOLSpeak.rb +5 -18
  6. data/data/mod_spox/extras/AutoKick.rb +44 -23
  7. data/data/mod_spox/extras/AutoMode.rb +2 -5
  8. data/data/mod_spox/extras/AutoRejoin.rb +21 -0
  9. data/data/mod_spox/extras/Bouncer.rb +10 -10
  10. data/data/mod_spox/extras/Bytes.rb +12 -0
  11. data/data/mod_spox/extras/Confess.rb +131 -52
  12. data/data/mod_spox/extras/DCC.rb +189 -0
  13. data/data/mod_spox/extras/DevWatch.rb +32 -33
  14. data/data/mod_spox/extras/FloodKicker.rb +129 -0
  15. data/data/mod_spox/extras/GoogleIt.rb +13 -0
  16. data/data/mod_spox/extras/Headers.rb +31 -4
  17. data/data/mod_spox/extras/Karma.rb +103 -49
  18. data/data/mod_spox/extras/Logger.rb +45 -30
  19. data/data/mod_spox/extras/LolSpeak.rb +1 -1
  20. data/data/mod_spox/extras/NickServ.rb +83 -0
  21. data/data/mod_spox/extras/PhpCli.rb +12 -15
  22. data/data/mod_spox/extras/PhpFuncLookup.rb +57 -25
  23. data/data/mod_spox/extras/Quotes.rb +5 -4
  24. data/data/mod_spox/extras/RegexTracker.rb +160 -0
  25. data/data/mod_spox/extras/Roulette.rb +22 -23
  26. data/data/mod_spox/extras/Search.rb +3 -2
  27. data/data/mod_spox/extras/Slashdot.rb +35 -0
  28. data/data/mod_spox/extras/Topten.rb +5 -5
  29. data/data/mod_spox/extras/TracTicket.rb +68 -0
  30. data/data/mod_spox/extras/Translate.rb +69 -30
  31. data/data/mod_spox/extras/Twitter.rb +372 -0
  32. data/data/mod_spox/extras/UrbanDictionary.rb +21 -12
  33. data/data/mod_spox/extras/Weather.rb +1 -1
  34. data/data/mod_spox/plugins/Authenticator.rb +63 -30
  35. data/data/mod_spox/plugins/Banner.rb +164 -151
  36. data/data/mod_spox/plugins/Helper.rb +18 -7
  37. data/data/mod_spox/plugins/PluginLoader.rb +46 -22
  38. data/data/mod_spox/plugins/PoolConfig.rb +52 -0
  39. data/data/mod_spox/plugins/Quitter.rb +1 -1
  40. data/data/mod_spox/plugins/Status.rb +28 -0
  41. data/lib/mod_spox/Action.rb +20 -3
  42. data/lib/mod_spox/BaseConfig.rb +1 -0
  43. data/lib/mod_spox/Bot.rb +98 -75
  44. data/lib/mod_spox/BotConfig.rb +14 -6
  45. data/lib/mod_spox/ConfigurationWizard.rb +94 -105
  46. data/lib/mod_spox/Database.rb +33 -13
  47. data/lib/mod_spox/Helpers.rb +67 -38
  48. data/lib/mod_spox/Loader.rb +25 -5
  49. data/lib/mod_spox/Logger.rb +20 -62
  50. data/lib/mod_spox/MessageFactory.rb +34 -25
  51. data/lib/mod_spox/Monitors.rb +5 -0
  52. data/lib/mod_spox/Pipeline.rb +40 -51
  53. data/lib/mod_spox/Plugin.rb +40 -9
  54. data/lib/mod_spox/PluginManager.rb +46 -38
  55. data/lib/mod_spox/Pool.rb +129 -143
  56. data/lib/mod_spox/Socket.rb +41 -50
  57. data/lib/mod_spox/Sockets.rb +211 -0
  58. data/lib/mod_spox/Timer.rb +86 -69
  59. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  60. data/lib/mod_spox/handlers/Created.rb +1 -1
  61. data/lib/mod_spox/handlers/Handler.rb +9 -0
  62. data/lib/mod_spox/handlers/Invite.rb +1 -1
  63. data/lib/mod_spox/handlers/Join.rb +2 -2
  64. data/lib/mod_spox/handlers/Kick.rb +1 -1
  65. data/lib/mod_spox/handlers/LuserChannels.rb +1 -1
  66. data/lib/mod_spox/handlers/LuserOp.rb +1 -1
  67. data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
  68. data/lib/mod_spox/handlers/Mode.rb +2 -2
  69. data/lib/mod_spox/handlers/MyInfo.rb +1 -1
  70. data/lib/mod_spox/handlers/Names.rb +1 -1
  71. data/lib/mod_spox/handlers/Nick.rb +20 -3
  72. data/lib/mod_spox/handlers/NickInUse.rb +3 -3
  73. data/lib/mod_spox/handlers/Notice.rb +5 -15
  74. data/lib/mod_spox/handlers/Part.rb +1 -1
  75. data/lib/mod_spox/handlers/Ping.rb +1 -1
  76. data/lib/mod_spox/handlers/Pong.rb +1 -1
  77. data/lib/mod_spox/handlers/Privmsg.rb +2 -2
  78. data/lib/mod_spox/handlers/Quit.rb +1 -1
  79. data/lib/mod_spox/handlers/Topic.rb +2 -1
  80. data/lib/mod_spox/handlers/Welcome.rb +3 -3
  81. data/lib/mod_spox/handlers/Who.rb +9 -7
  82. data/lib/mod_spox/handlers/Whois.rb +29 -16
  83. data/lib/mod_spox/handlers/YourHost.rb +1 -1
  84. data/lib/mod_spox/messages/incoming/Privmsg.rb +38 -19
  85. data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
  86. data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
  87. data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
  88. data/lib/mod_spox/messages/internal/StatusRequest.rb +2 -1
  89. data/lib/mod_spox/messages/outgoing/Privmsg.rb +21 -5
  90. data/lib/mod_spox/migrations/001_initialize_models.rb +115 -0
  91. data/lib/mod_spox/models/Auth.rb +24 -16
  92. data/lib/mod_spox/models/AuthGroup.rb +4 -3
  93. data/lib/mod_spox/models/Channel.rb +20 -12
  94. data/lib/mod_spox/models/ChannelMode.rb +2 -2
  95. data/lib/mod_spox/models/Config.rb +11 -3
  96. data/lib/mod_spox/models/Group.rb +6 -1
  97. data/lib/mod_spox/models/Nick.rb +93 -33
  98. data/lib/mod_spox/models/NickChannel.rb +8 -6
  99. data/lib/mod_spox/models/NickGroup.rb +16 -0
  100. data/lib/mod_spox/models/NickMode.rb +3 -3
  101. data/lib/mod_spox/models/Server.rb +6 -2
  102. data/lib/mod_spox/models/Setting.rb +12 -6
  103. data/lib/mod_spox/models/Signature.rb +7 -13
  104. data/lib/mod_spox/models/Trigger.rb +1 -1
  105. metadata +125 -100
@@ -11,26 +11,7 @@ module ModSpox
11
11
  def initialize
12
12
  @echo = nil
13
13
  @config = Array.new
14
- @config << {:id => :db_username, :string => 'Database username: ', :regex => '[a-zA-Z].*', :default => 'mod_spox', :value => nil, :echo => true}
15
- @config << {:id => :db_password, :string => 'Database password: ', :regex => '.*', :default => nil, :value => nil, :echo => false}
16
- @config << {:id => :db_host, :string => 'Database host: ', :regex => '.+', :default => 'localhost', :value => nil, :echo => true}
17
- @config << {:id => :db_database, :string => 'Database name: ', :regex => '.+', :default => 'mod_spox', :value => nil, :echo => true}
18
- @config << {:id => :db_adapter, :string => 'Database type (mysql|pgsql|sqlite): ', :regex => '(mysql|pgsql|sqlite)', :default => nil, :value => nil, :echo => true}
19
- @config << {:id => :irc_server, :string => 'IRC Server: ', :regex => '.+', :default => nil, :value => nil, :echo => true}
20
- @config << {:id => :irc_port, :string => 'IRC Port: ', :regex => '[0-9]+', :default => nil, :value => nil, :echo => true}
21
- @config << {:id => :reconnect_wait, :string => 'Reconnect wait time: ', :regex => '[0-9]+', :default => '10', :value => nil, :echo => true}
22
- @config << {:id => :bot_nick, :string => 'IRC Nick: ', :regex => '[a-zA-Z].*', :default => 'mod_spox', :value => nil, :echo => true}
23
- @config << {:id => :bot_password, :string => 'IRC Nick Password: ', :regex => '.*', :default => nil, :value => nil, :echo => false}
24
- @config << {:id => :bot_username, :string => 'IRC Username: ', :regex => '.+', :default => 'mod_spox', :value => nil, :echo => true}
25
- @config << {:id => :bot_realname, :string => 'IRC Real Name: ', :regex => '.+', :default => 'mod_spox IRC bot', :value => nil, :echo => true}
26
- @config << {:id => :socket_burst, :string => 'Socket burst rate (lines): ', :regex => '[0-9]+', :default => '3', :value => nil, :echo => true}
27
- @config << {:id => :socket_burst_in, :string => 'Socket burst time: ', :regex => '[0-9]+', :default => '2', :value => nil, :echo => true}
28
- @config << {:id => :socket_burst_delay, :string => 'Socket burst delay: ', :regex => '[0-9]+', :default => '2', :value => nil, :echo => true}
29
- @config << {:id => :admin_nick, :string => 'Administrator nick: ', :regex => '[a-zA-Z].*', :default => nil, :value => nil, :echo => true}
30
- @config << {:id => :admin_password, :string => 'Administrator password: ', :regex => '.+', :default => nil, :value => nil, :echo => false}
31
- @config << {:id => :plugin_directory, :string => 'Plugin directory (bot must have write priviliges): ', :regex => '.+', :default => nil, :echo => true}
32
- @config << {:id => :trigger, :string => 'Trigger character for plugins: ', :regex => '.', :default => '!', :value => nil, :echo => true}
33
- @config << {:id => :memcache, :string => 'Use memcache (EXPERIMENTAL): ', :regex => '(yes|no)', :default => 'no', :value => nil, :echo => true}
14
+ @config_db = Hash.new
34
15
  @stuck_visible = true
35
16
  begin
36
17
  require 'termios'
@@ -41,52 +22,109 @@ module ModSpox
41
22
 
42
23
  # Run the configuration wizard
43
24
  def run
25
+ config = {}
44
26
  puts "*********************************"
45
27
  puts "* mod_spox Configuration Wizard *"
46
28
  puts "*********************************"
47
29
  puts ""
48
- @config.each{|v|
49
- v[:value] = get_input(v[:string], v[:regex], v[:echo], v[:default])
50
- }
30
+ config[:irc_server] = get_input('IRC Server: ', '.+', nil)
31
+ config[:irc_port] = get_input('IRC Port: ', '\d+', '6667')
32
+ config[:reconnect_wait] = get_input('Reconnect wait time: ', '\d+', 10)
33
+ config[:bot_nick] = get_input('IRC Nick: ', '[a-zA-Z].*', 'mod_spox')
34
+ config[:bot_password] = get_input('IRC Nick Password (for nickserv): ', '.*', nil)
35
+ config[:bot_username] = get_input('IRC Username: ', '.+', 'mod_spox')
36
+ config[:bot_realname] = get_input('IRC Real Name: ', '.+', 'mod_spox IRC bot')
37
+ config[:socket_burst] = get_input('Socket burst rate (lines): ', '\d+', '3')
38
+ config[:socket_burst_in] = get_input('Socket burst time: ', '\d+', '2')
39
+ config[:socket_burst_delay] = get_input('Socket burst delay: ', '\d+', '2')
40
+ config[:admin_nick] = get_input('Administator nick: ', '[a-zA-Z].*', nil)
41
+ config[:admin_password] = get_input('Administrator password: ', '.+', nil)
42
+ config[:plugin_directory] = get_input('Plugin temp data driectory (bot needs write permission): ', '.+', '/tmp')
43
+ config[:trigger] = get_input('Default trigger: ', '.+', '!')
44
+ config[:memcache] = get_input('Use memcache (EXPERIMENTAL): ', '(yes|no)', 'no')
45
+ valid_connection = false
46
+ until valid_connection do
47
+ config[:db_adapter] = get_input('Database type (pgsql): ', '(pgsql)', 'pgsql')
48
+ unless(config[:db_adapter] == 'sqlite')
49
+ config[:db_username] = get_input('Database username: ', '.+', 'mod_spox')
50
+ config[:db_password] = get_input('Database password: ', '.*', nil)
51
+ config[:db_host] = get_input('Database host: ', '.*', '127.0.0.1')
52
+ config[:db_database] = get_input('Database name: ', '.+', 'mod_spox')
53
+ end
54
+ begin
55
+ print 'Testing database connection... '
56
+ config[:db_adapter] == 'sqlite' ? test_connection(config[:db_adapter]) : test_connection(config[:db_adapter], config[:db_username], config[:db_password], config[:db_host], config[:db_database])
57
+ puts 'OK'
58
+ valid_connection = true
59
+ rescue Sequel::DatabaseError, URI::InvalidURIError => boom
60
+ puts 'Failed'
61
+ puts 'Error: Connection to database failed'
62
+ puts "Info: #{boom}"
63
+ rescue Object => boom
64
+ puts 'Failed'
65
+ puts 'Error: Unexpected error encountered.'
66
+ puts "Info: #{boom.class} #{boom}\n#{boom.backtrace.join("\n")}"
67
+ exit 1
68
+ ensure
69
+ $stdout.flush
70
+ end
71
+ end
51
72
  print "Storing configuration values... "
52
- save_configuration
53
- puts "OK"
54
- puts "mod_spox is now configured and ready for use"
73
+ begin
74
+ save_configuration(config)
75
+ puts 'OK'
76
+ puts 'mod_spox is now configured and ready for use'
77
+ rescue Object => boom
78
+ puts 'Failed'
79
+ puts "Error: #{boom}\n#{boom.backtrace.join("\n")}"
80
+ puts 'Please try running the configuration again'
81
+ end
82
+ end
83
+
84
+ def update
85
+ run
55
86
  end
56
87
 
57
88
  private
58
89
 
59
- def find(key)
60
- @config.each{|c|
61
- if(c[:id] == key)
62
- return c[:value]
63
- end
64
- }
65
- return nil
90
+ def test_connection(type, username=nil, password=nil, host=nil, name=nil)
91
+ case type
92
+ # when 'mysql'
93
+ # c = Sequel.mysql(name, :user => username, :password => password, :host => host)
94
+ # c.test_connection
95
+ when 'pgsql'
96
+ c = Sequel.connect("#{$JDBC ? 'jdbc:' : ''}postgres://#{username}:#{password}@#{host}/#{name}")
97
+ c.test_connection
98
+ when 'sqlite'
99
+ return true
100
+ end
66
101
  end
67
102
 
68
103
  # Save our configuration values
69
- def save_configuration
104
+ def save_configuration(uconfig)
70
105
  config = BaseConfig.new(BotConfig[:userconfigpath])
71
- @config.each{|value|
72
- config[value[:id]] = value[:value] if value[:id].to_s =~ /^(db|memcache)/
73
- }
106
+ uconfig.each_pair do |key,value|
107
+ config[key] = value if key.to_s =~ /^(db|memcache)/
108
+ end
74
109
  config.write_configuration
75
110
  initialize_bot
76
111
  require 'mod_spox/models/Models'
77
112
  require 'mod_spox/Helpers'
78
- create_databases
79
- #Migrators.constants.each{|m| Migrators.const_get(m).apply(Database.db, :up)}
80
- @config.each{|value|
81
- Models::Config[value[:id]] = value[:value] unless value[:id].to_s =~ /^(db|irc|admin|trigger)/
82
- }
83
- s = Models::Server.find_or_create(:host => find(:irc_server), :port => find(:irc_port))
84
- n = Models::Nick.find_or_create(:nick => find(:admin_nick))
113
+ Sequel::Migrator.apply(Database.db, BotConfig[:libpath] + '/migrations')
114
+ uconfig.each_pair do |key,value|
115
+ unless key.to_s =~ /^(db|irc|admin|trigger)/
116
+ m = Models::Config.find_or_create(:name => key.to_s)
117
+ m.value = value
118
+ m.save
119
+ end
120
+ end
121
+ s = Models::Server.find_or_create(:host => uconfig[:irc_server], :port => uconfig[:irc_port])
122
+ n = Models::Nick.find_or_create(:nick => uconfig[:admin_nick])
85
123
  a = Models::Auth.find_or_create(:nick_id => n.pk)
86
124
  a.group = Models::Group.find_or_create(:name => 'admin')
87
- a.password = find(:admin_password)
125
+ a.password = uconfig[:admin_password]
88
126
  a.save
89
- t = Models::Trigger.find_or_create(:trigger => find(:trigger))
127
+ t = Models::Trigger.find_or_create(:trigger => uconfig[:trigger])
90
128
  t.update_with_params(:active => true)
91
129
  t.save
92
130
  end
@@ -106,85 +144,36 @@ module ModSpox
106
144
  # default:: default value if response is empty
107
145
  # echo:: echo user's input
108
146
  # Reads users input
109
- def read_input(pattern=nil, default=nil, echo=true)
110
- input_echo(echo)
147
+ def read_input(pattern=nil, default=nil)
148
+ #input_echo(echo)
111
149
  response = $stdin.readline
112
150
  response.strip!
113
151
  set = response.length > 0
114
152
  unless(pattern.nil?)
115
153
  response = nil unless response =~ /^#{pattern}$/
116
154
  end
117
- if(default && response.nil? && !set)
155
+ if(default && !set)
118
156
  response = default
119
157
  end
120
- input_echo(true) unless echo
121
- puts "" unless echo
158
+ #input_echo(true) unless echo
159
+ #puts "" unless echo
122
160
  return response
123
161
  end
124
162
 
125
- # output:: varchar(255) to send before user input
126
- # regex:: pattern user input must match (^ and $ not need. applied automatically)
163
+ # output:: to send before user input
164
+ # regex:: pattern user input must match (^ and $ not needed. applied automatically)
127
165
  # echo:: echo user's input
128
166
  # default:: default value if no value is entered
129
- def get_input(output, regex, echo=true, default=nil)
167
+ def get_input(output, regex, default=nil)
130
168
  response = nil
131
169
  until(response) do
132
170
  print output
133
171
  print "[#{default}]: " unless default.nil?
134
- response = read_input(regex, default, echo)
172
+ $stdout.flush
173
+ response = read_input(regex, default)
135
174
  end
136
175
  return response
137
176
  end
138
-
139
- def create_databases
140
- case Database.type
141
- when :mysql
142
- Database.db << "CREATE TABLE IF NOT EXISTS nicks (id int not null auto_increment primary key, nick varchar(255) unique not null, username varchar(255), real_name varchar(255), address varchar(255), source varchar(255), connected_at timestamp, connected_to varchar(255), seconds_idle int, visible boolean not null default false, away boolean not null default false, botnick boolean not null default false)"
143
- Database.db << "CREATE TABLE IF NOT EXISTS channels (id int not null auto_increment primary key, name varchar(255) not null, password varchar(255), autojoin boolean not null default false, topic varchar(255), quiet boolean not null default false, parked boolean not null default false)"
144
- Database.db << "CREATE TABLE IF NOT EXISTS auths (id int not null auto_increment primary key, password varchar(255), services boolean not null default false, mask varchar(255) unique, authed boolean not null default false, nick_id int unique references nicks)"
145
- Database.db << "CREATE TABLE IF NOT EXISTS channel_modes (id int not null auto_increment primary key, mode varchar(255) not null, channel_id int unique not null references channels)"
146
- Database.db << "CREATE TABLE IF NOT EXISTS configs (id int not null auto_increment primary key, name varchar(255) unique not null, value varchar(255))"
147
- Database.db << "CREATE TABLE IF NOT EXISTS nick_channels (channel_id int not null unique references channels, nick_id int not null unique not null references nicks, primary key(channel_id, nick_id))"
148
- Database.db << "CREATE TABLE IF NOT EXISTS nick_modes (id integer primary key auto_increment not null, mode varchar(255) not null, nick_id int not null references nicks, channel_id int references channels, unique index nick_modes_nick_id_channel_id_index (nick_id, channel_id))"
149
- Database.db << "CREATE TABLE IF NOT EXISTS servers (id int not null auto_increment primary key, host varchar(255) not null, port int not null default 6667, priority int not null default 0, connected boolean not null default false, unique index servers_server_port_index (server, port))"
150
- Database.db << "CREATE TABLE IF NOT EXISTS settings (id int not null auto_increment primary key, name varchar(255) not null unique, value text)"
151
- Database.db << "CREATE TABLE IF NOT EXISTS signatures (id int not null auto_increment primary key, signature varchar(255) not null, params varchar(255), group_id int default null references groups, method varchar(255) not null, plugin varchar(255) not null, description varchar(255), requirement enum('public', 'private', 'both') default 'both' not null)"
152
- Database.db << "CREATE TABLE IF NOT EXISTS triggers (id int not null auto_increment primary key, `trigger` varchar(255) unique not null, active boolean not null default false)"
153
- Database.db << "CREATE TABLE IF NOT EXISTS groups (id int not null auto_increment primary key, name varchar(255) not null unique)"
154
- Database.db << "CREATE TABLE IF NOT EXISTS auth_groups (auth_id int not null references auths, group_id int not null references groups, primary key(auth_id, group_id))"
155
- when :pgsql
156
- Database.db << "CREATE TABLE nicks (id serial not null primary key, nick varchar(255) unique not null, username varchar(255), real_name varchar(255), address varchar(255), source varchar(255), connected_at timestamp, connected_to varchar(255), seconds_idle integer, visible boolean not null default false, away boolean not null default false, botnick boolean not null default false)"
157
- Database.db << "CREATE INDEX nick_nicks_lower on nicks (lower(nick))"
158
- Database.db << "CREATE TABLE channels (id serial not null primary key, name varchar(255) unique not null, password varchar(255), autojoin boolean not null default false, topic varchar(255), quiet boolean not null default false, parked boolean not null default false)"
159
- Database.db << "CREATE TABLE auths (id serial not null primary key, password varchar(255), services boolean not null default false, mask varchar(255) unique, authed boolean not null default false, nick_id integer unique references nicks)"
160
- Database.db << "CREATE TABLE groups (id serial not null primary key, name varchar(255) unique not null)"
161
- Database.db << "CREATE TABLE channel_modes (id serial not null primary key, mode varchar(255) not null, channel_id integer unique not null references channels)"
162
- Database.db << "CREATE TABLE configs (id serial not null primary key, name varchar(255) unique not null, value text)"
163
- Database.db << "CREATE TABLE nick_channels (channel_id integer not null references channels, nick_id integer not null references nicks, primary key(nick_id, channel_id))"
164
- Database.db << "CREATE TABLE nick_modes (id serial not null primary key, mode varchar(255) not null, nick_id integer not null references nicks, channel_id integer references channels, unique (nick_id, channel_id))"
165
- Database.db << "CREATE TABLE servers (id serial not null primary key, host varchar(255) not null, port integer not null default 6667, priority integer not null default 0, connected boolean not null default false, unique (host, port))"
166
- Database.db << "CREATE TABLE signatures (id serial not null primary key, signature varchar(255) not null, params varchar(255), group_id integer default null references groups, method varchar(255) not null, plugin varchar(255) not null, description varchar(255), requirement varchar(255) default 'both' not null)"
167
- Database.db << "CREATE TABLE settings (id serial not null primary key, name varchar(255) unique not null, value text)"
168
- Database.db << "CREATE TABLE triggers (id serial not null primary key, trigger varchar(255) unique not null, active boolean not null default false)"
169
- Database.db << "CREATE TABLE auth_groups (auth_id integer not null references auths, group_id integer not null references groups, primary key (auth_id, group_id))"
170
- when :sqlite
171
- Database.db << "CREATE TABLE if not exists nicks (id integer PRIMARY KEY AUTOINCREMENT, nick string UNIQUE NOT NULL COLLATE NOCASE, username string, real_name string, address string, source string, connected_at timestamp, connected_to string, seconds_idle integer, visible boolean NOT NULL DEFAULT 'f', away boolean NOT NULL DEFAULT 'f', botnick boolean NOT NULL DEFAULT 'f')"
172
- Database.db << "CREATE TABLE if not exists channels (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL COLLATE NOCASE, password string, autojoin boolean NOT NULL DEFAULT 'f', topic string, quiet boolean NOT NULL DEFAULT 'f', parked boolean NOT NULL DEFAULT 'f')"
173
- Database.db << "CREATE TABLE if not exists auths (id integer PRIMARY KEY AUTOINCREMENT, password string, services boolean NOT NULL DEFAULT 'f', mask string UNIQUE, authed boolean NOT NULL DEFAULT 'f', nick_id integer UNIQUE REFERENCES nicks)"
174
- Database.db << "CREATE TABLE if not exists channel_modes (id integer PRIMARY KEY AUTOINCREMENT, mode string NOT NULL, channel_id integer UNIQUE NOT NULL REFERENCES channels)"
175
- Database.db << "CREATE TABLE if not exists configs (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL, value string)"
176
- Database.db << "CREATE TABLE if not exists nick_channels (channel_id integer NOT NULL REFERENCES channels, nick_id integer NOT NULL REFERENCES nicks, primary key (channel_id, nick_id))"
177
- Database.db << "CREATE TABLE if not exists nick_modes (id integer PRIMARY KEY AUTOINCREMENT, mode string NOT NULL, nick_id integer NOT NULL REFERENCES nicks, channel_id integer REFERENCES channels)"
178
- Database.db << "CREATE UNIQUE INDEX if not exists nick_modes_nick_id_channel_id_index ON nick_modes (nick_id, channel_id)"
179
- Database.db << "CREATE TABLE if not exists servers (id integer primary key autoincrement, host string NOT NULL, port integer NOT NULL DEFAULT 6667, priority integer NOT NULL DEFAULT 0, connected boolean NOT NULL DEFAULT 'f')"
180
- Database.db << "CREATE UNIQUE INDEX if not exists servers_host_port_index on servers (host, port)"
181
- Database.db << "CREATE TABLE if not exists settings (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL, value text)"
182
- Database.db << "CREATE TABLE if not exists signatures (id integer PRIMARY KEY AUTOINCREMENT, signature string NOT NULL UNIQUE, params string, group_id integer DEFAULT NULL REFERENCES groups, method string NOT NULL, plugin string NOT NULL, description varchar(255), requirement varchar(255) not null default 'both')"
183
- Database.db << "CREATE TABLE if not exists triggers (id integer PRIMARY KEY AUTOINCREMENT, trigger string UNIQUE NOT NULL, active boolean NOT NULL DEFAULT 'f')"
184
- Database.db << "CREATE TABLE if not exists groups (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL COLLATE NOCASE)"
185
- Database.db << "CREATE TABLE if not exists auth_groups(auth_id integer REFERENCES auths, group_id integer REFERENCES groups)"
186
- end
187
- end
188
177
 
189
178
  end
190
179
 
@@ -1,34 +1,54 @@
1
1
  module ModSpox
2
2
 
3
3
  class Database
4
-
5
- def self.db=(database)
4
+
5
+ def Database.db=(database)
6
6
  @@db = nil
7
7
  @@db = database
8
8
  end
9
-
10
- def self.type=(type)
9
+
10
+ def Database.type=(type)
11
11
  @@type = nil
12
12
  @@type = type
13
13
  end
14
-
15
- def self.cache=(cache)
14
+
15
+ def Database.cache=(cache)
16
16
  @@cache = nil
17
17
  @@cache = cache
18
18
  end
19
-
20
- def self.cache
19
+
20
+ def Database.cache
21
21
  return Database.class_variable_defined?(:@@cache) ? @@cache : nil
22
22
  end
23
-
24
- def self.type
23
+
24
+ def Database.type
25
25
  return Database.class_variable_defined?(:@@type) ? @@type : nil
26
26
  end
27
-
28
- def self.db
27
+
28
+ def Database.db
29
29
  return Database.class_variable_defined?(:@@db) ? @@db : nil
30
30
  end
31
-
31
+
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
37
+ end
38
+
39
+ def Database.reconnect
40
+ begin
41
+ @@db.test_connection
42
+ Logger.warn('Database connection appears to be active. Closing.')
43
+ @@db.disconnect
44
+ rescue Object => boom
45
+ Logger.warn('Database connection does not appear to be active.')
46
+ ensure
47
+ Logger.warn('Reconnecting to database.')
48
+ ModSpox.setup_adapter
49
+ end
50
+ end
51
+
32
52
  end
33
53
 
34
54
  end
@@ -11,21 +11,45 @@ module ModSpox
11
11
  # secs:: number of seconds
12
12
  # Converts seconds into a human readable string
13
13
  def Helpers.format_seconds(secs)
14
- str = []
15
- d = (secs / 86400).to_i
16
- secs = secs % 86400
17
- h = (secs / 3600).to_i
18
- secs = secs % 3600
19
- m = (secs / 60).to_i
20
- secs = secs % 60
21
- {:day => d, :hour => h, :minute => m, :second => secs}.each_pair do |type, value|
22
- if(value > 0)
23
- str << "#{value} #{type}#{value == 1 ? '':'s'}"
24
- end
14
+ arg = {:year => 29030400,
15
+ :month => 2419200,
16
+ :week => 604800,
17
+ :day => 86400,
18
+ :hour => 3600,
19
+ :minute => 60,
20
+ :second => 1}
21
+ res = ''
22
+ arg.each_pair do |k,v|
23
+ z = (secs / v).to_i
24
+ next unless z > 0
25
+ res += " #{z} #{k}#{z == 1 ? '':'s'}"
26
+ secs = secs % v
25
27
  end
26
- return str.join(' ')
28
+ res = '0 seconds' if res.empty?
29
+ return res.strip
30
+ end
31
+
32
+ # bytes:: number of bytes
33
+ # Converts bytes into easy human readable form
34
+ # O(1) version by Ryan "pizza_milkshake" Flynn
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
45
+ ]
46
+ def Helpers.format_size(bytes)
47
+ mag = (Math.log(bytes) / Math.log(1000)).floor
48
+ mag = [ Suff.length - 1, mag ].min
49
+ val = bytes.to_f / (1000 ** mag)
50
+ "%7.3f %sbyte%s" % [ val, Suff[mag], val == 1 ? "" : "s" ]
27
51
  end
28
-
52
+
29
53
  # command:: command to execute
30
54
  # timeout:: maximum number of seconds to run
31
55
  # Execute a system command (use with care)
@@ -35,32 +59,29 @@ module ModSpox
35
59
  result = `#{command}`
36
60
  end
37
61
  rescue Timeout::Error => boom
38
- Logger.log("Command execution exceeded allowed time (command: #{command} | timeout: #{timeout})")
62
+ Logger.warn("Command execution exceeded allowed time (command: #{command} | timeout: #{timeout})")
63
+ raise boom
39
64
  rescue Object => boom
40
- Logger.log("Command generated an exception (command: #{command} | error: #{boom})")
65
+ Logger.warn("Command generated an exception (command: #{command} | error: #{boom})")
66
+ raise boom
41
67
  end
42
68
  end
43
-
69
+
44
70
  # url:: URL to shorten
45
71
  # Gets a tinyurl for given URL
46
72
  def Helpers.tinyurl(url)
47
73
  begin
48
74
  connection = Net::HTTP.new('tinyurl.com', 80)
49
- resp, data = connection.get("/create.php?url=#{url}", nil)
75
+ resp, data = connection.get("/api-create.php?url=#{url}")
50
76
  if(resp.code !~ /^200$/)
51
77
  raise "Failed to make the URL small."
52
78
  end
53
- data.gsub!(/[\n\r]/, '')
54
- if(data =~ /<input type=hidden name=tinyurl value="(.+?)">/)
55
- return $1
56
- else
57
- raise "Failed to locate the small URL."
58
- end
79
+ return data.strip
59
80
  rescue Object => boom
60
81
  raise "Failed to process URL. #{boom}"
61
82
  end
62
83
  end
63
-
84
+
64
85
  # string:: name of target
65
86
  # Locates target model and returns it. String can be a nick
66
87
  # or channel name. If the string given does not match the required
@@ -68,55 +89,63 @@ module ModSpox
68
89
  def Helpers.find_model(string, create=true)
69
90
  Helpers.initialize_caches
70
91
  if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
71
- Logger.log("Model: #{string} -> Nick", 30)
72
92
  nick = nil
73
93
  if(@@nick_cache.has_key?(string.downcase.to_sym))
74
94
  begin
75
95
  nick = Models::Nick[@@nick_cache[string.downcase.to_sym]]
76
- Logger.log("Handler cache hit for nick: #{string}", 30)
77
96
  if(nick.nick.downcase != string.downcase)
78
- Logger.log("Nick returned from cache invalid. Expecting #{string} but got #{nick.nick}", 30)
97
+ Logger.warn("Nick returned from cache invalid. Expecting #{string} but got #{nick.nick}")
79
98
  nick = nil
80
99
  end
81
100
  rescue Object => boom
82
- Logger.log("Failed to grab cached nick: #{boom}", 30)
101
+ Logger.info("Failed to grab cached nick: #{boom}")
83
102
  end
84
103
  end
85
104
  unless(nick)
86
- nick = Models::Nick.locate(string, create)
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
87
115
  @@nick_cache[string.downcase.to_sym] = nick.pk if nick.is_a?(Models::Nick)
88
- Logger.log("Nick was retrieved from database", 30)
116
+ Logger.info('Nick was retrieved from database')
89
117
  end
90
118
  return nick
91
119
  elsif(string =~ /^[&#+!]/)
92
- Logger.log("Model: #{string} -> Channel", 30)
93
120
  if(@@channel_cache.has_key?(string.downcase.to_sym))
94
121
  begin
95
122
  channel = Models::Channel[@@channel_cache[string.downcase.to_sym]]
96
- Logger.log("Handler cache hit for channel: #{string}", 30)
97
123
  if(string.downcase != channel.name.downcase)
98
- Logger.log("Channel returned from cache invalid. Expecting #{string} but got #{channel.name}", 30)
124
+ Logger.warn("Channel returned from cache invalid. Expecting #{string} but got #{channel.name}")
99
125
  channel = nil
100
126
  end
101
127
  rescue Object => boom
102
- Logger.log("Failed to grab cached channel: #{boom}", 30)
128
+ Logger.info("Failed to grab cached channel: #{boom}")
103
129
  end
104
130
  end
105
131
  unless(channel)
106
132
  channel = Models::Channel.locate(string, create)
133
+ if(channel.nil?)
134
+ Database.reconnect
135
+ return string
136
+ end
107
137
  @@channel_cache[string.downcase.to_sym] = channel.pk if channel.is_a?(Models::Channel)
108
- Logger.log("Channel was retrieved from database", 30)
138
+ Logger.info('Channel was retrieved from database')
109
139
  end
110
140
  return channel
111
141
  elsif(model = Models::Server.filter(:host => string, :connected => true).first)
112
- Logger.log("Model: #{string} -> Server", 30)
113
142
  return model
114
143
  else
115
- Logger.log("FAIL Model: #{string} -> No match", 30)
144
+ Logger.warn("Failed to match string to model: #{string} -> No match")
116
145
  return string
117
146
  end
118
147
  end
119
-
148
+
120
149
  def Helpers.initialize_caches
121
150
  @@nick_cache = Cache.new(20) unless Helpers.class_variable_defined?(:@@nick_cache)
122
151
  @@channel_cache = Cache.new(5) unless Helpers.class_variable_defined?(:@@channel_cache)
@@ -1,13 +1,15 @@
1
1
  ['mod_spox/Exceptions',
2
2
  'mod_spox/BotConfig',
3
3
  'mod_spox/BaseConfig',
4
- 'mod_spox/Database'].each{|f|require f}
4
+ 'mod_spox/Database',
5
+ 'logger'].each{|f|require f}
5
6
 
6
7
  module ModSpox
7
8
 
8
9
  # Loads all files needed by the bot
9
10
  def initialize_bot
10
11
  setup_adapter
12
+ check_upgrade
11
13
  end
12
14
 
13
15
  # Setup the DataMapper adapter
@@ -27,15 +29,33 @@ module ModSpox
27
29
  case config[:db_adapter]
28
30
  when 'mysql'
29
31
  Database.db = Sequel.mysql(config[:db_database], :user => config[:db_username],
30
- :password => config[:db_password], :host => config[:db_host])
32
+ :password => config[:db_password], :host => config[:db_host], :max_connections => 20)
31
33
  Database.type = :mysql
32
34
  when 'pgsql'
33
- Database.db = Sequel.open("postgres://#{config[:db_username]}:#{config[:db_password]}@#{config[:db_host]}/#{config[:db_database]}")
35
+ Database.db = Sequel.connect("#{$JDBC ? 'jdbc:' : ''}postgres://#{config[:db_username]}:#{config[:db_password]}@#{config[:db_host]}/#{config[:db_database]}")
34
36
  Database.type = :pgsql
35
37
  when 'sqlite'
36
- Database.db = Sequel.sqlite "#{BotConfig[:userpath]}/mod_spox.db"
38
+ Database.db = Sequel.sqlite("#{BotConfig[:userpath]}/mod_spox.db")
37
39
  Database.type = :sqlite
38
40
  end
39
41
  end
40
-
42
+
43
+ # check if the bot has been upgraded
44
+ def check_upgrade
45
+ config = BaseConfig.new(BotConfig[:userconfigpath])
46
+ config[:plugin_upgrade] = 'no'
47
+ begin
48
+ do_upgrade(config) if config[:last_version] != $BOTVERSION
49
+ rescue Exceptions::UnknownKey => boom
50
+ do_upgrade(config)
51
+ 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'
59
+ end
60
+
41
61
  end