mod_spox 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG +38 -0
  2. data/INSTALL +5 -2
  3. data/bin/mod_spox +7 -3
  4. data/data/mod_spox/extras/Confess.rb +4 -4
  5. data/data/mod_spox/extras/Karma.rb +2 -2
  6. data/data/mod_spox/extras/Logger.rb +167 -0
  7. data/data/mod_spox/extras/Quotes.rb +2 -2
  8. data/data/mod_spox/extras/Roulette.rb +34 -16
  9. data/data/mod_spox/extras/Topten.rb +105 -0
  10. data/data/mod_spox/plugins/Authenticator.rb +2 -2
  11. data/data/mod_spox/plugins/Banner.rb +10 -10
  12. data/data/mod_spox/plugins/Initializer.rb +1 -1
  13. data/data/mod_spox/plugins/Triggers.rb +3 -3
  14. data/lib/mod_spox/Bot.rb +6 -5
  15. data/lib/mod_spox/BotConfig.rb +1 -1
  16. data/lib/mod_spox/ConfigurationWizard.rb +18 -17
  17. data/lib/mod_spox/Database.rb +9 -0
  18. data/lib/mod_spox/Helpers.rb +49 -0
  19. data/lib/mod_spox/Loader.rb +11 -0
  20. data/lib/mod_spox/PluginManager.rb +1 -0
  21. data/lib/mod_spox/Pool.rb +23 -107
  22. data/lib/mod_spox/Socket.rb +23 -37
  23. data/lib/mod_spox/Timer.rb +3 -3
  24. data/lib/mod_spox/handlers/Created.rb +1 -1
  25. data/lib/mod_spox/handlers/Handler.rb +1 -13
  26. data/lib/mod_spox/handlers/Invite.rb +1 -1
  27. data/lib/mod_spox/handlers/LuserOp.rb +1 -1
  28. data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
  29. data/lib/mod_spox/messages/internal/TimerAdd.rb +8 -0
  30. data/lib/mod_spox/messages/internal/TimerRemove.rb +8 -0
  31. data/lib/mod_spox/messages/internal/TimerResponse.rb +8 -1
  32. data/lib/mod_spox/models/Auth.rb +4 -4
  33. data/lib/mod_spox/models/Channel.rb +11 -0
  34. data/lib/mod_spox/models/Nick.rb +22 -11
  35. data/lib/mod_spox/models/Setting.rb +2 -2
  36. data/lib/mod_spox/models/Signature.rb +11 -2
  37. metadata +4 -2
data/lib/mod_spox/Bot.rb CHANGED
@@ -30,20 +30,21 @@ module ModSpox
30
30
  @socket = nil
31
31
  @nick = nil
32
32
  @thread = Thread.current
33
+ @waiter = Monitors::Boolean.new
33
34
  hook_pipeline
34
35
  end
35
36
 
36
37
  # Run the bot
37
38
  def run
