nats 0.3.12 → 0.4.2

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/nats/ext/em.rb CHANGED
@@ -4,3 +4,10 @@ rescue LoadError
4
4
  require 'rubygems'
5
5
  require 'eventmachine'
6
6
  end
7
+
8
+ # Check for get_outbound_data_size support, fake it out if it doesn't exist, e.g. jruby
9
+ if !EM::Connection.method_defined? :get_outbound_data_size
10
+ class EM::Connection
11
+ def get_outbound_data_size; return 0; end
12
+ end
13
+ end
data/lib/nats/server.rb CHANGED
@@ -1,306 +1,25 @@
1
1
 
2
- require File.dirname(__FILE__) + '/ext/em'
3
- require File.dirname(__FILE__) + '/ext/bytesize'
4
- require File.dirname(__FILE__) + '/ext/json'
5
- require File.dirname(__FILE__) + '/server/sublist'
6
- require File.dirname(__FILE__) + '/server/options'
7
- require File.dirname(__FILE__) + '/server/const'
8
-
9
2
  require 'socket'
10
3
  require 'fileutils'
11
4
  require 'pp'
12
5
 
6
+ ep = File.expand_path(File.dirname(__FILE__))
13
7
 
14
- module NATSD #:nodoc: all
15
-
16
- # Subscriber
17
- Subscriber = Struct.new(:conn, :subject, :sid)
18
-
19
- class Server
20
-
21
- class << self
22
- attr_reader :id, :info, :log_time, :auth_required, :debug_flag, :trace_flag
23
-
24
- alias auth_required? :auth_required
25
- alias debug_flag? :debug_flag
26
- alias trace_flag? :trace_flag
27
-
28
- def version; "nats server version #{NATSD::VERSION}" end
29
-
30
- def host; @options[:addr] end
31
- def port; @options[:port] end
32
- def pid_file; @options[:pid_file] end
33
-
34
- def setup(argv)
35
- @options = {}
36
-
37
- parser.parse!(argv)
38
- read_config_file
39
- finalize_options
40
-
41
- @id, @cid = fast_uuid, 1
42
- @sublist = Sublist.new
43
- @info = {
44
- :nats_server_id => Server.id,
45
- :version => VERSION,
46
- :auth_required => auth_required?,
47
- :max_payload => MAX_PAYLOAD_SIZE
48
- }
49
-
50
- # Check for daemon flag
51
- if @options[:daemonize]
52
- require 'rubygems'
53
- require 'daemons'
54
- # These log messages visible to controlling TTY
55
- log "Starting #{NATSD::APP_NAME} version #{NATSD::VERSION} on port #{NATSD::Server.port}"
56
- log "Switching to daemon mode"
57
- Daemons.daemonize(:app_name => APP_NAME, :mode => :exec)
58
- end
59
-
60
- setup_logs
61
-
62
- # Setup optimized select versions
63
- EM.epoll unless @options[:noepoll]
64
- EM.kqueue unless @options[:nokqueue]
65
-
66
- # Write pid file if need be.
67
- File.open(@options[:pid_file], 'w') { |f| f.puts "#{Process.pid}" } if @options[:pid_file]
68
-
69
- end
70
-
71
- def subscribe(subscriber)
72
- @sublist.insert(subscriber.subject, subscriber)
73
- end
74
-
75
- def unsubscribe(subscriber)
76
- @sublist.remove(subscriber.subject, subscriber)
77
- end
78
-
79
- def route_to_subscribers(subject, reply, msg)
80
- @sublist.match(subject).each do |subscriber|
81
- # Skip anyone in the closing state
82
- next if subscriber.conn.closing
83
-
84
- trace "Matched subscriber", subscriber[:subject], subscriber[:sid], subscriber.conn.client_info
85
- subscriber.conn.send_data("MSG #{subject} #{subscriber.sid} #{reply} #{msg.bytesize}#{CR_LF}")
86
- subscriber.conn.send_data(msg)
87
- subscriber.conn.send_data(CR_LF)
88
-
89
- # Check the outbound queue here and react if need be..
90
- if subscriber.conn.get_outbound_data_size > MAX_OUTBOUND_SIZE
91
- subscriber.conn.error_close SLOW_CONSUMER
92
- log "Slow consumer dropped", subscriber.conn.client_info
93
- end
94
- end
95
- end
96
-
97
- def auth_ok?(user, pass)
98
- user == @options[:user] && pass == @options[:pass]
99
- end
100
-
101
- def cid
102
- @cid+=1
103
- end
104
-
105
- def info_string
106
- @info.to_json
107
- end
108
-
109
- end
110
- end
111
-
112
- module Connection #:nodoc:
113
-
114
- attr_reader :cid, :closing
115
-
116
- def client_info
117
- @client_info ||= Socket.unpack_sockaddr_in(get_peername)
118
- end
119
-
120
- def post_init
121
- @cid = Server.cid
122
- @subscriptions = {}
123
- @verbose = @pedantic = true # suppressed by most clients, but allows friendly telnet
124
- @receive_data_calls = 0
125
- send_info
126
- @auth_pending = EM.add_timer(AUTH_TIMEOUT) { connect_auth_timeout } if Server.auth_required?
127
- debug "Client connection created", client_info, cid
128
- end
129
-
130
- def connect_auth_timeout
131
- error_close AUTH_REQUIRED
132
- debug "Connection timeout due to lack of auth credentials", cid
133
- end
134
-
135
- def receive_data(data)
136
- @receive_data_calls += 1
137
- (@buf ||= '') << data
138
- close_connection and return if @buf =~ /(\006|\004)/ # ctrl+c or ctrl+d for telnet friendly
139
- while (@buf && !@buf.empty? && !@closing)
140
- # Waiting on msg payload
141
- if @msg_size
142
- if (@buf.bytesize >= (@msg_size + CR_LF_SIZE))
143
- msg = @buf.slice(0, @msg_size)
144
- process_msg(msg)
145
- @buf = @buf.slice((msg.bytesize + CR_LF_SIZE), @buf.bytesize)
146
- else # Waiting for additional msg data
147
- return
148
- end
149
- # Waiting on control line
150
- elsif @buf =~ /^(.*)\r\n/
151
- @buf = $'
152
- process_op($1)
153
- else # Waiting for additional data for control line
154
- # This is not normal. Close immediately
155
- if @buf.bytesize > MAX_CONTROL_LINE_SIZE
156
- debug "MAX_CONTROL_LINE exceeded, closing connection.."
157
- @closing = true
158
- close_connection
159
- end
160
- return
161
- end
162
- end
163
- # Nothing should be here.
164
- end
165
-
166
- def process_op(op)
167
- case op
168
- when PUB_OP
169
- ctrace 'PUB OP', op
170
- return if @auth_pending
171
- @pub_sub, @reply, @msg_size, = $1, $3, $4.to_i
172
- send_data PAYLOAD_TOO_BIG and return if (@msg_size > MAX_PAYLOAD_SIZE)
173
- send_data INVALID_SUBJECT and return if @pedantic && !(@pub_sub =~ SUB_NO_WC)
174
- when SUB_OP
175
- ctrace 'SUB OP', op
176
- return if @auth_pending
177
- sub, sid = $1, $2
178
- send_data INVALID_SUBJECT and return if !($1 =~ SUB)
179
- send_data INVALID_SID_TAKEN and return if @subscriptions[sid]
180
- subscriber = Subscriber.new(self, sub, sid)
181
- @subscriptions[sid] = subscriber
182
- Server.subscribe(subscriber)
183
- send_data OK if @verbose
184
- when UNSUB_OP
185
- ctrace 'UNSUB OP', op
186
- return if @xsauth_pending
187
- sid, subscriber = $1, @subscriptions[$1]
188
- send_data INVALID_SID_NOEXIST and return unless subscriber
189
- Server.unsubscribe(subscriber)
190
- @subscriptions.delete(sid)
191
- send_data OK if @verbose
192
- when PING
193
- ctrace 'PING OP', op
194
- send_data PONG_RESPONSE
195
- when CONNECT
196
- ctrace 'CONNECT OP', op
197
- begin
198
- config = JSON.parse($1, :symbolize_keys => true)
199
- process_connect_config(config)
200
- rescue => e
201
- send_data INVALID_CONFIG
202
- log_error
203
- end
204
- when INFO
205
- ctrace 'INFO OP', op
206
- send_info
207
- else
208
- ctrace 'Unknown Op', op
209
- send_data UNKNOWN_OP
210
- end
211
- end
212
-
213
- def send_info
214
- send_data "INFO #{Server.info_string}#{CR_LF}"
215
- end
216
-
217
- def process_msg(body)
218
- ctrace 'Processing msg', @pub_sub, @reply, body
219
- send_data OK if @verbose
220
- Server.route_to_subscribers(@pub_sub, @reply, body)
221
- @pub_sub = @msg_size = @reply = nil
222
- true
223
- end
224
-
225
- def process_connect_config(config)
226
- @verbose = config[:verbose] if config[:verbose] != nil
227
- @pedantic = config[:pedantic] if config[:pedantic] != nil
228
-
229
- send_data OK and return unless Server.auth_required?
230
-
231
- EM.cancel_timer(@auth_pending)
232
- if Server.auth_ok?(config[:user], config[:pass])
233
- send_data OK
234
- @auth_pending = nil
235
- else
236
- error_close AUTH_FAILED
237
- debug "Authorization failed for connection", cid
238
- end
239
- end
240
-
241
- def error_close(msg)
242
- send_data msg
243
- close_connection_after_writing
244
- @closing = true
245
- end
246
-
247
- def unbind
248
- debug "Client connection closed", client_info, cid
249
- ctrace "Receive_Data called #{@receive_data_calls} times." if @receive_data_calls > 0
250
- @subscriptions.each_value { |subscriber| Server.unsubscribe(subscriber) }
251
- EM.cancel_timer(@auth_pending) if @auth_pending
252
- @auth_pending = nil
253
- end
254
-
255
- def ctrace(*args)
256
- trace(args, "c: #{cid}")
257
- end
258
- end
259
-
260
- end
261
-
262
- def fast_uuid #:nodoc:
263
- v = [rand(0x0010000),rand(0x0010000),rand(0x0010000),
264
- rand(0x0010000),rand(0x0010000),rand(0x1000000)]
265
- "%04x%04x%04x%04x%04x%06x" % v
266
- end
267
-
268
- def log(*args) #:nodoc:
269
- args.unshift(Time.now) if NATSD::Server.log_time
270
- pp args.compact
271
- end
272
-
273
- def debug(*args) #:nodoc:
274
- log *args if NATSD::Server.debug_flag?
275
- end
276
-
277
- def trace(*args) #:nodoc:
278
- log *args if NATSD::Server.trace_flag?
279
- end
280
-
281
- def log_error(e=$!) #:nodoc:
282
- debug e, e.backtrace
283
- end
284
-
285
- def shutdown #:nodoc:
286
- puts
287
- log 'Server exiting..'
288
- EM.stop
289
- FileUtils.rm(NATSD::Server.pid_file) if NATSD::Server.pid_file
290
- exit
291
- end
292
-
293
- ['TERM','INT'].each { |s| trap(s) { shutdown } }
8
+ require "#{ep}/ext/em"
9
+ require "#{ep}/ext/bytesize"
10
+ require "#{ep}/ext/json"
11
+ require "#{ep}/server/server"
12
+ require "#{ep}/server/sublist"
13
+ require "#{ep}/server/options"
14
+ require "#{ep}/server/const"
15
+ require "#{ep}/server/util"
294
16
 
