tkellem 0.7.1 → 0.8.0
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/.gitignore +7 -0
- data/Gemfile +4 -0
- data/README.md +28 -6
- data/Rakefile +14 -5
- data/bin/tkellem +2 -107
- data/debian/changelog +5 -0
- data/debian/compat +1 -0
- data/debian/control +18 -0
- data/debian/copyright +42 -0
- data/debian/docs +1 -0
- data/debian/examples +1 -0
- data/debian/install +3 -0
- data/debian/manpages +1 -0
- data/debian/rules +13 -0
- data/debian/source/format +1 -0
- data/debian/tkellem.1 +11 -0
- data/examples/config.yml +2 -29
- data/lib/tkellem/bouncer.rb +196 -31
- data/lib/tkellem/bouncer_connection.rb +90 -85
- data/lib/tkellem/daemon.rb +155 -0
- data/lib/tkellem/irc_message.rb +58 -0
- data/lib/tkellem/irc_server.rb +8 -121
- data/lib/tkellem/migrations/001_init_db.rb +33 -0
- data/lib/tkellem/models/host.rb +11 -0
- data/lib/tkellem/models/listen_address.rb +12 -0
- data/lib/tkellem/models/network.rb +15 -0
- data/lib/tkellem/models/network_user.rb +12 -0
- data/lib/tkellem/models/user.rb +56 -0
- data/lib/tkellem/plugins/backlog.rb +160 -0
- data/lib/tkellem/plugins/push_service.rb +152 -0
- data/lib/tkellem/socket_server.rb +29 -0
- data/lib/tkellem/tkellem_bot.rb +318 -0
- data/lib/tkellem/tkellem_server.rb +114 -0
- data/lib/tkellem/version.rb +3 -0
- data/lib/tkellem.rb +7 -10
- data/resources/bot_command_descriptions.yml +36 -0
- data/spec/irc_message_spec.rb +47 -0
- data/spec/irc_server_spec.rb +60 -0
- data/spec/spec_helper.rb +0 -2
- data/tkellem.gemspec +20 -47
- metadata +118 -22
- data/VERSION +0 -1
- data/lib/tkellem/backlog.rb +0 -85
- data/lib/tkellem/irc_line.rb +0 -58
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
require 'tkellem/bouncer_connection'
|
5
|
+
require 'tkellem/bouncer'
|
6
|
+
|
7
|
+
require 'tkellem/models/user'
|
8
|
+
require 'tkellem/models/network'
|
9
|
+
require 'tkellem/models/host'
|
10
|
+
require 'tkellem/models/network_user'
|
11
|
+
require 'tkellem/models/listen_address'
|
12
|
+
|
13
|
+
require 'tkellem/plugins/push_service'
|
14
|
+
require 'tkellem/plugins/backlog'
|
15
|
+
|
16
|
+
module Tkellem
|
17
|
+
|
18
|
+
class TkellemServer
|
19
|
+
include Tkellem::EasyLogger
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@listeners = {}
|
23
|
+
@bouncers = {}
|
24
|
+
|
25
|
+
ActiveRecord::Base.establish_connection({
|
26
|
+
:adapter => 'sqlite3',
|
27
|
+
:database => File.expand_path("~/.tkellem/tkellem.sqlite3"),
|
28
|
+
})
|
29
|
+
ActiveRecord::Migrator.migrate(File.expand_path("../migrations", __FILE__), nil)
|
30
|
+
|
31
|
+
ListenAddress.all.each { |a| listen(a) }
|
32
|
+
NetworkUser.find_each { |nu| add_bouncer(Bouncer.new(nu)) }
|
33
|
+
Observer.forward_to << self
|
34
|
+
end
|
35
|
+
|
36
|
+
# callbacks for AR observer events
|
37
|
+
def after_create(obj)
|
38
|
+
case obj
|
39
|
+
when ListenAddress
|
40
|
+
listen(obj)
|
41
|
+
when NetworkUser
|
42
|
+
add_bouncer(Bouncer.new(obj))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def after_destroy(obj)
|
47
|
+
case obj
|
48
|
+
when ListenAddress
|
49
|
+
stop_listening(obj)
|
50
|
+
# TODO: remove bouncer on NetworkUser.destroy
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def listen(listen_address)
|
55
|
+
address = listen_address.address
|
56
|
+
port = listen_address.port
|
57
|
+
ssl = listen_address.ssl
|
58
|
+
|
59
|
+
info "Listening on #{listen_address}"
|
60
|
+
|
61
|
+
@listeners[listen_address.id] = EM.start_server(listen_address.address,
|
62
|
+
listen_address.port,
|
63
|
+
BouncerConnection,
|
64
|
+
self,
|
65
|
+
listen_address.ssl)
|
66
|
+
end
|
67
|
+
|
68
|
+
def stop_listening(listen_address)
|
69
|
+
listener = @listeners[listen_address.id]
|
70
|
+
return unless listener
|
71
|
+
EM.stop_server(listener)
|
72
|
+
info "No longer listening on #{listen_address}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_bouncer(bouncer)
|
76
|
+
key = [bouncer.user.id, bouncer.network.name]
|
77
|
+
raise("bouncer already exists: #{key}") if @bouncers.include?(key)
|
78
|
+
@bouncers[key] = bouncer
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_bouncer(user, network_name)
|
82
|
+
key = [user.id, network_name]
|
83
|
+
bouncer = @bouncers[key]
|
84
|
+
if !bouncer
|
85
|
+
# find the public network with this name, and attempt to auto-add this user to it
|
86
|
+
network = Network.first(:conditions => { :user_id => nil, :name => network_name })
|
87
|
+
if network
|
88
|
+
nu = NetworkUser.create!(:user => user, :network => network)
|
89
|
+
# AR callback should create the bouncer in sync
|
90
|
+
bouncer = @bouncers[key]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
bouncer
|
94
|
+
end
|
95
|
+
|
96
|
+
class Observer < ActiveRecord::Observer
|
97
|
+
observe 'Tkellem::ListenAddress', 'Tkellem::NetworkUser'
|
98
|
+
cattr_accessor :forward_to
|
99
|
+
self.forward_to = []
|
100
|
+
|
101
|
+
def after_create(obj)
|
102
|
+
forward_to.each { |f| f.after_create(obj) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def after_destroy(obj)
|
106
|
+
forward_to.each { |f| f.after_destroy(obj) }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
ActiveRecord::Base.observers = Observer
|
111
|
+
ActiveRecord::Base.instantiate_observers
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
data/lib/tkellem.rb
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
begin
|
2
|
-
require 'rubygems'
|
3
|
-
rescue LoadError
|
4
|
-
end
|
5
|
-
|
6
|
-
pathname = File.expand_path(File.dirname(__FILE__))
|
7
|
-
$LOAD_PATH.push(pathname) unless $LOAD_PATH.include?(pathname)
|
8
|
-
|
9
1
|
module Tkellem
|
10
2
|
module EasyLogger
|
11
3
|
require 'logger'
|
@@ -24,7 +16,11 @@ module Tkellem
|
|
24
16
|
@trace = val
|
25
17
|
end
|
26
18
|
def self.trace
|
27
|
-
@trace || @trace =
|
19
|
+
@trace || @trace = true
|
20
|
+
end
|
21
|
+
|
22
|
+
def log_name
|
23
|
+
""
|
28
24
|
end
|
29
25
|
|
30
26
|
def trace(msg)
|
@@ -42,4 +38,5 @@ module Tkellem
|
|
42
38
|
end
|
43
39
|
end
|
44
40
|
|
45
|
-
require
|
41
|
+
require "tkellem/version"
|
42
|
+
require 'tkellem/tkellem_server'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
---
|
2
|
+
LISTEN:
|
3
|
+
banner: "Usage: LISTEN [--add|--remove|--list] <uri>"
|
4
|
+
help: |+
|
5
|
+
Manage the address/port combinations for tkellem to accept client
|
6
|
+
connections on.
|
7
|
+
|
8
|
+
Protocol is either `irc`, or `ircs` for an SSL listener.
|
9
|
+
|
10
|
+
Example:
|
11
|
+
LISTEN --add ircs://0.0.0.0:10001
|
12
|
+
|
13
|
+
USER:
|
14
|
+
banner: "Usage: USER [--add|--remove|--list] <username> [--admin]"
|
15
|
+
help: |+
|
16
|
+
Manage users.
|
17
|
+
|
18
|
+
Example:
|
19
|
+
USER --add joe admin
|
20
|
+
|
21
|
+
PASSWORD:
|
22
|
+
banner: "Usage: PASSWORD [--user <username>] <new-password>"
|
23
|
+
help: |+
|
24
|
+
Change password. If you are an admin, you can change other users passwords as well.
|
25
|
+
|
26
|
+
Example:
|
27
|
+
PASSWORD hunter2
|
28
|
+
|
29
|
+
NETWORK:
|
30
|
+
banner: "Usage: NETWORK [--add|--remove|--list] [--public] <network-name> <uri>"
|
31
|
+
help: |+
|
32
|
+
Manage networks. --add will add a new network, or a new connection host to an existing network. Public networks can only be created by admins, and can be joined by anybody.
|
33
|
+
|
34
|
+
Examples:
|
35
|
+
NETWORK --add --public freenode irc://irc.freenode.org:6667
|
36
|
+
NETWORK --add freenode ircs://irc.freenode.org:7000
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tkellem/irc_message'
|
3
|
+
|
4
|
+
include Tkellem
|
5
|
+
|
6
|
+
describe IrcMessage, ".parse" do
|
7
|
+
it "should parse complex irc lines" do
|
8
|
+
orig = ":some_long_prefix COMMAND first second :long arg here"
|
9
|
+
line = IrcMessage.parse(orig)
|
10
|
+
line.command.should == 'COMMAND'
|
11
|
+
line.prefix.should == 'some_long_prefix'
|
12
|
+
line.args.size.should == 3
|
13
|
+
line.args.should == ['first', 'second', 'long arg here']
|
14
|
+
line.replay.should == orig
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should parse messages with embedded colons" do
|
18
|
+
orig = "MSG #myroom http://google.com/"
|
19
|
+
line = IrcMessage.parse(orig)
|
20
|
+
line.command.should == "MSG"
|
21
|
+
line.args.should == ["#myroom", "http://google.com/"]
|
22
|
+
line.replay.should == orig
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe IrcMessage, "#with_timestamp" do
|
27
|
+
it "should prefix a timestamp to the last arg" do
|
28
|
+
line = IrcMessage.parse(":some_long_prefix COMMAND first second :long arg here")
|
29
|
+
require 'time'
|
30
|
+
timestamp = Time.parse("Thu Nov 29 14:33:20 2001")
|
31
|
+
ts_line = line.with_timestamp(timestamp)
|
32
|
+
ts_line.should be_a(IrcMessage)
|
33
|
+
ts_line.to_s.should == ":some_long_prefix COMMAND first second :14:33:20> long arg here"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe IrcMessage do
|
38
|
+
it "should know how to find the last arg" do
|
39
|
+
line1 = IrcMessage.parse("TEST one two three")
|
40
|
+
line1.args.should == %w(one two three)
|
41
|
+
line1.args.last.should == "three"
|
42
|
+
|
43
|
+
line2 = IrcMessage.parse("TEST one two :three")
|
44
|
+
line2.args.should == %w(one two three)
|
45
|
+
line2.args.last.should == "three"
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tkellem/irc_server'
|
3
|
+
|
4
|
+
include Tkellem
|
5
|
+
|
6
|
+
describe IrcServer, "connection" do
|
7
|
+
def make_server
|
8
|
+
Class.new do
|
9
|
+
include IrcServer
|
10
|
+
|
11
|
+
def send_data(*a); end
|
12
|
+
end.new(nil, "spec_server", false, "speccer")
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_welcome(s, &just_before_last)
|
16
|
+
s.receive_line("001 blah blah")
|
17
|
+
s.receive_line("002 more blah")
|
18
|
+
s.receive_line("003 even more blah")
|
19
|
+
just_before_last && just_before_last.call
|
20
|
+
s.receive_line("376 :end of MOTD")
|
21
|
+
end
|
22
|
+
|
23
|
+
def connected_server
|
24
|
+
s = make_server
|
25
|
+
s.post_init
|
26
|
+
send_welcome(s)
|
27
|
+
s.connected?.should be_true
|
28
|
+
s
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should connect to the server on creation" do
|
32
|
+
s = make_server
|
33
|
+
s.connected?.should_not be_true
|
34
|
+
s.should_receive(:send_data).with("USER speccer localhost blah :speccer\r\n")
|
35
|
+
s.should_receive(:send_data).with("NICK speccer\r\n")
|
36
|
+
s.post_init
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should join pending rooms once the connection is established" do
|
40
|
+
s = make_server
|
41
|
+
s.post_init
|
42
|
+
s.connected?.should_not be_true # still haven't received the welcome
|
43
|
+
|
44
|
+
s.join_room "#test1"
|
45
|
+
# as soon as the end of MOTD is received, the IrcServer will consider itself
|
46
|
+
# connected and try to join the rooms.
|
47
|
+
s.should_receive(:send_data).with("JOIN #test1\r\n")
|
48
|
+
s.should_receive(:send_data).with("JOIN #test2\r\n")
|
49
|
+
|
50
|
+
send_welcome(s) { s.join_room "#test2" }
|
51
|
+
|
52
|
+
s.connected?.should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should pong" do
|
56
|
+
s = connected_server
|
57
|
+
s.should_receive(:send_data).with("PONG speccer!tkellem :HAI\r\n")
|
58
|
+
s.receive_line(":speccer!test@host ping :HAI")
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/tkellem.gemspec
CHANGED
@@ -1,57 +1,30 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
1
|
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "tkellem/version"
|
5
4
|
|
6
5
|
Gem::Specification.new do |s|
|
7
|
-
s.name
|
8
|
-
s.version
|
6
|
+
s.name = %q{tkellem}
|
7
|
+
s.version = Tkellem::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Brian Palmer"]
|
10
|
+
s.email = ["brian@codekitchen.net"]
|
11
|
+
s.homepage = %q{http://github.com/codekitchen/tkellem}
|
12
|
+
s.summary = %q{IRC bouncer with multi-client support}
|
9
13
|
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
17
|
s.default_executable = %q{tkellem}
|
14
|
-
s.email = %q{brian@codekitchen.net}
|
15
|
-
s.executables = ["tkellem"]
|
16
|
-
s.extra_rdoc_files = [
|
17
|
-
"LICENSE",
|
18
|
-
"README.md"
|
19
|
-
]
|
20
|
-
s.files = [
|
21
|
-
"LICENSE",
|
22
|
-
"README.md",
|
23
|
-
"Rakefile",
|
24
|
-
"VERSION",
|
25
|
-
"bin/tkellem",
|
26
|
-
"examples/config.yml",
|
27
|
-
"lib/tkellem.rb",
|
28
|
-
"lib/tkellem/backlog.rb",
|
29
|
-
"lib/tkellem/bouncer.rb",
|
30
|
-
"lib/tkellem/bouncer_connection.rb",
|
31
|
-
"lib/tkellem/irc_line.rb",
|
32
|
-
"lib/tkellem/irc_server.rb",
|
33
|
-
"spec/spec_helper.rb",
|
34
|
-
"tkellem.gemspec"
|
35
|
-
]
|
36
|
-
s.homepage = %q{http://github.com/codekitchen/tkellem}
|
37
18
|
s.require_paths = ["lib"]
|
38
|
-
s.rubygems_version = %q{1.3.7}
|
39
|
-
s.summary = %q{IRC bouncer with multi-client support}
|
40
|
-
s.test_files = [
|
41
|
-
"spec/spec_helper.rb"
|
42
|
-
]
|
43
19
|
|
44
|
-
|
45
|
-
|
46
|
-
|
20
|
+
s.add_dependency "eventmachine", "~> 0.12.10"
|
21
|
+
s.add_dependency "daemons", "~> 1.1.0"
|
22
|
+
s.add_dependency "json"
|
23
|
+
s.add_dependency "activerecord", "~> 3.0.0"
|
24
|
+
s.add_dependency "sqlite3", "~> 1.3.3"
|
47
25
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
s.add_dependency(%q<eventmachine>, [">= 0"])
|
52
|
-
end
|
53
|
-
else
|
54
|
-
s.add_dependency(%q<eventmachine>, [">= 0"])
|
55
|
-
end
|
26
|
+
s.add_development_dependency "rspec", "~> 2.5"
|
27
|
+
s.add_development_dependency "rcov"
|
28
|
+
s.add_development_dependency "yard"
|
56
29
|
end
|
57
30
|
|
metadata
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tkellem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 7
|
8
|
-
- 1
|
9
|
-
version: 0.7.1
|
4
|
+
prerelease:
|
5
|
+
version: 0.8.0
|
10
6
|
platform: ruby
|
11
7
|
authors:
|
12
8
|
- Brian Palmer
|
@@ -14,44 +10,146 @@ autorequire:
|
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
12
|
|
17
|
-
date:
|
13
|
+
date: 2011-06-13 00:00:00 -06:00
|
18
14
|
default_executable: tkellem
|
19
15
|
dependencies:
|
20
16
|
- !ruby/object:Gem::Dependency
|
21
17
|
name: eventmachine
|
22
18
|
prerelease: false
|
23
19
|
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ~>
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.12.10
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: daemons
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ~>
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 1.1.0
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: json
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
24
42
|
none: false
|
25
43
|
requirements:
|
26
44
|
- - ">="
|
27
45
|
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 0
|
30
46
|
version: "0"
|
31
47
|
type: :runtime
|
32
|
-
version_requirements: *
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: activerecord
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ~>
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 3.0.0
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: sqlite3
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.3.3
|
69
|
+
type: :runtime
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: rspec
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ~>
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "2.5"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: rcov
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: yard
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id008
|
33
104
|
description:
|
34
|
-
email:
|
105
|
+
email:
|
106
|
+
- brian@codekitchen.net
|
35
107
|
executables:
|
36
108
|
- tkellem
|
37
109
|
extensions: []
|
38
110
|
|
39
|
-
extra_rdoc_files:
|
40
|
-
|
41
|
-
- README.md
|
111
|
+
extra_rdoc_files: []
|
112
|
+
|
42
113
|
files:
|
114
|
+
- .gitignore
|
115
|
+
- Gemfile
|
43
116
|
- LICENSE
|
44
117
|
- README.md
|
45
118
|
- Rakefile
|
46
|
-
- VERSION
|
47
119
|
- bin/tkellem
|
120
|
+
- debian/changelog
|
121
|
+
- debian/compat
|
122
|
+
- debian/control
|
123
|
+
- debian/copyright
|
124
|
+
- debian/docs
|
125
|
+
- debian/examples
|
126
|
+
- debian/install
|
127
|
+
- debian/manpages
|
128
|
+
- debian/rules
|
129
|
+
- debian/source/format
|
130
|
+
- debian/tkellem.1
|
48
131
|
- examples/config.yml
|
49
132
|
- lib/tkellem.rb
|
50
|
-
- lib/tkellem/backlog.rb
|
51
133
|
- lib/tkellem/bouncer.rb
|
52
134
|
- lib/tkellem/bouncer_connection.rb
|
53
|
-
- lib/tkellem/
|
135
|
+
- lib/tkellem/daemon.rb
|
136
|
+
- lib/tkellem/irc_message.rb
|
54
137
|
- lib/tkellem/irc_server.rb
|
138
|
+
- lib/tkellem/migrations/001_init_db.rb
|
139
|
+
- lib/tkellem/models/host.rb
|
140
|
+
- lib/tkellem/models/listen_address.rb
|
141
|
+
- lib/tkellem/models/network.rb
|
142
|
+
- lib/tkellem/models/network_user.rb
|
143
|
+
- lib/tkellem/models/user.rb
|
144
|
+
- lib/tkellem/plugins/backlog.rb
|
145
|
+
- lib/tkellem/plugins/push_service.rb
|
146
|
+
- lib/tkellem/socket_server.rb
|
147
|
+
- lib/tkellem/tkellem_bot.rb
|
148
|
+
- lib/tkellem/tkellem_server.rb
|
149
|
+
- lib/tkellem/version.rb
|
150
|
+
- resources/bot_command_descriptions.yml
|
151
|
+
- spec/irc_message_spec.rb
|
152
|
+
- spec/irc_server_spec.rb
|
55
153
|
- spec/spec_helper.rb
|
56
154
|
- tkellem.gemspec
|
57
155
|
has_rdoc: true
|
@@ -68,23 +166,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
166
|
requirements:
|
69
167
|
- - ">="
|
70
168
|
- !ruby/object:Gem::Version
|
71
|
-
segments:
|
72
|
-
- 0
|
73
169
|
version: "0"
|
74
170
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
171
|
none: false
|
76
172
|
requirements:
|
77
173
|
- - ">="
|
78
174
|
- !ruby/object:Gem::Version
|
79
|
-
segments:
|
80
|
-
- 0
|
81
175
|
version: "0"
|
82
176
|
requirements: []
|
83
177
|
|
84
178
|
rubyforge_project:
|
85
|
-
rubygems_version: 1.
|
179
|
+
rubygems_version: 1.6.2
|
86
180
|
signing_key:
|
87
181
|
specification_version: 3
|
88
182
|
summary: IRC bouncer with multi-client support
|
89
183
|
test_files:
|
184
|
+
- spec/irc_message_spec.rb
|
185
|
+
- spec/irc_server_spec.rb
|
90
186
|
- spec/spec_helper.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.7.1
|
data/lib/tkellem/backlog.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'tkellem/irc_line'
|
2
|
-
|
3
|
-
module Tkellem
|
4
|
-
|
5
|
-
# Normally there will be one client per backlog, but there can be more than one
|
6
|
-
# connection for the same backlog, if two or more IRC clients connect with the
|
7
|
-
# same client name. That situation is equivalent to how most multi-connection
|
8
|
-
# bouncers like bip work.
|
9
|
-
|
10
|
-
class Backlog
|
11
|
-
|
12
|
-
class BacklogLine < Struct.new(:irc_line, :time)
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(name, max_backlog = nil)
|
16
|
-
@name = name
|
17
|
-
@backlog = []
|
18
|
-
@pm_backlogs = Hash.new { |h,k| h[k] = [] }
|
19
|
-
@active_conns = []
|
20
|
-
@max_backlog = max_backlog
|
21
|
-
end
|
22
|
-
attr_reader :name, :backlog, :active_conns, :pm_backlogs, :max_backlog
|
23
|
-
|
24
|
-
def handle_message(msg)
|
25
|
-
# TODO: only send back response messages like WHO, NAMES, etc. to the
|
26
|
-
# BouncerConnection that requested it.
|
27
|
-
if !active_conns.empty?
|
28
|
-
case msg.command
|
29
|
-
when /3\d\d/, /join/i, /part/i
|
30
|
-
# transient response -- we want to forward these, but not backlog
|
31
|
-
active_conns.each { |conn| conn.transient_response(msg) }
|
32
|
-
when /privmsg/i
|
33
|
-
active_conns.each { |conn| conn.send_msg(msg) }
|
34
|
-
else
|
35
|
-
# do nothing?
|
36
|
-
end
|
37
|
-
elsif msg.command.match(/privmsg/i)
|
38
|
-
if msg.args.first.match(/^#/)
|
39
|
-
# room privmsg always goes in a specific backlog
|
40
|
-
pm_target = msg.args.first
|
41
|
-
bl = pm_backlogs[pm_target]
|
42
|
-
else
|
43
|
-
# other messages go in the general backlog
|
44
|
-
bl = backlog
|
45
|
-
end
|
46
|
-
bl.push(BacklogLine.new(msg, Time.now))
|
47
|
-
limit_backlog(bl)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def limit_backlog(bl)
|
52
|
-
bl.shift until !max_backlog || bl.size <= max_backlog
|
53
|
-
end
|
54
|
-
|
55
|
-
def max_backlog=(new_val)
|
56
|
-
@max_backlog = new_val
|
57
|
-
limit_backlog(backlog)
|
58
|
-
pm_backlogs.each { |k,bl| limit_backlog(bl) }
|
59
|
-
end
|
60
|
-
|
61
|
-
def add_conn(bouncer_conn)
|
62
|
-
active_conns << bouncer_conn
|
63
|
-
end
|
64
|
-
|
65
|
-
def remove_conn(bouncer_conn)
|
66
|
-
active_conns.delete(bouncer_conn)
|
67
|
-
end
|
68
|
-
|
69
|
-
def send_backlog(conn, pm_target = nil)
|
70
|
-
if pm_target
|
71
|
-
# send room-specific backlog
|
72
|
-
msgs = pm_backlogs.key?(pm_target) ? pm_backlogs[pm_target] : []
|
73
|
-
else
|
74
|
-
# send the general backlog
|
75
|
-
msgs = backlog
|
76
|
-
end
|
77
|
-
|
78
|
-
until msgs.empty?
|
79
|
-
backlog_line = msgs.shift
|
80
|
-
conn.send_msg(backlog_line.irc_line.with_timestamp(backlog_line.time))
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end
|