38
- trap('SIGTERM'){ Logger.log("Caught SIGTERM"); Thread.current.exit }
39
- trap('SIGKILL'){ Logger.log("Caught SIGKILL"); Thread.current.exit }
40
- trap('SIGINT'){ Logger.log("Caught SIGINT"); Thread.current.exit }
41
- trap('SIGQUIT'){ Logger.log("Caught SIGQUIT"); Thread.current.exit }
39
+ trap('SIGTERM'){ Logger.log("Caught SIGTERM"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
40
+ trap('SIGKILL'){ Logger.log("Caught SIGKILL"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
41
+ trap('SIGINT'){ Logger.log("Caught SIGINT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
42
+ trap('SIGQUIT'){ Logger.log("Caught SIGQUIT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
42
43
  until @shutdown do
43
44
  @timer.start
44
45
  @pipeline << Messages::Internal::BotInitialized.new
45
46
  begin
46
- Thread.stop
47
+ @waiter.wait
47
48
  rescue Object => boom
48
49
  Logger.log("Caught exception: #{boom}")
49
50
  end
@@ -21,7 +21,7 @@ module ModSpox
21
21
  }
22
22
  if(gem)
23
23
  p = gem.full_gem_path
24
- up = Etc.getpwnam(Etc.getlogin).dir
24
+ up = $MOD_SPOX_PATH.nil? ? Etc.getpwnam(Etc.getlogin).dir : $MOD_SPOX_PATH
25
25
  @@config = {:basepath => p,
26
26
  :libpath => "#{p}/lib/mod_spox",
27
27
  :datapath => "#{p}/data/mod_spox",
@@ -27,7 +27,8 @@ module ModSpox
27
27
  @config << {:id => :admin_nick, :string => 'Administrator nick: ', :regex => '[a-zA-Z].*', :default => nil, :value => nil, :echo => true}
28
28
  @config << {:id => :admin_password, :string => 'Administrator password: ', :regex => '.+', :default => nil, :value => nil, :echo => false}
29
29
  @config << {:id => :plugin_directory, :string => 'Plugin directory (bot must have write priviliges): ', :regex => '.+', :default => nil, :echo => true}
30
- @config << {:id => :trigger, :string => 'Trigger character for plugins: ', :regex => '.', :default => '!', :value => nil, :echo => true}
30
+ @config << {:id => :trigger, :string => 'Trigger character for plugins: ', :regex => '.', :default => '!', :value => nil, :echo => true}
31
+ @config << {:id => :memcache, :string => 'Use memcache (EXPERIMENTAL): ', :regex => '(yes|no)', :default => 'no', :value => nil, :echo => true}
31
32
  @stuck_visible = true
32
33
  begin
33
34
  require 'termios'
@@ -66,7 +67,7 @@ module ModSpox
66
67
  def save_configuration
67
68
  config = BaseConfig.new(BotConfig[:userconfigpath])
68
69
  @config.each{|value|
69
- config[value[:id]] = value[:value] if value[:id].to_s =~ /^db/
70
+ config[value[:id]] = value[:value] if value[:id].to_s =~ /^(db|memcache)/
70
71
  }
71
72
  config.write_configuration
72
73
  initialize_bot
@@ -117,7 +118,7 @@ module ModSpox
117
118
  return response
118
119
  end
119
120
 
120
- # output:: text to send before user input
121
+ # output:: varchar(255) to send before user input
121
122
  # regex:: pattern user input must match (^ and $ not need. applied automatically)
122
123
  # echo:: echo user's input
123
124
  # default:: default value if no value is entered
@@ -143,24 +144,24 @@ module ModSpox
143
144
  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))"
144
145
  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))"
145
146
  Database.db << "CREATE TABLE IF NOT EXISTS settings (id int not null auto_increment primary key, name varchar(255) not null unique, value text)"
146
- 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 text, requirement enum('public', 'private', 'both') default 'both' not null)"
147
+ 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)"
147
148
  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)"
148
149
  Database.db << "CREATE TABLE IF NOT EXISTS groups (id int not null auto_increment primary key, name varchar(255) not null unique)"
149
150
  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))"
150
151
  when :pgsql
151
- Database.db << "CREATE TYPE sig_requirement AS ENUM ('public', 'private', 'both')"
152
- Database.db << "CREATE TABLE nicks (id serial not null primary key, nick text unique not null, username text, real_name text, address text, source text, connected_at timestamp, connected_to text, seconds_idle integer, visible boolean not null default false, away boolean not null default false, botnick boolean not null default false)"
153
- Database.db << "CREATE TABLE channels (id serial not null primary key, name text unique not null, password text, autojoin boolean not null default false, topic text, quiet boolean not null default false, parked boolean not null default false)"
154
- Database.db << "CREATE TABLE auths (id serial not null primary key, password text, services boolean not null default false, mask text unique, authed boolean not null default false, nick_id integer unique references nicks)"
155
- Database.db << "CREATE TABLE groups (id serial not null primary key, name text unique not null)"
156
- Database.db << "CREATE TABLE channel_modes (id serial not null primary key, mode text not null, channel_id integer unique not null references channels)"
157
- Database.db << "CREATE TABLE configs (id serial not null primary key, name text unique not null, value text)"
152
+ 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)"
153
+ Database.db << "CREATE INDEX nick_nicks_lower on nicks (lower(nick))"
154
+ 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)"
155
+ 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)"
156
+ Database.db << "CREATE TABLE groups (id serial not null primary key, name varchar(255) unique not null)"
157
+ 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)"
158
+ Database.db << "CREATE TABLE configs (id serial not null primary key, name varchar(255) unique not null, value text)"
158
159
  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))"
