tkellem 0.9.0.beta3 → 0.9.0.beta4
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/lib/tkellem/bouncer.rb +14 -30
- data/lib/tkellem/bouncer_connection.rb +58 -42
- data/lib/tkellem/daemon.rb +18 -7
- data/lib/tkellem/irc_server.rb +124 -0
- data/lib/tkellem/migrations/001_init_db.rb +22 -39
- data/lib/tkellem/migrations/002_at_connect_columns.rb +4 -21
- data/lib/tkellem/migrations/003_settings.rb +9 -18
- data/lib/tkellem/models/host.rb +2 -2
- data/lib/tkellem/models/listen_address.rb +1 -13
- data/lib/tkellem/models/network.rb +7 -11
- data/lib/tkellem/models/network_user.rb +6 -22
- data/lib/tkellem/models/setting.rb +3 -3
- data/lib/tkellem/models/user.rb +6 -13
- data/lib/tkellem/plugins/backlog.rb +31 -43
- data/lib/tkellem/socket_server.rb +7 -15
- data/lib/tkellem/tkellem_bot.rb +19 -11
- data/lib/tkellem/tkellem_server.rb +70 -77
- data/lib/tkellem/version.rb +1 -1
- data/lib/tkellem.rb +10 -1
- data/spec/bouncer_connection_spec.rb +37 -0
- data/spec/irc_server_spec.rb +145 -0
- data/spec/spec_helper.rb +17 -4
- data/tkellem.gemspec +5 -6
- metadata +31 -43
- data/lib/tkellem/celluloid_tools.rb +0 -131
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tkellem/irc_server'
|
3
|
+
|
4
|
+
include Tkellem
|
5
|
+
|
6
|
+
describe Bouncer, "connection" do
|
7
|
+
before do
|
8
|
+
EM.stub!(:add_timer).and_return(nil)
|
9
|
+
end
|
10
|
+
|
11
|
+
def make_server
|
12
|
+
network = Network.create!(:hosts => [Host.create!(:address => 'localhost', :port => 4321)], :name => 'test')
|
13
|
+
b = Bouncer.new(NetworkUser.create!(:user => User.new(:username => 'speccer'), :network => network))
|
14
|
+
b
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_welcome(s, &just_before_last)
|
18
|
+
s.should_receive(:send_msg).with("USER speccer somehost tkellem :speccer@tkellem")
|
19
|
+
s.should_receive(:send_msg).with("NICK speccer")
|
20
|
+
s.should_receive(:send_msg).with("AWAY :Away")
|
21
|
+
s.connection_established(nil)
|
22
|
+
s.server_msg(IrcMessage.parse("001 blah blah"))
|
23
|
+
s.server_msg(IrcMessage.parse("002 more blah"))
|
24
|
+
s.server_msg(IrcMessage.parse("003 even more blah"))
|
25
|
+
just_before_last && just_before_last.call
|
26
|
+
s.server_msg(IrcMessage.parse("376 :end of MOTD"))
|
27
|
+
end
|
28
|
+
|
29
|
+
def connected_server
|
30
|
+
s = make_server
|
31
|
+
send_welcome(s)
|
32
|
+
s.connected?.should be_true
|
33
|
+
s
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should connect to the server on creation" do
|
37
|
+
s = make_server
|
38
|
+
s.connected?.should_not be_true
|
39
|
+
s.should_receive(:send_msg).with("USER speccer somehost tkellem :speccer@tkellem")
|
40
|
+
s.should_receive(:send_msg).with("NICK speccer")
|
41
|
+
s.connection_established(nil)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should pong" do
|
45
|
+
s = connected_server
|
46
|
+
s.should_receive(:send_msg).with("PONG tkellem!tkellem :HAI")
|
47
|
+
s.server_msg(IrcMessage.parse(":speccer!test@host ping :HAI"))
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should ignore blank lines" do
|
51
|
+
b = mock("bouncer", :trace => nil)
|
52
|
+
b.should_receive(:failsafe).and_yield
|
53
|
+
s = em(IrcServerConnection).new('connected', b, false)
|
54
|
+
b.should_receive(:server_msg).never
|
55
|
+
s.receive_line("")
|
56
|
+
end
|
57
|
+
|
58
|
+
def tk_server
|
59
|
+
$tk_server ||= TkellemServer.new
|
60
|
+
end
|
61
|
+
|
62
|
+
after(:each) do
|
63
|
+
$tk_server.stop if $tk_server
|
64
|
+
$tk_server = nil
|
65
|
+
end
|
66
|
+
|
67
|
+
def network_user(opts = {})
|
68
|
+
opts[:user] ||= @user ||= User.create!(:username => 'speccer', :password => 'test123')
|
69
|
+
opts[:network] ||= @network ||= Network.create!(:name => 'localhost')
|
70
|
+
@network_user ||= NetworkUser.create!(opts)
|
71
|
+
end
|
72
|
+
|
73
|
+
def bouncer(opts = {})
|
74
|
+
tk_server
|
75
|
+
network_user
|
76
|
+
@bouncer = $tk_server.bouncers.values.last
|
77
|
+
if opts[:connect]
|
78
|
+
@server_conn = em(IrcServerConnection).new(nil, @bouncer, false)
|
79
|
+
@server_conn.stub!(:send_data)
|
80
|
+
@bouncer.connection_established(@server_conn)
|
81
|
+
@bouncer.send :ready!
|
82
|
+
end
|
83
|
+
@bouncer
|
84
|
+
end
|
85
|
+
|
86
|
+
def client_connection(opts = {})
|
87
|
+
@client ||= em(BouncerConnection).new(tk_server, false)
|
88
|
+
if opts[:connect]
|
89
|
+
end
|
90
|
+
@client
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should force the client nick on connect" do
|
94
|
+
network_user(:nick => 'mynick')
|
95
|
+
bouncer(:connect => true)
|
96
|
+
@bouncer.server_msg(m ":mynick JOIN #t1")
|
97
|
+
client_connection
|
98
|
+
@client.should_receive(:send_msg).with(":some_other_nick NICK mynick")
|
99
|
+
@client.should_receive(:send_msg).with(":mynick JOIN #t1")
|
100
|
+
@client.receive_line("PASS test123")
|
101
|
+
@client.receive_line("NICK some_other_nick")
|
102
|
+
@client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should attempt another nick if the default is taken" do
|
106
|
+
network_user(:nick => 'mynick')
|
107
|
+
bouncer
|
108
|
+
@server_conn = em(IrcServerConnection).new(nil, @bouncer, false)
|
109
|
+
@server_conn.stub!(:send_data)
|
110
|
+
@bouncer.connection_established(@server_conn)
|
111
|
+
@server_conn.should_receive(:send_data).with("NICK mynick_\r\n")
|
112
|
+
@bouncer.server_msg(m ":server 433 * mynick :Nickname already in use")
|
113
|
+
@bouncer.nick.should == 'mynick_'
|
114
|
+
@bouncer.send :ready!
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should change nicks if a client sends nick after connecting" do
|
118
|
+
network_user(:nick => 'mynick')
|
119
|
+
bouncer(:connect => true)
|
120
|
+
@bouncer.server_msg(m ":mynick JOIN #t1")
|
121
|
+
client_connection
|
122
|
+
@client.should_receive(:send_msg).with(":mynick JOIN #t1")
|
123
|
+
@client.receive_line("PASS test123")
|
124
|
+
@client.receive_line("NICK mynick")
|
125
|
+
@client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
|
126
|
+
@bouncer.nick.should == 'mynick'
|
127
|
+
@bouncer.client_msg(@client, m("NICK some_other"))
|
128
|
+
@bouncer.nick.should == 'some_other'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should change nicks if a server forces nick change" do
|
132
|
+
network_user(:nick => 'mynick')
|
133
|
+
bouncer(:connect => true)
|
134
|
+
@bouncer.server_msg(m ":mynick JOIN #t1")
|
135
|
+
client_connection
|
136
|
+
@client.should_receive(:send_msg).with(":mynick JOIN #t1")
|
137
|
+
@client.receive_line("PASS test123")
|
138
|
+
@client.receive_line("NICK mynick")
|
139
|
+
@client.receive_line("USER #{@user.username}@#{@network.name} a b :c")
|
140
|
+
@bouncer.nick.should == 'mynick'
|
141
|
+
@client.should_receive(:send_msg).with(m ":mynick NICK some_other")
|
142
|
+
@bouncer.server_msg(m ":mynick NICK some_other")
|
143
|
+
@bouncer.nick.should == 'some_other'
|
144
|
+
end
|
145
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,17 +5,30 @@ require 'tkellem'
|
|
5
5
|
require 'rspec'
|
6
6
|
|
7
7
|
Tkellem::EasyLogger.logger = Logger.new("test.log")
|
8
|
+
ActiveRecord::Base.logger = Tkellem::EasyLogger.logger
|
8
9
|
|
9
|
-
|
10
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
11
|
+
ActiveRecord::Migration.verbose = false
|
12
|
+
ActiveRecord::Migrator.migrate(File.expand_path("../../lib/tkellem/migrations", __FILE__), nil)
|
10
13
|
|
11
14
|
RSpec.configure do |config|
|
12
|
-
config.around(:each) do |
|
13
|
-
|
14
|
-
|
15
|
+
config.around(:each) do |test|
|
16
|
+
EM.run do
|
17
|
+
ActiveRecord::Base.transaction do
|
18
|
+
test.run
|
19
|
+
raise ActiveRecord::Rollback
|
20
|
+
end
|
21
|
+
EM.stop
|
15
22
|
end
|
16
23
|
end
|
17
24
|
|
18
25
|
def m(line)
|
19
26
|
IrcMessage.parse(line)
|
20
27
|
end
|
28
|
+
|
29
|
+
def em(mod)
|
30
|
+
c = Class.new
|
31
|
+
c.send(:include, mod)
|
32
|
+
c
|
33
|
+
end
|
21
34
|
end
|
data/tkellem.gemspec
CHANGED
@@ -17,12 +17,11 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.default_executable = %q{tkellem}
|
18
18
|
s.require_paths = ["lib"]
|
19
19
|
|
20
|
-
s.add_dependency "
|
21
|
-
s.add_dependency "
|
22
|
-
s.add_dependency "
|
23
|
-
s.add_dependency "
|
24
|
-
s.add_dependency "sqlite3", "1.3.6"
|
20
|
+
s.add_dependency "eventmachine", "~> 1.0.3"
|
21
|
+
s.add_dependency "activerecord", "~> 4.0.0.rc2"
|
22
|
+
s.add_dependency "sqlite3", "~> 1.3.3"
|
23
|
+
s.add_dependency "rails-observers"
|
25
24
|
|
26
|
-
s.add_development_dependency "rake"
|
27
25
|
s.add_development_dependency "rspec", "~> 2.5"
|
26
|
+
s.add_development_dependency "simplecov"
|
28
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tkellem
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.0.
|
4
|
+
version: 0.9.0.beta4
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,16 +9,16 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-06-
|
12
|
+
date: 2013-06-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
15
|
+
name: eventmachine
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 1.0.3
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,15 +26,15 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 1.0.3
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: activerecord
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
none: false
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 0.
|
37
|
+
version: 4.0.0.rc2
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,57 +42,57 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 0.
|
45
|
+
version: 4.0.0.rc2
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: sqlite3
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 3.
|
53
|
+
version: 1.3.3
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.
|
61
|
+
version: 1.3.3
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: rails-observers
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- - '
|
67
|
+
- - ! '>='
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: '0'
|
70
70
|
type: :runtime
|
71
71
|
prerelease: false
|
72
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- - '
|
75
|
+
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: '0'
|
78
78
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
79
|
+
name: rspec
|
80
80
|
requirement: !ruby/object:Gem::Requirement
|
81
81
|
none: false
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ~>
|
84
84
|
- !ruby/object:Gem::Version
|
85
|
-
version:
|
86
|
-
type: :
|
85
|
+
version: '2.5'
|
86
|
+
type: :development
|
87
87
|
prerelease: false
|
88
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
89
|
none: false
|
90
90
|
requirements:
|
91
|
-
- -
|
91
|
+
- - ~>
|
92
92
|
- !ruby/object:Gem::Version
|
93
|
-
version:
|
93
|
+
version: '2.5'
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
95
|
+
name: simplecov
|
96
96
|
requirement: !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
@@ -107,22 +107,6 @@ dependencies:
|
|
107
107
|
- - ! '>='
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: '0'
|
110
|
-
- !ruby/object:Gem::Dependency
|
111
|
-
name: rspec
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
|
-
requirements:
|
115
|
-
- - ~>
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '2.5'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
|
-
requirements:
|
123
|
-
- - ~>
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
version: '2.5'
|
126
110
|
description:
|
127
111
|
email:
|
128
112
|
- brian@codekitchen.net
|
@@ -152,9 +136,9 @@ files:
|
|
152
136
|
- lib/tkellem.rb
|
153
137
|
- lib/tkellem/bouncer.rb
|
154
138
|
- lib/tkellem/bouncer_connection.rb
|
155
|
-
- lib/tkellem/celluloid_tools.rb
|
156
139
|
- lib/tkellem/daemon.rb
|
157
140
|
- lib/tkellem/irc_message.rb
|
141
|
+
- lib/tkellem/irc_server.rb
|
158
142
|
- lib/tkellem/migrations/001_init_db.rb
|
159
143
|
- lib/tkellem/migrations/002_at_connect_columns.rb
|
160
144
|
- lib/tkellem/migrations/003_settings.rb
|
@@ -173,7 +157,9 @@ files:
|
|
173
157
|
- lib/tkellem/version.rb
|
174
158
|
- resources/bot_command_descriptions.yml
|
175
159
|
- resources/setting_descriptions.yml
|
160
|
+
- spec/bouncer_connection_spec.rb
|
176
161
|
- spec/irc_message_spec.rb
|
162
|
+
- spec/irc_server_spec.rb
|
177
163
|
- spec/spec_helper.rb
|
178
164
|
- tkellem.gemspec
|
179
165
|
homepage: http://github.com/codekitchen/tkellem
|
@@ -190,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
190
176
|
version: '0'
|
191
177
|
segments:
|
192
178
|
- 0
|
193
|
-
hash: -
|
179
|
+
hash: -629410189197339585
|
194
180
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
195
181
|
none: false
|
196
182
|
requirements:
|
@@ -204,5 +190,7 @@ signing_key:
|
|
204
190
|
specification_version: 3
|
205
191
|
summary: IRC bouncer with multi-client support
|
206
192
|
test_files:
|
193
|
+
- spec/bouncer_connection_spec.rb
|
207
194
|
- spec/irc_message_spec.rb
|
195
|
+
- spec/irc_server_spec.rb
|
208
196
|
- spec/spec_helper.rb
|
@@ -1,131 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require 'celluloid/io'
|
3
|
-
|
4
|
-
module Tkellem
|
5
|
-
module CelluloidTools
|
6
|
-
|
7
|
-
# Generates a new SSL context with a new cert and key
|
8
|
-
# Great for easily getting up and running, but not necessarily a good idea for
|
9
|
-
# production use
|
10
|
-
def self.generate_ssl_ctx
|
11
|
-
key = OpenSSL::PKey::RSA.new(2048)
|
12
|
-
|
13
|
-
dn = OpenSSL::X509::Name.parse("/CN=tkellem-auto")
|
14
|
-
cert = OpenSSL::X509::Certificate.new
|
15
|
-
cert.version = 2
|
16
|
-
cert.serial = 1
|
17
|
-
cert.subject = dn
|
18
|
-
cert.issuer = dn
|
19
|
-
cert.public_key = key.public_key
|
20
|
-
cert.not_before = Time.now
|
21
|
-
cert.not_after = Time.now + 94670777 # 3 years
|
22
|
-
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
23
|
-
|
24
|
-
ctx = OpenSSL::SSL::SSLContext.new
|
25
|
-
ctx.key = key
|
26
|
-
ctx.cert = cert
|
27
|
-
|
28
|
-
ctx
|
29
|
-
end
|
30
|
-
|
31
|
-
class BackoffSupervisor < ::Celluloid::SupervisionGroup
|
32
|
-
attr_reader :registry
|
33
|
-
|
34
|
-
def restart_actor(actor, reason)
|
35
|
-
member = @members.find do |member|
|
36
|
-
member.actor == actor
|
37
|
-
end
|
38
|
-
raise "a group member went missing. This shouldn't be!" unless member
|
39
|
-
|
40
|
-
if reason
|
41
|
-
end
|
42
|
-
|
43
|
-
member.restart(reason)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class Listener < Struct.new(:server, :callback)
|
48
|
-
include Celluloid::IO
|
49
|
-
|
50
|
-
def self.start(*args, &callback)
|
51
|
-
listener = self.new(*args)
|
52
|
-
listener.callback = callback
|
53
|
-
listener.async.run
|
54
|
-
listener
|
55
|
-
end
|
56
|
-
|
57
|
-
def run
|
58
|
-
loop { handle_connection(server.accept) }
|
59
|
-
end
|
60
|
-
|
61
|
-
def handle_connection(socket)
|
62
|
-
callback.(socket)
|
63
|
-
end
|
64
|
-
|
65
|
-
finalizer :close
|
66
|
-
|
67
|
-
def close
|
68
|
-
server.try(:close) unless server.try(:closed?)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class TCPListener < Listener
|
73
|
-
def initialize(host, port)
|
74
|
-
self.server = TCPServer.new(host, port)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class SSLListener < Listener
|
79
|
-
def initialize(host, port)
|
80
|
-
self.server = SSLServer.new(TCPServer.new(host, port), CelluloidTools.generate_ssl_ctx)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class UnixListener < Listener
|
85
|
-
def initialize(socket_path)
|
86
|
-
self.server = UNIXServer.new(socket_path)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
module LineReader
|
91
|
-
def self.included(k)
|
92
|
-
k.send :finalizer, :close_connection
|
93
|
-
end
|
94
|
-
|
95
|
-
def readline
|
96
|
-
@delimiter ||= "\r\n"
|
97
|
-
@readline_buffer ||= ''
|
98
|
-
loop do
|
99
|
-
if idx = @readline_buffer.index(@delimiter)
|
100
|
-
postidx = idx + @delimiter.size
|
101
|
-
line = @readline_buffer[0, postidx]
|
102
|
-
@readline_buffer = @readline_buffer[postidx..-1]
|
103
|
-
return line
|
104
|
-
else
|
105
|
-
@socket.readpartial(4096, @readline_buffer)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def close_connection
|
111
|
-
@socket.close if @socket && !@socket.closed?
|
112
|
-
end
|
113
|
-
|
114
|
-
def run
|
115
|
-
loop do
|
116
|
-
line = readline.force_encoding(Encoding::UTF_8)
|
117
|
-
receive_line(line)
|
118
|
-
end
|
119
|
-
rescue EOFError, IOError, OpenSSL::SSL::SSLError
|
120
|
-
unbind
|
121
|
-
end
|
122
|
-
|
123
|
-
def receive_line(line)
|
124
|
-
end
|
125
|
-
|
126
|
-
def unbind
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
end
|
131
|
-
end
|