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.
- data/CHANGELOG +38 -0
- data/INSTALL +5 -2
- data/bin/mod_spox +7 -3
- data/data/mod_spox/extras/Confess.rb +4 -4
- data/data/mod_spox/extras/Karma.rb +2 -2
- data/data/mod_spox/extras/Logger.rb +167 -0
- data/data/mod_spox/extras/Quotes.rb +2 -2
- data/data/mod_spox/extras/Roulette.rb +34 -16
- data/data/mod_spox/extras/Topten.rb +105 -0
- data/data/mod_spox/plugins/Authenticator.rb +2 -2
- data/data/mod_spox/plugins/Banner.rb +10 -10
- data/data/mod_spox/plugins/Initializer.rb +1 -1
- data/data/mod_spox/plugins/Triggers.rb +3 -3
- data/lib/mod_spox/Bot.rb +6 -5
- data/lib/mod_spox/BotConfig.rb +1 -1
- data/lib/mod_spox/ConfigurationWizard.rb +18 -17
- data/lib/mod_spox/Database.rb +9 -0
- data/lib/mod_spox/Helpers.rb +49 -0
- data/lib/mod_spox/Loader.rb +11 -0
- data/lib/mod_spox/PluginManager.rb +1 -0
- data/lib/mod_spox/Pool.rb +23 -107
- data/lib/mod_spox/Socket.rb +23 -37
- data/lib/mod_spox/Timer.rb +3 -3
- data/lib/mod_spox/handlers/Created.rb +1 -1
- data/lib/mod_spox/handlers/Handler.rb +1 -13
- data/lib/mod_spox/handlers/Invite.rb +1 -1
- data/lib/mod_spox/handlers/LuserOp.rb +1 -1
- data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
- data/lib/mod_spox/messages/internal/TimerAdd.rb +8 -0
- data/lib/mod_spox/messages/internal/TimerRemove.rb +8 -0
- data/lib/mod_spox/messages/internal/TimerResponse.rb +8 -1
- data/lib/mod_spox/models/Auth.rb +4 -4
- data/lib/mod_spox/models/Channel.rb +11 -0
- data/lib/mod_spox/models/Nick.rb +22 -11
- data/lib/mod_spox/models/Setting.rb +2 -2
- data/lib/mod_spox/models/Signature.rb +11 -2
- 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
|
-
|
47
|
+
@waiter.wait
|
47
48
|
rescue Object => boom
|
48
49
|
Logger.log("Caught exception: #{boom}")
|
49
50
|
end
|
data/lib/mod_spox/BotConfig.rb
CHANGED
@@ -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::
|
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
|
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
|
152
|
-
Database.db << "CREATE
|
153
|
-
Database.db << "CREATE TABLE channels (id serial not null primary key, name
|
154
|
-
Database.db << "CREATE TABLE auths (id serial not null primary key, password
|
155
|
-
Database.db << "CREATE TABLE groups (id serial not null primary key, name
|
156
|
-
Database.db << "CREATE TABLE channel_modes (id serial not null primary key, mode
|
157
|
-
Database.db << "CREATE TABLE configs (id serial not null primary key, name
|
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
|
160
|
-
Database.db << "CREATE TABLE servers (id serial not null primary key, host
|
161
|
-
Database.db << "CREATE TABLE signatures (id serial not null primary key, signature
|
162
|
-
Database.db << "CREATE TABLE settings (id serial not null primary key, name
|
163
|
-
Database.db << "CREATE TABLE triggers (id serial not null primary key, trigger
|
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
|
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)"
|
data/lib/mod_spox/Database.rb
CHANGED
@@ -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
|
data/lib/mod_spox/Helpers.rb
CHANGED
@@ -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
|
data/lib/mod_spox/Loader.rb
CHANGED
@@ -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],
|
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 =
|
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
|
-
@@
|
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
|
-
|
85
|
-
|
86
|
-
|
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
|
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
|
-
|
128
|
-
|
129
|
-
|
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
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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
|
-
|
90
|
+
end
|
166
91
|
end
|
167
92
|
|
168
93
|
# Forces sleeping threads to wake up
|
169
|
-
def Pool.
|
170
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
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.
|
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.
|
131
|
+
Pool.process
|
216
132
|
end
|
217
133
|
end
|
218
134
|
|
data/lib/mod_spox/Socket.rb
CHANGED
@@ -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
|
-
@
|
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
|
127
|
-
@
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
|
data/lib/mod_spox/Timer.rb
CHANGED
@@ -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
|
-
|
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
|