295
17
  # Do setup
296
18
  NATSD::Server.setup(ARGV.dup)
297
19
 
298
20
  # Event Loop
299
-
300
21
  EM.run {
301
-
302
22
  log "Starting #{NATSD::APP_NAME} version #{NATSD::VERSION} on port #{NATSD::Server.port}"
303
-
304
23
  begin
305
24
  EM.set_descriptor_table_size(32768) # Requires Root privileges
306
25
  EventMachine::start_server(NATSD::Server.host, NATSD::Server.port, NATSD::Connection)
@@ -309,5 +28,4 @@ EM.run {
309
28
  log_error
310
29
  exit
311
30
  end
312
-
313
31
  }
@@ -1,51 +1,61 @@
1
+
1
2
  module NATSD #:nodoc:
2
3
 
3
- VERSION = '0.3.12'
4
+ VERSION = '0.4.2'
4
5
  APP_NAME = 'nats-server'
5
6
 
6
7
  DEFAULT_PORT = 4222
8
+ DEFAULT_HOST = '0.0.0.0'
7
9
 
8
- # Ops
9
- INFO = /^INFO$/i
10
- PUB_OP = /^PUB\s+(\S+)\s+((\S+)\s+)?(\d+)$/i
11
- SUB_OP = /^SUB\s+(\S+)\s+(\S+)$/i
12
- UNSUB_OP = /^UNSUB\s+(\S+)$/i
13
- PING = /^PING$/i
14
- CONNECT = /^CONNECT\s+(.+)$/i
15
-
16
- # 1k should be plenty since payloads sans connect are payload
17
- MAX_CONTROL_LINE_SIZE = 1024
18
-
19
- # Should be using something different if > 1MB payload
20
- MAX_PAYLOAD_SIZE = (1024*1024)
10
+ # Parser
11
+ AWAITING_CONTROL_LINE = 1
12
+ AWAITING_MSG_PAYLOAD = 2
21
13
 
22
- # Maximum outbound size per client
23
- MAX_OUTBOUND_SIZE = (10*1024*1024)
14
+ # Ops - See protocol.txt for more info
15
+ INFO = /\AINFO\r\n/i
16
+ PUB_OP = /\APUB\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?(\d+)\r\n/i
17
+ SUB_OP = /\ASUB\s+([^\s\r\n]+)\s+(([^\s\r\n]+)[^\S\r\n]+)?([^\s\r\n]+)\r\n/i
18
+ UNSUB_OP = /\AUNSUB\s+([^\s\r\n]+)\s*(\s+(\d+))?\r\n/i
19
+ PING = /\APING\r\n/i
20
+ CONNECT = /\ACONNECT\s+([^\r\n]+)\r\n/i
21
+ UNKNOWN = /\A(.*)\r\n/
24
22
 
25
23
  # RESPONSES
26
24
  CR_LF = "\r\n".freeze
27
25
  CR_LF_SIZE = CR_LF.bytesize
28
- OK = "+OK #{CR_LF}".freeze
26
+ EMPTY = ''.freeze
27
+ OK = "+OK#{CR_LF}".freeze
29
28
  PONG_RESPONSE = "PONG#{CR_LF}".freeze
30
-
31
29
  INFO_RESPONSE = "#{CR_LF}".freeze
32
30
 
33
31
  # ERR responses
34
- PAYLOAD_TOO_BIG = "-ERR 'Payload size exceeded, max is #{MAX_PAYLOAD_SIZE} bytes'#{CR_LF}".freeze
32
+ PAYLOAD_TOO_BIG = "-ERR 'Payload size exceeded'#{CR_LF}".freeze
33
+ PROTOCOL_OP_TOO_BIG = "-ERR 'Protocol Operation size exceeded'#{CR_LF}".freeze
35
34
  INVALID_SUBJECT = "-ERR 'Invalid Subject'#{CR_LF}".freeze
36
35
  INVALID_SID_TAKEN = "-ERR 'Invalid Subject Identifier (sid), already taken'#{CR_LF}".freeze
37
36
  INVALID_SID_NOEXIST = "-ERR 'Invalid Subject-Identifier (sid), no subscriber registered'#{CR_LF}".freeze
38
37
  INVALID_CONFIG = "-ERR 'Invalid config, valid JSON required for connection configuration'#{CR_LF}".freeze
39
38
  AUTH_REQUIRED = "-ERR 'Authorization is required'#{CR_LF}".freeze
40
39
  AUTH_FAILED = "-ERR 'Authorization failed'#{CR_LF}".freeze
41
- UNKNOWN_OP = "-ERR 'Unkown Protocol Operation'#{CR_LF}".freeze
40
+ UNKNOWN_OP = "-ERR 'Unknown Protocol Operation'#{CR_LF}".freeze
42
41
  SLOW_CONSUMER = "-ERR 'Slow consumer detected, connection dropped'#{CR_LF}".freeze
43
42
 
44
43
  # Pedantic Mode
45
44
  SUB = /^([^\.\*>\s]+|>$|\*)(\.([^\.\*>\s]+|>$|\*))*$/
46
45
  SUB_NO_WC = /^([^\.\*>\s]+)(\.([^\.\*>\s]+))*$/
47
46
 
48
- # Autorization wait time
49
- AUTH_TIMEOUT = 5
47
+ # Some sane default thresholds
48
+
49
+ # 1k should be plenty since payloads sans connect string are separate
50
+ MAX_CONTROL_LINE_SIZE = 1024
51
+
52
+ # Should be using something different if > 1MB payload
53
+ MAX_PAYLOAD_SIZE = (1024*1024)
54
+
55
+ # Maximum outbound size per client
56
+ MAX_PENDING_SIZE = (10*1024*1024)
57
+
58
+ # Authorization wait time
59
+ AUTH_TIMEOUT = 1
50
60
 
51
61
  end
@@ -8,44 +8,45 @@ module NATSD
8
8
  class << self
9
9
  def parser
10
10
  @parser ||= OptionParser.new do |opts|
11
- opts.banner = "Usage: nats [options]"
11
+ opts.banner = "Usage: nats-server [options]"
12
12
 
13
13
  opts.separator ""
14
14
  opts.separator "Server options:"
15
15
 
16
16
  opts.on("-a", "--addr HOST", "Bind to HOST address " +
17
- "(default: #{@options[:addr]})") { |host| @options[:address] = host }
18
- opts.on("-p", "--port PORT", "Use PORT (default: #{@options[:port]})") { |port| @options[:port] = port.to_i }
17
+ "(default: #{DEFAULT_HOST})") { |host| @options[:addr] = host }
18
+ opts.on("-p", "--port PORT", "Use PORT (default: #{DEFAULT_PORT})") { |port| @options[:port] = port.to_i }
19
+ opts.on("-d", "--daemonize", "Run daemonized in the background") { @options[:daemonize] = true }
20
+ opts.on("-P", "--pid FILE", "File to store PID") { |file| @options[:pid_file] = file }
19
21
 
