ng 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +28 -9
- data/lib/nailgun/client.rb +64 -8
- data/lib/nailgun/client/chunk_header.rb +1 -1
- data/lib/nailgun/client/version.rb +5 -0
- data/lib/ng.rb +2 -0
- data/ng.gemspec +2 -2
- data/test_app/Gemfile +7 -0
- metadata +5 -4
- data/lib/nailgun.rb +0 -49
- data/lib/nailgun/version.rb +0 -3
data/README.md
CHANGED
@@ -1,24 +1,43 @@
|
|
1
1
|
# ng - Pure-Ruby Nailgun client port
|
2
2
|
|
3
|
-
Eliminates the need to shell-out when using Nailgun
|
3
|
+
Eliminates the need to shell-out to the `ng` binary when using Nailgun, by implementing the Nailgun Protocol in pure Ruby code.
|
4
|
+
|
5
|
+
This was an experiment, so don't consider it stable.
|
6
|
+
|
7
|
+
I've noticed that Nailgun doesn't like when its IO buffer fills up, and it will if you don't empty it fast enough. Ruby may not be fast enough to handle this job, so if you're trying to send/receive lots of data, this may not work for you. If you're just sending some signals and getting small return values, it may yet.
|
4
8
|
|
5
9
|
## Installation
|
6
10
|
|
7
|
-
|
11
|
+
$ gem install ng
|
8
12
|
|
9
|
-
|
13
|
+
## Usage
|
10
14
|
|
11
|
-
|
15
|
+
```Ruby
|
16
|
+
# instantiate a new client (optional option overrides may be passed in)
|
17
|
+
client = Nailgun::Client.new(port: 2114)
|
12
18
|
|
13
|
-
|
19
|
+
# send this command to the server
|
20
|
+
client.run('java.Command', :arg1, 2) # args are splatted on the instance method
|
14
21
|
|
15
|
-
|
22
|
+
# shouldn't be strictly necessary to close the socket manually, but it's there if you want it
|
23
|
+
client.close!
|
24
|
+
```
|
16
25
|
|
17
|
-
|
26
|
+
A class method is also available:
|
18
27
|
|
19
|
-
|
28
|
+
```Ruby
|
29
|
+
Nailgun::Client.run('java.Command', [:arg1, 2], port: 2114) # args must be explicitly an array here
|
30
|
+
```
|
31
|
+
|
32
|
+
Or, if you prefer, there is a block form available, which automatically closes the socket at completion
|
33
|
+
|
34
|
+
```Ruby
|
35
|
+
Nailgun::Client.new do |client|
|
36
|
+
|
37
|
+
client.run('java.Command', [:arg1, 2])
|
20
38
|
|
21
|
-
|
39
|
+
end
|
40
|
+
```
|
22
41
|
|
23
42
|
## Contributing
|
24
43
|
|
data/lib/nailgun/client.rb
CHANGED
@@ -5,6 +5,51 @@ require 'timeout'
|
|
5
5
|
|
6
6
|
module Nailgun
|
7
7
|
class Client
|
8
|
+
|
9
|
+
DEFAULTS = {
|
10
|
+
hostname: 'localhost',
|
11
|
+
port: 2113,
|
12
|
+
stdin: nil,
|
13
|
+
stdout: STDOUT,
|
14
|
+
stderr: STDERR,
|
15
|
+
env: ENV,
|
16
|
+
dir: Dir.pwd
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
CHUNK_HEADER_LEN = 5
|
20
|
+
|
21
|
+
TIMEOUT = 5
|
22
|
+
|
23
|
+
TimeoutError = Class.new(StandardError)
|
24
|
+
SocketFailedError = Class.new(StandardError)
|
25
|
+
ConnectFailedError = Class.new(StandardError)
|
26
|
+
UnexpectedChunktypeError = Class.new(StandardError)
|
27
|
+
ServerExceptionError = Class.new(StandardError)
|
28
|
+
ConnectionBrokenError = Class.new(StandardError)
|
29
|
+
BadArgumentsError = Class.new(StandardError)
|
30
|
+
OtherError = Class.new(StandardError)
|
31
|
+
|
32
|
+
EXIT_CODE_EXCEPTIONS = {
|
33
|
+
999 => SocketFailedError,
|
34
|
+
998 => ConnectFailedError,
|
35
|
+
997 => UnexpectedChunktypeError,
|
36
|
+
996 => ServerExceptionError,
|
37
|
+
995 => ConnectionBrokenError,
|
38
|
+
994 => BadArgumentsError
|
39
|
+
}.freeze
|
40
|
+
|
41
|
+
CHUNK_TYPES = {
|
42
|
+
stdin: '0',
|
43
|
+
stdout: '1',
|
44
|
+
stderr: '2',
|
45
|
+
stdin_eof: '.',
|
46
|
+
arg: 'A',
|
47
|
+
env: 'E',
|
48
|
+
dir: 'D',
|
49
|
+
cmd: 'C',
|
50
|
+
exit: 'X'
|
51
|
+
}.freeze
|
52
|
+
|
8
53
|
attr_reader :opts, :socket
|
9
54
|
|
10
55
|
# Public: Convinience method to instantiate and run the command
|
@@ -20,10 +65,16 @@ module Nailgun
|
|
20
65
|
|
21
66
|
# Public: Initialize a Client.
|
22
67
|
#
|
23
|
-
# opts = {} - a Hash of options to override the defaults in
|
68
|
+
# opts = {} - a Hash of options to override the defaults in DEFAULTS
|
24
69
|
def initialize(opts = {})
|
25
|
-
@opts =
|
70
|
+
@opts = DEFAULTS.merge(opts)
|
26
71
|
@socket = TCPSocket.new(*@opts.values_at(:hostname, :port))
|
72
|
+
|
73
|
+
if block_given?
|
74
|
+
yield self
|
75
|
+
@socket.close
|
76
|
+
return nil
|
77
|
+
end
|
27
78
|
end
|
28
79
|
|
29
80
|
# Public: Run a command on the Client instance
|
@@ -54,6 +105,11 @@ module Nailgun
|
|
54
105
|
end
|
55
106
|
}
|
56
107
|
end
|
108
|
+
|
109
|
+
# Public: Explicitly close the TCPSocket
|
110
|
+
def close!
|
111
|
+
socket.close
|
112
|
+
end
|
57
113
|
|
58
114
|
private
|
59
115
|
|
@@ -113,7 +169,7 @@ module Nailgun
|
|
113
169
|
|
114
170
|
# Private: get the next chunk from the socket, and then determine what to do with it.
|
115
171
|
def receive_chunk
|
116
|
-
Timeout.timeout(
|
172
|
+
Timeout.timeout(TIMEOUT, TimeoutError) do
|
117
173
|
length, type = receive_header
|
118
174
|
if length > 0
|
119
175
|
content = socket.read(length)
|
@@ -127,7 +183,7 @@ module Nailgun
|
|
127
183
|
#
|
128
184
|
# Returns [length, type]
|
129
185
|
def receive_header
|
130
|
-
socket.read(
|
186
|
+
socket.read(CHUNK_HEADER_LEN).unpack('NA')
|
131
187
|
end
|
132
188
|
|
133
189
|
# Private: Determine what to do with the received chunk
|
@@ -135,24 +191,24 @@ module Nailgun
|
|
135
191
|
# type - chunk type
|
136
192
|
# content - chunk content
|
137
193
|
def handle_chunk(type, content)
|
138
|
-
case t =
|
194
|
+
case t = CHUNK_TYPES.key(type)
|
139
195
|
when :stdout, :stderr
|
140
196
|
opts[t].write content
|
141
197
|
when :exit
|
142
198
|
socket.close
|
143
199
|
handle_exit(content.to_i)
|
144
200
|
else
|
145
|
-
raise
|
201
|
+
raise UnexpectedChunktypeError.new([type, content].join(?;))
|
146
202
|
end
|
147
203
|
end
|
148
204
|
|
149
205
|
def handle_exit(code)
|
150
206
|
if code == 0
|
151
207
|
throw :exit
|
152
|
-
elsif ex =
|
208
|
+
elsif ex = EXIT_CODE_EXCEPTIONS[code]
|
153
209
|
raise ex.new
|
154
210
|
else
|
155
|
-
raise
|
211
|
+
raise OtherError.new(code.to_s)
|
156
212
|
end
|
157
213
|
end
|
158
214
|
|
data/lib/ng.rb
ADDED
data/ng.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../lib/nailgun/version', __FILE__)
|
2
|
+
require File.expand_path('../lib/nailgun/client/version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ['Ryan Taylor Long']
|
@@ -13,5 +13,5 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
14
|
gem.name = 'ng'
|
15
15
|
gem.require_paths = ['lib']
|
16
|
-
gem.version = Nailgun::VERSION
|
16
|
+
gem.version = Nailgun::Client::VERSION
|
17
17
|
end
|
data/test_app/Gemfile
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ng
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-11-02 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Pure-Ruby Nailgun client port
|
15
15
|
email:
|
@@ -23,12 +23,13 @@ files:
|
|
23
23
|
- LICENSE
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
-
- lib/nailgun.rb
|
27
26
|
- lib/nailgun/client.rb
|
28
27
|
- lib/nailgun/client/chunk.rb
|
29
28
|
- lib/nailgun/client/chunk_header.rb
|
30
|
-
- lib/nailgun/version.rb
|
29
|
+
- lib/nailgun/client/version.rb
|
30
|
+
- lib/ng.rb
|
31
31
|
- ng.gemspec
|
32
|
+
- test_app/Gemfile
|
32
33
|
homepage: ''
|
33
34
|
licenses: []
|
34
35
|
post_install_message:
|
data/lib/nailgun.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require_relative 'nailgun/version'
|
2
|
-
require_relative 'nailgun/client'
|
3
|
-
|
4
|
-
module Nailgun
|
5
|
-
|
6
|
-
DEFAULTS = {
|
7
|
-
hostname: 'localhost',
|
8
|
-
port: 2113,
|
9
|
-
stdin: nil,
|
10
|
-
stdout: STDOUT,
|
11
|
-
stderr: STDERR,
|
12
|
-
env: ENV,
|
13
|
-
dir: Dir.pwd
|
14
|
-
}.freeze
|
15
|
-
|
16
|
-
CHUNK_HEADER_LEN = 5
|
17
|
-
|
18
|
-
TIMEOUT = 5
|
19
|
-
|
20
|
-
TimeoutError = Class.new(StandardError)
|
21
|
-
SocketFailedError = Class.new(StandardError)
|
22
|
-
ConnectFailedError = Class.new(StandardError)
|
23
|
-
UnexpectedChunktypeError = Class.new(StandardError)
|
24
|
-
ServerExceptionError = Class.new(StandardError)
|
25
|
-
ConnectionBrokenError = Class.new(StandardError)
|
26
|
-
BadArgumentsError = Class.new(StandardError)
|
27
|
-
OtherError = Class.new(StandardError)
|
28
|
-
|
29
|
-
EXIT_CODE_EXCEPTIONS = {
|
30
|
-
999 => SocketFailedError,
|
31
|
-
998 => ConnectFailedError,
|
32
|
-
997 => UnexpectedChunktypeError,
|
33
|
-
996 => ServerExceptionError,
|
34
|
-
995 => ConnectionBrokenError,
|
35
|
-
994 => BadArgumentsError
|
36
|
-
}.freeze
|
37
|
-
|
38
|
-
CHUNK_TYPES = {
|
39
|
-
stdin: '0',
|
40
|
-
stdout: '1',
|
41
|
-
stderr: '2',
|
42
|
-
stdin_eof: '.',
|
43
|
-
arg: 'A',
|
44
|
-
env: 'E',
|
45
|
-
dir: 'D',
|
46
|
-
cmd: 'C',
|
47
|
-
exit: 'X'
|
48
|
-
}.freeze
|
49
|
-
end
|
data/lib/nailgun/version.rb
DELETED