159
- Database.db << "CREATE TABLE nick_modes (id serial not null primary key, mode text not null, nick_id integer not null references nicks, channel_id integer references channels, unique (nick_id, channel_id))"
160
- Database.db << "CREATE TABLE servers (id serial not null primary key, host text not null, port integer not null default 6667, priority integer not null default 0, connected boolean not null default false, unique (host, port))"
161
- Database.db << "CREATE TABLE signatures (id serial not null primary key, signature text not null, params text, group_id integer default null references groups, method text not null, plugin text not null, description text, requirement sig_requirement default 'both' not null)"
162
- Database.db << "CREATE TABLE settings (id serial not null primary key, name text unique not null, value text)"
163
- Database.db << "CREATE TABLE triggers (id serial not null primary key, trigger text unique not null, active boolean not null default false)"
160
+ 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))"
161
+ 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))"
162
+ 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)"
163
+ Database.db << "CREATE TABLE settings (id serial not null primary key, name varchar(255) unique not null, value varchar(255))"
164
+ Database.db << "CREATE TABLE triggers (id serial not null primary key, trigger varchar(255) unique not null, active boolean not null default false)"
164
165
  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))"
165
166
  when :sqlite
166
167
  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')"
@@ -174,7 +175,7 @@ module ModSpox
174
175
  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')"
175
176
  Database.db << "CREATE UNIQUE INDEX if not exists servers_host_port_index on servers (host, port)"
176
177
  Database.db << "CREATE TABLE if not exists settings (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL, value text)"
177
- 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 text, requirement text not null default 'both')"
178
+ 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')"
178
179
  Database.db << "CREATE TABLE if not exists triggers (id integer PRIMARY KEY AUTOINCREMENT, trigger string UNIQUE NOT NULL, active boolean NOT NULL DEFAULT 'f')"
179
180
  Database.db << "CREATE TABLE if not exists groups (id integer PRIMARY KEY AUTOINCREMENT, name string UNIQUE NOT NULL COLLATE NOCASE)"
180
181
  Database.db << "CREATE TABLE if not exists auth_groups(auth_id integer REFERENCES auths, group_id integer REFERENCES groups)"
@@ -12,6 +12,15 @@ module ModSpox
12
12
  @@type = type
13
13
  end
14
14
 
15
+ def self.cache=(cache)
16
+ @@cache = nil
17
+ @@cache = cache
18
+ end
19
+
20
+ def self.cache
21
+ return Database.class_variable_defined?(:@@cache) ? @@cache : nil
22
+ end
23
+
15
24
  def self.type
16
25
  return Database.class_variable_defined?(:@@type) ? @@type : nil
17
26
  end
@@ -54,5 +54,54 @@ module ModSpox
54
54
  raise "Failed to process URL. #{boom}"
55
55
  end
56
56
  end