20
- opts.on("-d", "--daemonize", "Run daemonized in the background") { @options[:daemonize] = true }
21
- opts.on("-l", "--log FILE", "File to redirect output " +
22
- "(default: #{@options[:log_file]})") { |file| @options[:log_file] = file }
23
- opts.on("-T", "--logtime", "Timestamp log entries") { @options[:log_time] = true }
22
+ opts.on("-C", "--config FILE", "Configuration File " +
23
+ "(default: #{@options[:config_file]})") { |file| @options[:config_file] = file }
24
24
 
25
- opts.on("-P", "--pid FILE", "File to store PID " +
26
- "(default: #{@options[:pid_file]})") { |file| @options[:pid_file] = file }
25
+ opts.separator ""
26
+ opts.separator "Logging options:"
27
27
 
28
- opts.on("-C", "--config FILE", "Configuration File " +
29
- "(default: #{@options[:config_file]})") { |file| @options[:config_file] = file }
28
+ opts.on("-l", "--log FILE", "File to redirect log output") { |file| @options[:log_file] = file }
29
+ opts.on("-T", "--logtime", "Timestamp log entries (default: false)") { @options[:log_time] = true }
30
+ opts.on("-D", "--debug", "Enable debugging output") { @options[:debug] = true }
31
+ opts.on("-V", "--trace", "Trace the raw protocol") { @options[:trace] = true }
30
32
 
