tkellem 0.8.11 → 0.9.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|