tkellem 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|