31
33
  opts.separator ""
32
- opts.separator "Authorization options: (Should be done in config file for production)"
34
+ opts.separator "Authorization options:"
33
35
 
34
- opts.on("--user user", "User required for connections") { |user| @options[:user] = user }
36
+ opts.on("--user user", "User required for connections") { |user| @options[:user] = user }
37
+ opts.on("--pass password", "Password required for connections") { |pass| @options[:pass] = pass }
35
38
 
36
- opts.on("--pass password", "Password required for connections") { |pass| @options[:pass] = pass }
37
- opts.on("--password password", "Password required for connections") { |pass| @options[:pass] = pass }
39
+ opts.separator ""
40
+ opts.separator "Advanced IO options:"
38
41
 
39
- opts.on("--no_epoll", "Enable epoll (Linux)") { @options[:noepoll] = true }
40
- opts.on("--kqueue", "Enable kqueue (MacOSX and BSD)") { @options[:nokqueue] = true }
42
+ opts.on("--no_epoll", "Disable epoll (Linux)") { @options[:noepoll] = true }
43
+ opts.on("--no_kqueue", "Disable kqueue (MacOSX and BSD)") { @options[:nokqueue] = true }
41
44
 
42
45
  opts.separator ""
43
46
  opts.separator "Common options:"
