tkellem 0.8.11 → 0.9.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +9 -0
- data/lib/tkellem/bouncer.rb +50 -15
- data/lib/tkellem/bouncer_connection.rb +46 -60
- data/lib/tkellem/celluloid_tools.rb +131 -0
- data/lib/tkellem/daemon.rb +3 -7
- data/lib/tkellem/irc_message.rb +1 -1
- data/lib/tkellem/migrations/001_init_db.rb +39 -22
- data/lib/tkellem/migrations/002_at_connect_columns.rb +21 -4
- data/lib/tkellem/migrations/003_settings.rb +18 -9
- data/lib/tkellem/models/host.rb +2 -2
- data/lib/tkellem/models/listen_address.rb +13 -1
- data/lib/tkellem/models/network.rb +11 -7
- data/lib/tkellem/models/network_user.rb +22 -6
- data/lib/tkellem/models/setting.rb +3 -3
- data/lib/tkellem/models/user.rb +13 -6
- data/lib/tkellem/plugins/backlog.rb +45 -27
- data/lib/tkellem/socket_server.rb +15 -7
- data/lib/tkellem/tkellem_bot.rb +11 -19
- data/lib/tkellem/tkellem_server.rb +84 -61
- data/lib/tkellem/version.rb +1 -1
- data/lib/tkellem.rb +1 -10
- data/spec/spec_helper.rb +5 -18
- data/tkellem.gemspec +6 -4
- metadata +56 -28
- data/lib/tkellem/irc_server.rb +0 -124
- data/spec/bouncer_connection_spec.rb +0 -37
- data/spec/irc_server_spec.rb +0 -145
@@ -1,20 +1,24 @@
|
|
1
1
|
module Tkellem
|
2
2
|
|
3
|
-
class Network <
|
4
|
-
|
5
|
-
|
3
|
+
class Network < Sequel::Model
|
4
|
+
plugin :nested_attributes
|
5
|
+
plugin :validation_class_methods
|
6
|
+
plugin :serialization
|
6
7
|
|
7
|
-
|
8
|
+
one_to_many :hosts, :dependent => :destroy
|
9
|
+
nested_attributes :hosts
|
10
|
+
|
11
|
+
one_to_many :network_users, :dependent => :destroy
|
8
12
|
# networks either belong to a specific user, or they are public and any user
|
9
13
|
# can join them.
|
10
|
-
|
14
|
+
many_to_one :user
|
11
15
|
|
12
16
|
validates_uniqueness_of :name, :scope => :user_id
|
13
17
|
|
14
|
-
|
18
|
+
serialize_attributes :yaml, :at_connect
|
15
19
|
|
16
20
|
def at_connect
|
17
|
-
|
21
|
+
super || []
|
18
22
|
end
|
19
23
|
|
20
24
|
def public?
|
@@ -1,17 +1,33 @@
|
|
1
1
|
module Tkellem
|
2
2
|
|
3
|
-
class NetworkUser <
|
4
|
-
|
5
|
-
belongs_to :user
|
3
|
+
class NetworkUser < Sequel::Model
|
4
|
+
plugin :serialization
|
6
5
|
|
7
|
-
|
6
|
+
many_to_one :network
|
7
|
+
many_to_one :user
|
8
|
+
|
9
|
+
serialize_attributes :yaml, :at_connect
|
10
|
+
|
11
|
+
def at_connect
|
12
|
+
super || []
|
13
|
+
end
|
8
14
|
|
9
15
|
def nick
|
10
|
-
|
16
|
+
super || user.name
|
11
17
|
end
|
12
18
|
|
13
19
|
def combined_at_connect
|
14
|
-
network.at_connect +
|
20
|
+
network.at_connect + at_connect
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_create
|
24
|
+
super
|
25
|
+
$tkellem_server.try(:after_create, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def after_destroy
|
29
|
+
super
|
30
|
+
$tkellem_server.try(:after_destroy, self)
|
15
31
|
end
|
16
32
|
end
|
17
33
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Tkellem
|
2
2
|
|
3
|
-
class Setting <
|
3
|
+
class Setting < Sequel::Model
|
4
4
|
def self.get(setting_name)
|
5
|
-
setting =
|
5
|
+
setting = where(:name => setting_name).first
|
6
6
|
setting.try(:value)
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.set(setting_name, new_value)
|
10
|
-
setting =
|
10
|
+
setting = where(:name => setting_name).first
|
11
11
|
setting.try(:update_attributes, :value => new_value.to_s, :unchanged => false)
|
12
12
|
setting
|
13
13
|
end
|
data/lib/tkellem/models/user.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
module Tkellem
|
2
2
|
|
3
|
-
class User <
|
4
|
-
|
5
|
-
|
3
|
+
class User < Sequel::Model
|
4
|
+
plugin :validation_class_methods
|
5
|
+
|
6
|
+
one_to_many :network_users, :dependent => :destroy
|
7
|
+
one_to_many :networks, :dependent => :destroy
|
6
8
|
|
7
9
|
validates_presence_of :username
|
8
10
|
validates_uniqueness_of :username
|
9
11
|
validates_presence_of :role, :in => %w(user admin)
|
10
12
|
|
13
|
+
def before_validation
|
14
|
+
self.role ||= 'user'
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
11
18
|
# pluggable authentication -- add your own block, which takes |username, password|
|
12
19
|
# parameters. Return a User object if authentication succeeded, or a
|
13
20
|
# false/nil value if auth failed. You can create the user on-the-fly if
|
@@ -18,7 +25,7 @@ class User < ActiveRecord::Base
|
|
18
25
|
# default database-based authentication
|
19
26
|
# TODO: proper password hashing
|
20
27
|
self.authentication_methods << proc do |username, password|
|
21
|
-
user =
|
28
|
+
user = first(:username => username)
|
22
29
|
user && user.valid_password?(password) && user
|
23
30
|
end
|
24
31
|
|
@@ -31,7 +38,7 @@ class User < ActiveRecord::Base
|
|
31
38
|
end
|
32
39
|
|
33
40
|
def username=(val)
|
34
|
-
|
41
|
+
super(val.try(:downcase))
|
35
42
|
end
|
36
43
|
|
37
44
|
def name
|
@@ -44,7 +51,7 @@ class User < ActiveRecord::Base
|
|
44
51
|
end
|
45
52
|
|
46
53
|
def password=(password)
|
47
|
-
|
54
|
+
super(password ? OpenSSL::Digest::SHA1.hexdigest(password) : nil)
|
48
55
|
end
|
49
56
|
|
50
57
|
def admin?
|
@@ -15,9 +15,11 @@ module Tkellem
|
|
15
15
|
# different backlog implementation. Right now, it's always loaded though.
|
16
16
|
class Backlog
|
17
17
|
include Tkellem::EasyLogger
|
18
|
+
include Celluloid
|
19
|
+
|
20
|
+
cattr_accessor :replay_pool
|
18
21
|
|
19
22
|
Bouncer.add_plugin(self)
|
20
|
-
cattr_accessor :instances
|
21
23
|
|
22
24
|
def self.get_instance(bouncer)
|
23
25
|
bouncer.data(self)[:instance] ||= self.new(bouncer)
|
@@ -57,7 +59,7 @@ class Backlog
|
|
57
59
|
# open stream in append-only mode
|
58
60
|
return @streams[ctx] if @streams[ctx]
|
59
61
|
stream = @streams[ctx] = File.open(stream_filename(ctx), 'ab')
|
60
|
-
stream.seek(0, IO::SEEK_END)
|
62
|
+
stream.seek(0, ::IO::SEEK_END)
|
61
63
|
@starting_pos[ctx] = stream.pos
|
62
64
|
stream
|
63
65
|
end
|
@@ -98,7 +100,7 @@ class Backlog
|
|
98
100
|
ctx = msg.prefix.split(/[!~@]/, 2).first
|
99
101
|
end
|
100
102
|
stream = get_stream(ctx)
|
101
|
-
stream.puts(Time.now.strftime("%d-%m-%Y %H:%M:%S < #{'* ' if msg.action?}#{msg.prefix}: #{msg.args.last}")
|
103
|
+
stream.puts(Time.now.strftime("%d-%m-%Y %H:%M:%S") + " < #{'* ' if msg.action?}#{msg.prefix}: #{msg.args.last}")
|
102
104
|
update_pos(ctx, stream.pos)
|
103
105
|
end
|
104
106
|
end
|
@@ -109,39 +111,53 @@ class Backlog
|
|
109
111
|
return if msg.ctcp? && !msg.action?
|
110
112
|
ctx = msg.args.first
|
111
113
|
stream = get_stream(ctx)
|
112
|
-
stream.puts(Time.now.strftime("%d-%m-%Y %H:%M:%S > #{'* ' if msg.action?}#{msg.args.last}")
|
114
|
+
stream.puts(Time.now.strftime("%d-%m-%Y %H:%M:%S") + " > #{'* ' if msg.action?}#{msg.args.last}")
|
113
115
|
update_pos(ctx, stream.pos)
|
114
116
|
end
|
115
117
|
end
|
116
118
|
|
117
119
|
def send_backlog(conn, device)
|
118
120
|
device.each do |ctx_name, pos|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
121
|
+
filename = stream_filename(ctx_name)
|
122
|
+
Backlog.replay_pool.async(:replay, filename, pos, @bouncer, conn, ctx_name)
|
123
|
+
device[ctx_name] = get_stream(ctx_name).pos
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class BacklogReplay
|
129
|
+
include Celluloid
|
130
|
+
|
131
|
+
def replay(filename, pos, bouncer, conn, ctx_name)
|
132
|
+
stream = File.open(filename, 'rb')
|
133
|
+
stream.seek(pos)
|
134
|
+
|
135
|
+
while line = stream.gets
|
136
|
+
timestamp, msg = parse_line(line, ctx_name)
|
137
|
+
next unless msg
|
138
|
+
privmsg = msg.args.first[0] != '#'[0]
|
139
|
+
if msg.prefix
|
140
|
+
# to this user
|
141
|
+
if privmsg
|
142
|
+
msg.args[0] = bouncer.nick
|
127
143
|
else
|
128
|
-
#
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
144
|
+
# do nothing, it's good to send
|
145
|
+
end
|
146
|
+
else
|
147
|
+
# from this user, maybe add prefix
|
148
|
+
if privmsg
|
149
|
+
# a one-on-one chat -- every client i've seen doesn't know how to
|
150
|
+
# display messages from themselves here, so we fake it by just
|
151
|
+
# adding an arrow and pretending the other user said it. shame.
|
152
|
+
msg.prefix = msg.args.first
|
153
|
+
msg.args[0] = bouncer.nick
|
154
|
+
msg.args[-1] = "-> #{msg.args.last}"
|
155
|
+
else
|
156
|
+
# it's a room, we can just replay
|
157
|
+
msg.prefix = bouncer.nick
|
140
158
|
end
|
141
|
-
conn.send_msg(msg.with_timestamp(timestamp))
|
142
159
|
end
|
143
|
-
|
144
|
-
device[ctx_name] = get_stream(ctx_name).pos
|
160
|
+
conn.send_msg(msg.with_timestamp(timestamp))
|
145
161
|
end
|
146
162
|
end
|
147
163
|
|
@@ -166,4 +182,6 @@ class Backlog
|
|
166
182
|
end
|
167
183
|
end
|
168
184
|
|
185
|
+
Backlog.replay_pool = BacklogReplay.pool(size: Celluloid.cores * 2)
|
186
|
+
|
169
187
|
end
|
@@ -1,26 +1,30 @@
|
|
1
|
-
require '
|
1
|
+
require 'celluloid/io'
|
2
2
|
|
3
3
|
require 'tkellem/tkellem_bot'
|
4
4
|
|
5
5
|
module Tkellem
|
6
6
|
|
7
7
|
# listens on the unix domain socket and executes admin commands
|
8
|
-
|
9
|
-
|
8
|
+
# TODO: rename this class
|
9
|
+
class SocketServer
|
10
|
+
include Celluloid::IO
|
10
11
|
include Tkellem::EasyLogger
|
12
|
+
include Tkellem::CelluloidTools::LineReader
|
11
13
|
|
12
14
|
def log_name
|
13
15
|
"admin"
|
14
16
|
end
|
15
17
|
|
16
|
-
def
|
17
|
-
|
18
|
+
def initialize(socket)
|
19
|
+
@socket = socket
|
20
|
+
@delimiter = "\n"
|
21
|
+
run!
|
18
22
|
end
|
19
23
|
|
20
24
|
def receive_line(line)
|
21
25
|
trace "admin socket: #{line}"
|
22
|
-
TkellemBot.run_command(line, nil, nil) do |
|
23
|
-
send_data("#{
|
26
|
+
TkellemBot.run_command(line, nil, nil) do |outline|
|
27
|
+
send_data("#{outline}\n")
|
24
28
|
end
|
25
29
|
send_data("\0\n")
|
26
30
|
rescue => e
|
@@ -28,6 +32,10 @@ module SocketServer
|
|
28
32
|
e.backtrace.each { |l| send_data("#{l}\n") }
|
29
33
|
send_data("\0\n")
|
30
34
|
end
|
35
|
+
|
36
|
+
def send_data(dat)
|
37
|
+
@socket.write(dat)
|
38
|
+
end
|
31
39
|
end
|
32
40
|
|
33
41
|
end
|
data/lib/tkellem/tkellem_bot.rb
CHANGED
@@ -156,7 +156,7 @@ class TkellemBot
|
|
156
156
|
end
|
157
157
|
|
158
158
|
def modify
|
159
|
-
instance = model.first(
|
159
|
+
instance = model.first(find_attributes)
|
160
160
|
new_record = false
|
161
161
|
if instance
|
162
162
|
instance.attributes = attributes
|
@@ -181,7 +181,7 @@ class TkellemBot
|
|
181
181
|
end
|
182
182
|
|
183
183
|
def remove
|
184
|
-
instance = model.first(
|
184
|
+
instance = model.first(find_attributes)
|
185
185
|
if instance
|
186
186
|
instance.destroy
|
187
187
|
respond "Removed #{show(instance)}"
|
@@ -258,7 +258,7 @@ class TkellemBot
|
|
258
258
|
|
259
259
|
if opts['username']
|
260
260
|
if Command.admin_user?(user)
|
261
|
-
user = User.
|
261
|
+
user = User.where(:username => opts['username']).first
|
262
262
|
else
|
263
263
|
raise Command::ArgumentError, "Only admins can change other passwords"
|
264
264
|
end
|
@@ -303,7 +303,7 @@ class TkellemBot
|
|
303
303
|
|
304
304
|
def execute
|
305
305
|
if opts['network'].present? # only settable by admins
|
306
|
-
target = Network.
|
306
|
+
target = Network.where(:user_id => nil, :name => opts['network'].downcase).first
|
307
307
|
else
|
308
308
|
target = network_user
|
309
309
|
end
|
@@ -339,7 +339,7 @@ class TkellemBot
|
|
339
339
|
admin_option('public', '--public', "Create new public network. Once created, public/private status can't be modified.")
|
340
340
|
|
341
341
|
def list
|
342
|
-
public_networks = Network.
|
342
|
+
public_networks = Network.where(:user_id => nil).all
|
343
343
|
user_networks = user.try(:reload).try(:networks) || []
|
344
344
|
if user_networks.present? && public_networks.present?
|
345
345
|
r "Public networks are prefixed with [P], user-specific networks with [U]."
|
@@ -355,15 +355,14 @@ class TkellemBot
|
|
355
355
|
end
|
356
356
|
|
357
357
|
def execute
|
358
|
-
# TODO: this got gross
|
359
358
|
if args.empty? && !opts['remove']
|
360
359
|
list
|
361
360
|
return
|
362
361
|
end
|
363
362
|
|
364
363
|
if opts['network'].present?
|
365
|
-
target = Network.
|
366
|
-
target ||= Network.
|
364
|
+
target = Network.where(:name => opts['network'].downcase, :user_id => user.try(:id)).first
|
365
|
+
target ||= Network.where(:user_id => nil, :name => opts['network'].downcase).first if self.class.admin_user?(user)
|
367
366
|
else
|
368
367
|
target = network_user.try(:network)
|
369
368
|
if target && target.public? && !self.class.admin_user?(user)
|
@@ -379,7 +378,7 @@ class TkellemBot
|
|
379
378
|
raise(Command::ArgumentError, "No network found") unless target
|
380
379
|
raise(Command::ArgumentError, "You must explicitly specify the network to remove") unless opts['network']
|
381
380
|
if uri
|
382
|
-
target.hosts.
|
381
|
+
target.hosts.where(addr_args).first.try(:destroy)
|
383
382
|
respond " #{show(target)}"
|
384
383
|
else
|
385
384
|
target.destroy
|
@@ -397,16 +396,9 @@ class TkellemBot
|
|
397
396
|
end
|
398
397
|
end
|
399
398
|
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
respond "Error:"
|
404
|
-
target.errors.full_messages.each { |m| respond " #{m}" }
|
405
|
-
respond " #{show(target)}"
|
406
|
-
else
|
407
|
-
respond("updated:")
|
408
|
-
respond " #{show(target)}"
|
409
|
-
end
|
399
|
+
Host.create(addr_args.merge(network: target))
|
400
|
+
respond("updated:")
|
401
|
+
respond " #{show(target)}"
|
410
402
|
end
|
411
403
|
end
|
412
404
|
end
|
@@ -1,46 +1,62 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'celluloid'
|
3
|
+
require 'sequel'
|
3
4
|
|
4
|
-
require 'tkellem/bouncer_connection'
|
5
5
|
require 'tkellem/bouncer'
|
6
|
-
|
7
|
-
require 'tkellem/
|
8
|
-
require 'tkellem/models/listen_address'
|
9
|
-
require 'tkellem/models/network'
|
10
|
-
require 'tkellem/models/network_user'
|
11
|
-
require 'tkellem/models/setting'
|
12
|
-
require 'tkellem/models/user'
|
6
|
+
require 'tkellem/bouncer_connection'
|
7
|
+
require 'tkellem/celluloid_tools'
|
13
8
|
|
14
9
|
require 'tkellem/plugins/backlog'
|
15
|
-
require 'tkellem/plugins/push_service'
|
10
|
+
#require 'tkellem/plugins/push_service'
|
16
11
|
|
17
12
|
module Tkellem
|
18
13
|
|
19
14
|
class TkellemServer
|
15
|
+
include Celluloid
|
20
16
|
include Tkellem::EasyLogger
|
21
17
|
|
22
|
-
attr_reader :bouncers
|
18
|
+
attr_reader :bouncers, :options
|
19
|
+
|
20
|
+
def self.initialize_database(path)
|
21
|
+
Sequel.extension :migration
|
22
|
+
db = Sequel.connect({
|
23
|
+
:adapter => 'sqlite',
|
24
|
+
:database => path,
|
25
|
+
})
|
26
|
+
migrations_path = File.expand_path("../migrations", __FILE__)
|
27
|
+
Sequel::Migrator.apply(db, migrations_path)
|
28
|
+
|
29
|
+
Sequel::Model.raise_on_save_failure = true
|
30
|
+
# Can't load the models until we've connected to the database and migrated
|
31
|
+
require 'tkellem/models/host'
|
32
|
+
require 'tkellem/models/listen_address'
|
33
|
+
require 'tkellem/models/network'
|
34
|
+
require 'tkellem/models/network_user'
|
35
|
+
require 'tkellem/models/setting'
|
36
|
+
require 'tkellem/models/user'
|
37
|
+
|
38
|
+
db
|
39
|
+
end
|
23
40
|
|
24
|
-
def initialize
|
41
|
+
def initialize(options)
|
42
|
+
Celluloid.logger = Tkellem::EasyLogger.logger
|
43
|
+
@options = options
|
25
44
|
@listeners = {}
|
26
|
-
@bouncers = {}
|
45
|
+
@bouncers = CelluloidTools::BackoffSupervisor.new_link({})
|
27
46
|
$tkellem_server = self
|
28
47
|
|
29
|
-
|
30
|
-
ActiveRecord::Base.establish_connection({
|
31
|
-
:adapter => 'sqlite3',
|
32
|
-
:database => File.expand_path("~/.tkellem/tkellem.sqlite3"),
|
33
|
-
})
|
34
|
-
ActiveRecord::Migrator.migrate(File.expand_path("../migrations", __FILE__), nil)
|
35
|
-
end
|
36
|
-
|
37
|
-
ListenAddress.all.each { |a| listen(a) }
|
38
|
-
NetworkUser.find_each { |nu| add_bouncer(Bouncer.new(nu)) }
|
39
|
-
Observer.forward_to << self
|
48
|
+
@db = self.class.initialize_database(db_file)
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
43
|
-
|
51
|
+
def run
|
52
|
+
start_unix_server
|
53
|
+
ListenAddress.all { |a| listen(a) }
|
54
|
+
NetworkUser.all { |nu| add_bouncer(nu) }
|
55
|
+
|
56
|
+
begin
|
57
|
+
loop { sleep 5 }
|
58
|
+
rescue Interrupt
|
59
|
+
end
|
44
60
|
end
|
45
61
|
|
46
62
|
# callbacks for AR observer events
|
@@ -49,7 +65,7 @@ class TkellemServer
|
|
49
65
|
when ListenAddress
|
50
66
|
listen(obj)
|
51
67
|
when NetworkUser
|
52
|
-
add_bouncer(
|
68
|
+
add_bouncer(obj)
|
53
69
|
end
|
54
70
|
end
|
55
71
|
|
@@ -57,68 +73,75 @@ class TkellemServer
|
|
57
73
|
case obj
|
58
74
|
when ListenAddress
|
59
75
|
stop_listening(obj)
|
60
|
-
# TODO: remove bouncer on NetworkUser.destroy
|
61
76
|
end
|
62
77
|
end
|
63
78
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
79
|
+
def start_unix_server
|
80
|
+
# This file relies on the models being loaded
|
81
|
+
# TODO: this is gross
|
82
|
+
require 'tkellem/socket_server'
|
83
|
+
CelluloidTools::UnixListener.start(socket_file) do |socket|
|
84
|
+
SocketServer.new(socket)
|
85
|
+
end
|
86
|
+
end
|
68
87
|
|
88
|
+
def listen(listen_address)
|
69
89
|
info "Listening on #{listen_address}"
|
70
90
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
91
|
+
if listen_address.ssl
|
92
|
+
server_class = CelluloidTools::SSLListener
|
93
|
+
else
|
94
|
+
server_class = CelluloidTools::TCPListener
|
95
|
+
end
|
96
|
+
|
97
|
+
listener = server_class.start(listen_address.address,
|
98
|
+
listen_address.port) do |socket|
|
99
|
+
BouncerConnection.new(self, socket).async.run
|
100
|
+
end
|
101
|
+
|
102
|
+
@listeners[listen_address.id] = listener
|
76
103
|
end
|
77
104
|
|
78
105
|
def stop_listening(listen_address)
|
79
106
|
listener = @listeners[listen_address.id]
|
80
107
|
return unless listener
|
81
|
-
|
108
|
+
listener.terminate
|
82
109
|
info "No longer listening on #{listen_address}"
|
83
110
|
end
|
84
111
|
|
85
|
-
def add_bouncer(
|
86
|
-
|
87
|
-
|
88
|
-
|
112
|
+
def add_bouncer(network_user)
|
113
|
+
unless network_user.user && network_user.network
|
114
|
+
info "Terminating orphan network user #{network_user}"
|
115
|
+
network_user.destroy
|
116
|
+
return
|
117
|
+
end
|
118
|
+
key = [network_user.user_id, network_user.network.name]
|
119
|
+
raise("bouncer already exists: #{key}") if @bouncers.registry.key?(key)
|
120
|
+
@bouncers.supervise_as(key, Bouncer, network_user)
|
89
121
|
end
|
90
122
|
|
91
123
|
def find_bouncer(user, network_name)
|
92
124
|
key = [user.id, network_name]
|
93
|
-
bouncer = @bouncers[key]
|
125
|
+
bouncer = @bouncers.registry[key]
|
94
126
|
if !bouncer
|
95
127
|
# find the public network with this name, and attempt to auto-add this user to it
|
96
|
-
network = Network.first(
|
128
|
+
network = Network.first({ :user_id => nil, :name => network_name })
|
97
129
|
if network
|
98
|
-
|
130
|
+
NetworkUser.create(:user => user, :network => network)
|
99
131
|
# AR callback should create the bouncer in sync
|
100
|
-
bouncer = @bouncers[key]
|
132
|
+
bouncer = @bouncers.registry[key]
|
101
133
|
end
|
102
134
|
end
|
103
135
|
bouncer
|
104
136
|
end
|
105
137
|
|
106
|
-
|
107
|
-
|
108
|
-
cattr_accessor :forward_to
|
109
|
-
self.forward_to = []
|
110
|
-
|
111
|
-
def after_create(obj)
|
112
|
-
forward_to.each { |f| f.after_create(obj) }
|
113
|
-
end
|
114
|
-
|
115
|
-
def after_destroy(obj)
|
116
|
-
forward_to.each { |f| f.after_destroy(obj) }
|
117
|
-
end
|
138
|
+
def socket_file
|
139
|
+
File.join(options[:path], 'tkellem.socket')
|
118
140
|
end
|
119
141
|
|
120
|
-
|
121
|
-
|
142
|
+
def db_file
|
143
|
+
File.join(options[:path], 'tkellem.sqlite3')
|
144
|
+
end
|
122
145
|
end
|
123
146
|
|
124
147
|
end
|
data/lib/tkellem/version.rb
CHANGED
data/lib/tkellem.rb
CHANGED
@@ -21,7 +21,7 @@ module Tkellem
|
|
21
21
|
@trace = val
|
22
22
|
end
|
23
23
|
def self.trace
|
24
|
-
@trace || @trace =
|
24
|
+
@trace || @trace = true
|
25
25
|
end
|
26
26
|
|
27
27
|
def log_name
|
@@ -32,15 +32,6 @@ module Tkellem
|
|
32
32
|
puts("TRACE: #{log_name}: #{msg}") if EasyLogger.trace
|
33
33
|
end
|
34
34
|
|
35
|
-
def failsafe(event)
|
36
|
-
yield
|
37
|
-
rescue => e
|
38
|
-
# if the failsafe rescue fails, we're in a really bad state and should probably just die
|
39
|
-
self.error "exception while handling #{event}"
|
40
|
-
self.error e.to_s
|
41
|
-
(e.backtrace || []).each { |line| self.error line }
|
42
|
-
end
|
43
|
-
|
44
35
|
::Logger::Severity.constants.each do |level|
|
45
36
|
next if level == "UNKNOWN"
|
46
37
|
module_eval(<<-EVAL, __FILE__, __LINE__)
|
data/spec/spec_helper.rb
CHANGED
@@ -5,30 +5,17 @@ require 'tkellem'
|
|
5
5
|
require 'rspec'
|
6
6
|
|
7
7
|
Tkellem::EasyLogger.logger = Logger.new("test.log")
|
8
|
-
ActiveRecord::Base.logger = Tkellem::EasyLogger.logger
|
9
8
|
|
10
|
-
|
11
|
-
ActiveRecord::Migration.verbose = false
|
12
|
-
ActiveRecord::Migrator.migrate(File.expand_path("../../lib/tkellem/migrations", __FILE__), nil)
|
9
|
+
TestDB = Tkellem::TkellemServer.initialize_database(':memory:')
|
13
10
|
|
14
11
|
RSpec.configure do |config|
|
15
|
-
config.
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
config.after(:each) do
|
21
|
-
ActiveRecord::Base.connection.rollback_db_transaction
|
22
|
-
ActiveRecord::Base.connection.decrement_open_transactions
|
12
|
+
config.around(:each) do |block|
|
13
|
+
TestDB.transaction(:rollback => :always) do
|
14
|
+
block.run()
|
15
|
+
end
|
23
16
|
end
|
24
17
|
|
25
18
|
def m(line)
|
26
19
|
IrcMessage.parse(line)
|
27
20
|
end
|
28
|
-
|
29
|
-
def em(mod)
|
30
|
-
c = Class.new
|
31
|
-
c.send(:include, mod)
|
32
|
-
c
|
33
|
-
end
|
34
21
|
end
|