57
+
58
+ # string:: name of target
59
+ # Locates target model and returns it. String can be a nick
60
+ # or channel name. If the string given does not match the required
61
+ # pattern for a channel or nick, the string is returned.
62
+ def Helpers.find_model(string, create=true)
63
+ @@channel_cache = {} unless Helpers.class_variable_defined?(:@@channel_cache)
64
+ @@nick_cache = {} unless Helpers.class_variable_defined?(:@@nick_cache)
65
+ if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
66
+ Logger.log("Model: #{string} -> Nick")
67
+ nick = nil
68
+ if(@@nick_cache.has_key?(string.to_sym))
69
+ begin
70
+ nick = Models::Nick[@@nick_cache[string.to_sym]]
71
+ Logger.log("Handler cache hit for nick: #{string}", 30)
72
+ rescue Object => boom
73
+ Logger.log("Failed to grab cached nick: #{boom}")
74
+ end
75
+ end
76
+ unless(nick)
77
+ nick = Models::Nick.locate(string, create)
78
+ @@nick_cache[string.to_sym] = nick.pk if nick.is_a?(Models::Nick)
79
+ Logger.log("Nick was retrieved from database")
80
+ end
81
+ return nick
82
+ elsif(string =~ /^[&#+!]/)
83
+ Logger.log("Model: #{string} -> Channel")
84
+ if(@@channel_cache.has_key?(string.to_sym))
85
+ begin
86
+ channel = Models::Channel[@@channel_cache[string.to_sym]]
87
+ Logger.log("Handler cache hit for channel: #{string}", 30)
88
+ rescue Object => boom
89
+ Logger.log("Failed to grab cached channel: #{boom}")
90
+ end
91
+ end
92
+ unless(channel)
93
+ channel = Models::Channel.locate(string, create)
94
+ @@channel_cache[string.to_sym] = channel.pk if channel.is_a?(Models::Channel)
95
+ Logger.log("Channel was retrieved from database")
96
+ end
97
+ return channel
98
+ elsif(model = Models::Server.filter(:host => string, :connected => true).first)
99
+ Logger.log("Model: #{string} -> Server")
100
+ return model
101
+ else
102
+ Logger.log("FAIL Model: #{string} -> No match")
103
+ return string
104
+ end
105
+ end
57
106
  end
58
107
  end
@@ -61,7 +61,18 @@ module ModSpox
61
61
  require 'mod_spox/BotConfig'
62
62
  require 'mod_spox/BaseConfig'
63
63
  require 'mod_spox/Database'
64
+ memcache = false
64
65
  config = BaseConfig.new(BotConfig[:userconfigpath])
66
+ if(config[:memcache] == 'on')
67
+ begin
68
+ require 'memcache'
69
+ memcache = true
70
+ Database.cache = MemCache.new('localhost:11211', :namespace => 'modspox')
71
+ rescue Object => boom
72
+ puts "FAILED TO LOAD MEMCACHE SUPPORT: #{boom}"
73
+ # do nothing #
74
+ end
75
+ end
65
76
  case config[:db_adapter]
66
77
  when 'mysql'
67
78
  Database.db = Sequel.mysql(config[:db_database], :user => config[:db_username],
@@ -1,3 +1,4 @@
1
+ require 'fileutils'
1
2
  module ModSpox
2
3
 
3
4
  class PluginManager
data/lib/mod_spox/Pool.rb CHANGED
@@ -3,27 +3,6 @@ module ModSpox
3
3
  # The Pool class is used to reduce thread creation. It provides
4
4
  # an easy way to process many objects in an asynchronous manner.
5
5
  class Pool
6
-
7
- #
8
- def Pool.max_threads(num=nil)
9
- if(num.nil?)
10
- return @@max_threads
11
- else
12
- num = num.to_i
13
- raise Exceptions::InvalidValue.new('Maximum threads setting must be a positive integer') if num < 1
14
- @@max_threads = num
15
- end
16
- end
17
-
18
- def Pool.max_thread_life(num=nil)
19
- if(num.nil?)
20
- return @@max_thread_life
21
- else
22
- num = num.to_i
23
- raise Exceptions::InvalidValue.new('Maximum thread life setting must be a positive integer') if num < 1
24
- @@max_thread_life = num
25
- end
26
- end
27
6
 
28
7
  # Action thread is to perform
29
8
  attr_reader :proc
@@ -63,46 +42,21 @@ module ModSpox
63
42
  # Running pools
64
43
  @@pools = Array.new
65
44
  # Threads running in pool
66
- @@threads = Hash.new
45
+ @@threads = Array.new
67
46
  # Lock for thread safety
68
47
  @@lock = Mutex.new
69
- # Maximum number of threads in pool
70
- @@max_threads = 10
71
48
  # Maximum number of seconds a thread may spend waiting for an action
72
- @@max_thread_life = 60
73
- # Thread to tend to pool actions
74
- @@pool_thread = nil
49
+ @@max_exec_time = 60
75
50
  # Informs threads to halt
76
51
  @@kill = false
77
- # Place for threads to wait for actions
78
- @@thread_stopper = Monitors::Boolean.new
79
- # Timer for the Pool thread
80
- @@watcher_timer = Monitors::Timer.new
81
52
 
82
53
  # Adds a new thread to the pool
83
54
  def Pool.add_thread
84
- if(@@threads.size < @@max_threads)
85
- thread = Thread.new do
86
- sleep(0.01)
87
- until(@@kill) do
88
- Pool.schedule_thread
89
- end
55
+ @@threads << Thread.new do
56
+ until(Pool.max_queue_size < 1 || @@kill) do
57
+ Pool.schedule_thread
90
58
  end
91
- @@threads[thread] = Time.now
92
- Logger.log("New thread added to pool: #{thread}")
93
- else
94
- raise Exceptions::BotException.new("Reached maximum thread pool size: #{@@max_threads} threads")
95
- end
96
- end
97
-
98
- # thread:: Thread to delete
99
- # Removes thread from pool
100
- def Pool.delete_thread(thread)
101
- @@lock.synchronize do
102
- @@threads.delete(thread) if @@threads.has_key?(thread)
103
- @@thread_stopper.remove_thread(thread)
104
- thread.kill
105
- Logger.log("Thread removed from thread pool: #{thread}")
59
+ @@threads.delete(Thread.current)
106
60
  end
107
61
  end
108
62
 
@@ -124,74 +78,36 @@ module ModSpox
124
78
  end
125
79
  end
126
80
  unless(run_pool.nil?)
127
- @@threads[Thread.current] = Time.now
128
- run_pool.proc.call
129
- @@threads[Thread.current] = Time.now
130
- else
131
- @@thread_stopper.wait
132
- end
133
- end
134
-
135
- # Starts the master thread for Pool maintanence
136
- def Pool.start_watcher
137
- @@pool_thread = Thread.new{
138
- until(@@kill) do
139
- sleep_time = 0
140
- begin
141
- waiters = Pool.waiting_threads
142
- unless(waiters.empty?)
143
- waiters.each do |thread|
144
- time = Time.now.to_i - @@threads[thread].to_i
145
- sleep_time = (@@max_thread_life - time).to_i if sleep_time = 0 || (@@max_thread_life - time).to_i < sleep_time
146
- if(time > @@max_thread_life)
147
- Pool.delete_thread(thread)
148
- elsif(!['sleep', 'run'].include?(thread.status))
149
- Pool.delete_thread(thread)
150
- end
151
- end
152
- else
153
- if(Pool.max_queue_size > 0)
154
- Pool.add_thread
155
- end
156
- end
157
- rescue Object => boom
158
- Logger.log("Pool watcher caught an error (ignoring): #{boom}")
81
+ begin
82
+ Timeout::timeout(@@max_exec_time) do
83
+ run_pool.proc.call
159
84
  end
160
- sleep_time = 1 if sleep_time == 0
161
- sleep_time = nil if sleep_time < 0
162
- Logger.log("Pool watcher thread is now sleeping for: #{sleep_time.nil? ? 'forever' : "#{sleep_time} seconds"}")
163
- @@watcher_timer.wait(sleep_time)
85
+ rescue Timeout::Error => boom
86
+ Logger.log("Thread reached maximum execution time (#{@max_exec_time}) processing pool item")
87
+ rescue Object => boom
88
+ Logger.log("Thread encountered error processing pool item: #{boom}")
164
89
  end
165
- } if @@pool_thread.nil?
90
+ end
166
91
  end
167
92
 
168
93
  # Forces sleeping threads to wake up
169
- def Pool.wakeup_threads
170
- @@watcher_timer.wakeup
171
- @@thread_stopper.wakeup
172
- end
173
-
174
- # Returns list of threads currently waiting for an action to process
175
- def Pool.waiting_threads
176
- waiting = []
177
- @@threads.each_pair do |thread,time|
178
- waiting << thread if @@thread_stopper.thread_waiting?(thread)
179
- end
180
- return waiting
94
+ def Pool.process
95
+ sleep(0.1)
96
+ Pool.add_thread if Pool.max_queue_size > 0
97
+ Logger.log("Current number of threads: #{@@threads.size}")
98
+ Logger.log("Total number of threads in use system-wide: #{Thread.list.size}")
181
99
  end
182
100
 
183
101
  # Adds a Pool to the master Pool list
184
102
  def Pool.add_pool(pool)
185
103
  @@pools << pool
186
- @@lock.synchronize do
187
- Pool.start_watcher
188
- end
189
104
  end
190
105
 
191
106
  # Removes a Pool from the master Pool list
192
107
  def Pool.remove_pool(pool)
193
108
  @@pools.delete(pool)
194
- @@kill = true if @@pools.empty?
109
+ sleep(0.1)
110
+ @@threads.each{|t| t.kill} if @@pools.empty?
195
111
  end
196
112
 
197
113
  # Modified Queue to properly interact with Pool
@@ -205,14 +121,14 @@ module ModSpox
205
121
  def <<(val)
206
122
  @lock.synchronize do
207
123
  super
208
- Pool.wakeup_threads
124
+ Pool.process
209
125
  end
210
126
  end
211
127
 
212
128
  def push(val)
213
129
  @lock.synchronize do
214
130
  super
215
- Pool.wakeup_threads
131
+ Pool.process
216
132
  end
217
133
  end
218
134
 
@@ -1,6 +1,6 @@
1
1
  module ModSpox
2
2
 
3
- class Socket
3
+ class Socket < Pool
4
4
 
5
5
  attr_reader :sent
6
6
  attr_reader :received
@@ -18,6 +18,7 @@ module ModSpox
18
18
  # burst:: Number of lines allowed to be sent within the burst_in time limit
19
19
  # Create a new Socket
20
20
  def initialize(bot, server, port, delay=2, burst_in=2, burst=4)
21
+ super()
21
22
  @factory = bot.factory
22
23
  @pipeline = bot.pipeline
23
24
  @server = server
@@ -29,10 +30,11 @@ module ModSpox
29
30
  @burst_in = 2
30
31
  @kill = false
31
32
  @reader_thread = nil
32
- @writer_thread = nil
33
33
  @time_check = nil
34
34
  @check_burst = 0
35
35
  @pause = false
36
+ @sendq = @queue
37
+ start_pool
36
38
  end
37
39
 
38
40
  # Connects to the IRC server
@@ -43,9 +45,7 @@ module ModSpox
43
45
  server = Models::Server.find_or_create(:host => @server, :port => @port)
44
46
  server.connected = true
45
47
  server.save
46
- @sendq = Queue.new
47
48
  Logger.log("Created new send queue: #{@sendq}", 10)
48
- spooler
49
49
  reader
50
50
  end
51
51
 
@@ -80,12 +80,12 @@ module ModSpox
80
80
  # Sends a string to the IRC server
81
81
  def write(message)
82
82
  return if message.nil?
83
+ @socket.puts(message + "\n") #send(message + "\n", 0)
83
84
  Logger.log("<< #{message}", 5)
84
- @socket.send(message + "\n", 0)
85
85
  @last_send = Time.new
86
86
  @sent += 1
87
87
  @check_burst += 1
88
- @check_time = Time.now.to_i if @check_time.nil?
88
+ @time_check = Time.now.to_i if @time_check.nil?
89
89
  end
90
90
 
91
91
  # Retrieves a string from the server
@@ -96,7 +96,7 @@ module ModSpox
96
96
  # Retrieves a string from the server
97
97
  def read
98
98
  message = @socket.gets
99
- if(message.nil?)
99
+ if(message.nil?) # || message =~ /^ERROR/)
100
100
  @pipeline << Messages::Internal::Disconnected.new
101
101
  shutdown
102
102
  server = Models::Server.find_or_create(:host => @server, :port => @port)
@@ -109,60 +109,46 @@ module ModSpox
109
109
  message.strip!
110
110
  return message
111
111
  end
112
-
112
+
113
113
  # message:: String to be sent to server
114
114
  # Queues a message up to be sent to the IRC server
115
115
  def <<(message)
116
- queue(message)
117
- end
118
-
119
- # message:: String to be sent to server
120
- # Queues a message up to be sent to the IRC server
121
- def queue(message)
122
116
  @sendq << message
123
117
  end
124
118
 
125
119
  # Starts the thread for sending messages to the server
126
- def spooler
127
- @writer_thread = Thread.new{
128
- until @kill do
129
- write(@sendq.pop)
130
- if((Time.now.to_i - @check_time) > @burst_in)
131
- @check_time = nil
132
- @check_burst = 0
133
- elsif((Time.now.to_i - @check_time) >= @burst_in && @check_burst >= @burst)
134
- sleep(@delay)
135
- @check_time = nil
136
- @check_burst = 0
137
- end
138
- end
139
- }
120
+ def processor
121
+ write(@sendq.pop)
122
+ if((Time.now.to_i - @time_check) > @burst_in)
123
+ @time_check = nil
124
+ @check_burst = 0
125
+ elsif((Time.now.to_i - @time_check) >= @burst_in && @check_burst >= @burst)
126
+ sleep(@delay)
127
+ @time_check = nil
128
+ @check_burst = 0
129
+ end
140
130
  end
141
131
 
142
132
  # Starts the thread for reading messages from the server
143
133
  def reader
144
- @reader_thread = Thread.new{
134
+ @reader_thread = Thread.new do
145
135
  until @kill do
146
136
  Kernel.select([@socket], nil, nil, nil)
147
137
  @factory << read
148
138
  end
149
- }
139
+ end
150
140
  end
151
141
 
152
142
  # restart:: Reconnect after closing connection
153
143
  # Closes connection to IRC server
154
144
  def shutdown(restart=false)
145
+ @socket.close unless @socket.closed?
155
146
  @kill = true
156
- @reader_thread.join(0.1)
157
- @reader_thread.kill if @reader_thread.alive?
158
- @writer_thread.join(0.1)
159
- @writer_thread.kill if @writer_thread.alive?
160
- @reader_thread = nil
161
- @writer_thread = nil
162
- @socket.close
163
147
  server = Models::Server.find_or_create(:host => @server, :port => @port)
164
148
  server.connected = false
165
149
  server.save
150
+ sleep(0.1)
151
+ @reader_thread.kill if @reader_thread.alive?
166
152
  connect if restart
167
153
  end
168
154
 
@@ -31,11 +31,11 @@ module ModSpox
31
31
  Logger.log("New block is being added to the timer", 15)
32
32
  action = add(message.period, message.once, message.data, &message.block)
33
33
  begin
34
- @pipeline << Messages::Internal::TimerResponse.new(message.requester, action, true)
34
+ @pipeline << Messages::Internal::TimerResponse.new(message.requester, action, true, message.id)
35
35
  Logger.log("New block was successfully added to the timer", 15)
36
36
  rescue Object => boom
37
37
  Logger.log("Failed to add block to timer: #{boom}", 10)
38
- @pipeline << Messages::Internal::TimerResponse.new(message.requester, action, false)
38
+ @pipeline << Messages::Internal::TimerResponse.new(message.requester, action, false, message.id)
39
39
  end
40
40
  end
41
41
 
@@ -44,7 +44,7 @@ module ModSpox
44
44
  def remove_message(message)
45
45
  remove(message.action)
46
46
  Logger.log("Action has been removed from the Timer", 15)
47
- @pipeline << Messages::Internal::TimerResponse.new(nil, message.action, false)
47
+ @pipeline << Messages::Internal::TimerResponse.new(nil, message.action, false, message.id)
48
48
  end
49
49
 
50
50
  # period:: seconds between running action
@@ -6,7 +6,7 @@ module ModSpox
6
6
  end
7
7
  def process(string)
8
8
  if(string =~ /#{RPL_CREATED.to_s}.+?:created\s(.+)$/)
9
- return Messages::Incoming::Created(string, $1)
9
+ return Messages::Incoming::Created.new(string, $1)
10
10
  else
11
11
  Logger.log('Failed to parse RPL_CREATED message')
12
12
  end
@@ -10,19 +10,7 @@ module ModSpox
10
10
  protected
11
11
 
12
12
  def find_model(string)
13
- if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
14
- Logger.log("Model: #{string} -> Nick")
15
- return Models::Nick.find_or_create(:nick => string)
16
- elsif(string =~ /^[&#+!]/)
17
- Logger.log("Model: #{string} -> Channel")
18
- return Models::Channel.find_or_create(:name => string)
19
- elsif(model = Models::Server.filter(:host => string, :connected => true).first)
20
- Logger.log("Model: #{string} -> Server")
21
- return model
22
- else
23
- Logger.log("FAIL Model: #{string} -> No match")
24
- return string
25
- end
13
+ Helpers.find_model(string)
26
14
  end
27
15
 
28
16
  end
@@ -9,7 +9,7 @@ module ModSpox
9
9
  source = find_model($1)
10
10
  target = find_model($2)
11
11
  channel = find_model($3)
12
- return Messages::Incoming::Invite(string, source, target, channel)
12
+ return Messages::Incoming::Invite.new(string, source, target, channel)
13
13
  else
14
14
  Logger.log('Failed to parse INVITE message')
15
15
  end
@@ -6,7 +6,7 @@ module ModSpox
6
6
  end
7
7
  def process(string)
8
8
  if(string =~ /(\d+) :.*?\s*[oO]perators/)
9
- return Messages::Incoming::LuserOp(string, $1.to_i)
9
+ return Messages::Incoming::LuserOp.new(string, $1.to_i)
10
10
  else
11
11
  Logger.log('Failed to match RPL_LUSEROP message')
12
12
  end
@@ -6,7 +6,7 @@ module ModSpox
6
6
  end
7
7
  def process(string)
8
8
  if(string =~ /(\d+) :.*[Uu]nknown/)
9
- return Messages::Incoming::LuserUnknown(string, $1.to_i)
9
+ return Messages::Incoming::LuserUnknown.new(string, $1.to_i)
10
10
  else
11
11
  Logger.log('Failed to match RPL_LUSERUNKNOWN message')
12
12
  end
@@ -10,6 +10,8 @@ module ModSpox
10
10
  attr_reader :period
11
11
  # only execute block once
12
12
  attr_reader :once
13
+ # message identification
14
+ attr_reader :ident
13
15
  # period:: interval between executions
14
16
  # once:: only run block once
15
17
  # block:: code block
@@ -20,6 +22,12 @@ module ModSpox
20
22
  @period = period
21
23
  @once = once
22
24
  @block = block
25
+ @ident = rand(99999999)
26
+ end
27
+
28
+ # Message ID
29
+ def id
30
+ @ident
23
31
  end
24
32
  end
25
33
  end