44
47
 
45
- opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
46
- opts.on_tail('-v', '--version', "Show version") { puts NATSD::Server.version; exit }
47
- opts.on_tail("-D", "--debug", "Set debugging on") { @options[:debug] = true }
48
- opts.on_tail("-V", "--trace", "Set tracing on of raw protocol") { @options[:trace] = true }
48
+ opts.on_tail("-h", "--help", "Show this message") { puts opts; exit }
49
+ opts.on_tail('-v', '--version', "Show version") { puts NATSD::Server.version; exit }
49
50
  end
50
51
  end
51
52
 
@@ -53,13 +54,32 @@ module NATSD
53
54
  return unless config_file = @options[:config_file]
54
55
  config = File.open(config_file) { |f| YAML.load(f) }
55
56
  # Command lines args, parsed first, will override these.
56
- [:addr, :port, :log_file, :pid_file, :user, :pass, :log_time, :debug].each do |p|
57
- c = config[p.to_s]
58
- @options[p] = c if c and not @options[p]
57
+ @options[:port] = config['port'] if @options[:port].nil?
58
+ @options[:addr] = config['net'] if @options[:addr].nil?
59
+ if auth = config['authorization']
60
+ @options[:user] = auth['user'] if @options[:user].nil?
61
+ @options[:pass] = auth['password'] if @options[:pass].nil?
62
+ @options[:token] = auth['token'] if @options[:token].nil?
63
+ @options[:auth_timeout] = auth['timeout'] if @options[:auth_timeout].nil?
59
64
  end
60
- rescue => e
61
- log "Could not read configuration file: #{e}"
62
- exit
65
+ @options[:pid_file] = config['pid_file'] if @options[:pid_file].nil?
66
+ @options[:log_file] = config['log_file'] if @options[:log_file].nil?
67
+ @options[:logtime] = config['logtime'] if @options[:logtime].nil?
68
+ @options[:debug] = config['debug'] if @options[:debug].nil?
69
+ @options[:trace] = config['trace'] if @options[:trace].nil?
70
+
71
+ # these just override if present
72
+ @options[:max_control_line] = config['max_control_line'] if config['max_control_line']
73
+ @options[:max_payload] = config['max_payload'] if config['max_payload']
74
+ @options[:max_pending] = config['max_pending'] if config['max_pending']
75
+
76
+ # just set
77
+ @options[:noepoll] = config['no_epoll'] if config['no_epoll']
78
+ @options[:nokqueue] = config['no_kqueue'] if config['no_kqueue']
79
+
80
+ rescue => e
81
+ log "Could not read configuration file: #{e}"
82
+ exit
63
83
  end
64
84
 
65
85
  def setup_logs
@@ -72,7 +92,7 @@ module NATSD
72
92
  def finalize_options
73
93
  # Addr/Port
74
94
  @options[:port] ||= DEFAULT_PORT
75
- @options[:addr] ||= '0.0.0.0'
95
+ @options[:addr] ||= DEFAULT_HOST
76
96
 
77
97
  # Debug and Tracing
78
98
  @debug_flag = @options[:debug]
@@ -80,14 +100,26 @@ module NATSD
80
100
 
81
101
  # Log timestamps
82
102
  @log_time = @options[:log_time]
83
- # setup_logs
84
103
 
85
104
  debug @options # Block pass?
86
105
  debug "DEBUG is on"
87
106
  trace "TRACE is on"
88
107
 
89
- # Auth
90
- @auth_required = (@options[:user] != nil)
108
+ # Authorization
109
+ @auth_required = (not @options[:user].nil?)
110
+
111
+ # Thresholds
112
+ @options[:max_control_line] ||= MAX_CONTROL_LINE_SIZE
113
+ @max_control_line = @options[:max_control_line]
114
+
115
+ @options[:max_payload] ||= MAX_PAYLOAD_SIZE
116
+ @max_payload = @options[:max_payload]
117
+
118
+ @options[:max_pending] ||= MAX_PENDING_SIZE
119
+ @max_pending = @options[:max_pending]
120
+
121
+ @options[:auth_timeout] ||= AUTH_TIMEOUT
122
+ @auth_timeout = @options[:auth_timeout]
91
123
  end
92
124
 
93
125
  end