em-wssh 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +42 -9
- data/lib/em/wssh.rb +1 -1
- data/lib/em/wssh/client.rb +1 -1
- data/lib/em/wssh/connect.rb +8 -1
- data/lib/em/wssh/ephemeral.rb +119 -0
- data/lib/em/wssh/exe.rb +3 -2
- data/lib/em/wssh/help.rb +46 -46
- data/lib/em/wssh/index.js +212 -0
- data/lib/em/wssh/server.rb +8 -1
- data/lib/em/wssh/service.rb +5 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ef81d191ad0809a51504e1f789f5e40f6c882be
|
4
|
+
data.tar.gz: da12d0d652fccf49292e6ee59917b607694d7af6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ed9868c3ed61ce056cfdc261a391ce2f8b5607fb8ff8cc99efe94babf248e316698a988ef97f160e2cf7e1f0213503956e90d27f7f73702f3f181d90470e82f
|
7
|
+
data.tar.gz: d60cee8efb8911ce45bfb880e036dff03ba8e65dd334e3c6ccf007de95248e8cd161c473384a6b18aff20b4ce31cad1429581079373e5cd7156a5df1eeefa839
|
data/README.md
CHANGED
@@ -11,7 +11,7 @@ Ruby version of ssh thru websocket proxying.
|
|
11
11
|
Add this line to your application's Gemfile:
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
gem 'em-wssh'
|
14
|
+
gem 'em-wssh'
|
15
15
|
```
|
16
16
|
|
17
17
|
And then execute:
|
@@ -50,7 +50,7 @@ Running client from terminal is not very useful. It should be called by ssh clie
|
|
50
50
|
ssh -o ProxyCommand='wssh client wss://server.host.com/ssh/%h' sshd.local
|
51
51
|
```
|
52
52
|
|
53
|
-
By default
|
53
|
+
By default nginx has 60 seconds timeout. To prevent idle connection to drop,
|
54
54
|
one can use `ServerAliveInterval` parameter:
|
55
55
|
|
56
56
|
```sh
|
@@ -92,22 +92,26 @@ s.loop!
|
|
92
92
|
```ruby
|
93
93
|
require 'em/wssh/client'
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
95
|
+
c=EventMachine::Wssh::Client
|
96
|
+
c.options[:uri]='wss://server.host.com/ssh/sshd.local'
|
97
|
+
c.loop!
|
98
98
|
```
|
99
99
|
|
100
100
|
```ruby
|
101
101
|
require 'em/wssh/connect'
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
103
|
+
p=EventMachine::Wssh::Connect
|
104
|
+
p.options.merge! base: '.', all: true, uri: 'wss://server.host.com/ssh/sshd.local'
|
105
|
+
p.loop!
|
106
106
|
```
|
107
107
|
|
108
|
+
Use `go!` method instead `loop!` to mimic cli behavour (command line parsing).
|
109
|
+
|
108
110
|
Some options are not accesible to `wssh` command and can be used only programmaticaly.
|
109
111
|
|
110
|
-
|
112
|
+
### Ephemeral module
|
113
|
+
|
114
|
+
Eg, EventMachine::Wssh::Connect has option `onlisten` that allows listening to ephemeral port:
|
111
115
|
|
112
116
|
```ruby
|
113
117
|
#!/usr/bin/env ruby
|
@@ -134,6 +138,35 @@ x=Net::SSH.start 'sshd.local', 'root',
|
|
134
138
|
puts x.exec! 'hostname'
|
135
139
|
```
|
136
140
|
|
141
|
+
Unfortunately, EventMachine fails to run in thread inside Capistrano.
|
142
|
+
But Connect proxy still can run in separate process.
|
143
|
+
To do this, module Ephemeral was forged:
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
task :wssh do
|
147
|
+
require 'net/ssh/proxy/http'
|
148
|
+
require 'em/wssh/ephemeral'
|
149
|
+
|
150
|
+
port = EventMachine::Wssh::Ephemeral.allocate 'ws://localhost:4567/test'
|
151
|
+
|
152
|
+
proxy = Net::SSH::Proxy::HTTP.new 'localhost', port
|
153
|
+
|
154
|
+
roles(:all).each{|h| h.wssh_proxy proxy }
|
155
|
+
end
|
156
|
+
|
157
|
+
class SSHKit::Host
|
158
|
+
def wssh_proxy proxy
|
159
|
+
@ssh_options[:proxy]=proxy
|
160
|
+
end
|
161
|
+
end
|
162
|
+
```
|
163
|
+
Use this task `cap stage wssh task(s)...` to tunnel all Capistrano ssh traffic through
|
164
|
+
WSSH server.
|
165
|
+
|
166
|
+
In addition, if WSSH URL is secure (wss: or https:) and Ephemeral module is running on Windows,
|
167
|
+
it automagically starts small Node.js process that wraps traffic into TLS.
|
168
|
+
This behavour can be disabled by setting Ephemeral.options[:tlswrap]=false
|
169
|
+
|
137
170
|
## Data flow
|
138
171
|
|
139
172
|
Normal SSH session is very simple:
|
data/lib/em/wssh.rb
CHANGED
data/lib/em/wssh/client.rb
CHANGED
data/lib/em/wssh/connect.rb
CHANGED
@@ -22,7 +22,7 @@ module Connect
|
|
22
22
|
puts <<-EOF
|
23
23
|
Simple HTTP CONNECT proxy to WSSH daemon
|
24
24
|
|
25
|
-
|
25
|
+
#{Exe.usage} [options...] ws[s]://host[:port]/uri
|
26
26
|
EOF
|
27
27
|
helptions
|
28
28
|
end
|
@@ -66,6 +66,12 @@ Usage: #{Exe.biname} [options...] ws[s]://host[:port]/uri
|
|
66
66
|
def onopen
|
67
67
|
log "Connected to WSSHD"
|
68
68
|
http.onopen
|
69
|
+
pinger
|
70
|
+
end
|
71
|
+
|
72
|
+
def pinger
|
73
|
+
return unless t=Connect.options[:ping]
|
74
|
+
@timer=EM::PeriodicTimer.new(t){@ws.ping if @ws}
|
69
75
|
end
|
70
76
|
|
71
77
|
def onmessage data
|
@@ -85,6 +91,7 @@ Usage: #{Exe.biname} [options...] ws[s]://host[:port]/uri
|
|
85
91
|
def bye
|
86
92
|
http.close_connection if http
|
87
93
|
@ws.close if @ws
|
94
|
+
@timer.cancel if @timer
|
88
95
|
instance_variables.each{|v| remove_instance_variable v if '@count'!=v.to_s}
|
89
96
|
end
|
90
97
|
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require_relative 'service'
|
2
|
+
|
3
|
+
module EventMachine::Wssh
|
4
|
+
class Ephemeral
|
5
|
+
extend Service
|
6
|
+
|
7
|
+
@options={
|
8
|
+
tlswrap: true,
|
9
|
+
base: '.',
|
10
|
+
pid: 'tmp/pids/ephemeral.pid',
|
11
|
+
log: 'log/ephemeral.log',
|
12
|
+
tls: 'log/tls.log',
|
13
|
+
}
|
14
|
+
|
15
|
+
%i(log options mkdir).each do |meth|
|
16
|
+
define_method meth do |*args|
|
17
|
+
self.class.send meth, *args
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
require 'socket'
|
23
|
+
@sock=Addrinfo.tcp('127.0.0.1', 0).listen 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def myport
|
27
|
+
Socket.unpack_sockaddr_in(@sock.getsockname).first
|
28
|
+
end
|
29
|
+
|
30
|
+
def rport
|
31
|
+
sock=@sock.accept.first
|
32
|
+
at_exit{sock}
|
33
|
+
sock.gets.to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
def tlswrap uri
|
37
|
+
return uri unless options[:tlswrap] and Gem.win_platform?
|
38
|
+
require 'uri'
|
39
|
+
z = URI uri
|
40
|
+
return uri unless %w(wss https).include? z.scheme
|
41
|
+
log "Running TLS Wrapper..."
|
42
|
+
spawn 'node', '.', myport.to_s, z.host,
|
43
|
+
chdir: __dir__,
|
44
|
+
%i(out err)=>File.open(mkdir(:tls), 'a')
|
45
|
+
z.scheme='ws'
|
46
|
+
z.host='localhost'
|
47
|
+
z.port=rport
|
48
|
+
z.to_s
|
49
|
+
end
|
50
|
+
|
51
|
+
def allocate uri
|
52
|
+
uri = tlswrap uri
|
53
|
+
|
54
|
+
log "Running WSSH proxy..."
|
55
|
+
spawn *%w(bundle exec wssh ephemeral), myport.to_s, uri,
|
56
|
+
%i(out err)=>File.open(mkdir(:log), 'a')
|
57
|
+
|
58
|
+
rport
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.allocate uri
|
62
|
+
new.allocate uri
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.help
|
66
|
+
require_relative 'exe'
|
67
|
+
puts <<-EOF
|
68
|
+
Run HTTP proxy on ephemeral port
|
69
|
+
|
70
|
+
#{Exe.usage} <port> <uri>
|
71
|
+
|
72
|
+
For internal use.
|
73
|
+
EOF
|
74
|
+
exit
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.go!
|
78
|
+
help if 2!=ARGV.length
|
79
|
+
require_relative 'connect'
|
80
|
+
|
81
|
+
pid
|
82
|
+
|
83
|
+
Connect.options.merge!(
|
84
|
+
port: 0,
|
85
|
+
uri: ARGV[1],
|
86
|
+
ping: 50,
|
87
|
+
onlisten: Proc.new{|port| onlisten port},
|
88
|
+
)
|
89
|
+
Connect.loop!
|
90
|
+
end
|
91
|
+
|
92
|
+
module Parent
|
93
|
+
def initialize port
|
94
|
+
@port=port
|
95
|
+
@c=EM::Wssh::Connect
|
96
|
+
log "Listening to port", port
|
97
|
+
end
|
98
|
+
|
99
|
+
def log *args
|
100
|
+
@c.log *args
|
101
|
+
end
|
102
|
+
|
103
|
+
def post_init
|
104
|
+
log "Connected to parent"
|
105
|
+
send_data "#{@port}\n"
|
106
|
+
end
|
107
|
+
|
108
|
+
def unbind
|
109
|
+
log "Parent disconnected"
|
110
|
+
EM.stop_event_loop
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.onlisten port
|
115
|
+
EM.connect 'localhost', ARGV[0], Parent, port
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
data/lib/em/wssh/exe.rb
CHANGED
@@ -22,6 +22,7 @@ module Exe
|
|
22
22
|
.map{|n|m.const_get n}
|
23
23
|
.grep(Module)
|
24
24
|
.select{|m| m.respond_to? :go!}
|
25
|
+
.select{|m| m.const_defined? :Title}
|
25
26
|
.map{|m| [m.name.split(/\W+/).last.downcase, m]}
|
26
27
|
.sort_by{|x| x[0]}
|
27
28
|
]
|
@@ -39,8 +40,8 @@ module Exe
|
|
39
40
|
exit
|
40
41
|
end
|
41
42
|
|
42
|
-
def self.
|
43
|
-
"wssh "+File.basename(caller_locations.first.path).sub(/[.][^.]*\Z/, '')
|
43
|
+
def self.usage
|
44
|
+
"Usage: wssh "+File.basename(caller_locations.first.path).sub(/[.][^.]*\Z/, '')
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
data/lib/em/wssh/help.rb
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
require_relative 'exe'
|
2
|
-
|
3
|
-
module EventMachine::Wssh
|
4
|
-
module Help
|
5
|
-
|
6
|
-
Title='Show this help'
|
7
|
-
|
8
|
-
def self.go!
|
9
|
-
if mod = Exe.command?(ARGV.shift)
|
10
|
-
command mod
|
11
|
-
else
|
12
|
-
top
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.top
|
17
|
-
require_relative 'all'
|
18
|
-
|
19
|
-
puts <<-EOT
|
20
|
-
WSSH suite v#{VERSION}
|
21
|
-
|
22
|
-
Usage: wssh command [parameters...]
|
23
|
-
|
24
|
-
Available commands:
|
25
|
-
|
26
|
-
EOT
|
27
|
-
Exe.commands.each{|cmd, mod| puts " wssh #{cmd}\t#{mod::Title
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.command mod
|
31
|
-
if mod.respond_to? :help
|
32
|
-
mod.help
|
33
|
-
else
|
34
|
-
puts mod::Title
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.help
|
39
|
-
puts <<-EOT
|
40
|
-
Shows help for WSSH suite or individual commands
|
41
|
-
|
42
|
-
|
43
|
-
EOT
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
1
|
+
require_relative 'exe'
|
2
|
+
|
3
|
+
module EventMachine::Wssh
|
4
|
+
module Help
|
5
|
+
|
6
|
+
Title='Show this help'
|
7
|
+
|
8
|
+
def self.go!
|
9
|
+
if mod = Exe.command?(ARGV.shift)
|
10
|
+
command mod
|
11
|
+
else
|
12
|
+
top
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.top
|
17
|
+
require_relative 'all'
|
18
|
+
|
19
|
+
puts <<-EOT
|
20
|
+
WSSH suite v#{VERSION}
|
21
|
+
|
22
|
+
Usage: wssh command [parameters...]
|
23
|
+
|
24
|
+
Available commands:
|
25
|
+
|
26
|
+
EOT
|
27
|
+
Exe.commands.each{|cmd, mod| puts " wssh #{cmd}\t#{mod::Title}"}
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.command mod
|
31
|
+
if mod.respond_to? :help
|
32
|
+
mod.help
|
33
|
+
else
|
34
|
+
puts mod::Title
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.help
|
39
|
+
puts <<-EOT
|
40
|
+
Shows help for WSSH suite or individual commands
|
41
|
+
|
42
|
+
#{Exe.usage} [command]
|
43
|
+
EOT
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
//
|
2
|
+
// Simple stunnel for Websocket
|
3
|
+
//
|
4
|
+
net = require('net')
|
5
|
+
ssl = require('tls')
|
6
|
+
|
7
|
+
if(4!=process.argv.length) help()
|
8
|
+
|
9
|
+
var Host = process.argv[3]
|
10
|
+
|
11
|
+
net.createServer(Req)
|
12
|
+
.listen(0, On)
|
13
|
+
|
14
|
+
var
|
15
|
+
myport,
|
16
|
+
Count=0,
|
17
|
+
_log=log
|
18
|
+
|
19
|
+
function help()
|
20
|
+
{
|
21
|
+
path = require('path')
|
22
|
+
log('Usage:', path.basename(__filename), 'port host')
|
23
|
+
process.exit()
|
24
|
+
}
|
25
|
+
|
26
|
+
function On()
|
27
|
+
{
|
28
|
+
myport = this.address().port;
|
29
|
+
log("Listening", this.address())
|
30
|
+
net.connect(process.argv[2], 'localhost')
|
31
|
+
.on('connect', pConnect)
|
32
|
+
.on('end', pEnd)
|
33
|
+
.on('error', pError)
|
34
|
+
}
|
35
|
+
|
36
|
+
function pConnect()
|
37
|
+
{
|
38
|
+
log('Connected to parent')
|
39
|
+
this.write(''+myport+'\n')
|
40
|
+
}
|
41
|
+
|
42
|
+
function pEnd()
|
43
|
+
{
|
44
|
+
log('Parent closed')
|
45
|
+
process.exit()
|
46
|
+
}
|
47
|
+
|
48
|
+
function pError(err)
|
49
|
+
{
|
50
|
+
log('Parent error', err)
|
51
|
+
process.exit()
|
52
|
+
}
|
53
|
+
|
54
|
+
function Req(conn)
|
55
|
+
{
|
56
|
+
var
|
57
|
+
No=++Count, hs=[], prolog, body, tls
|
58
|
+
|
59
|
+
function log()
|
60
|
+
{
|
61
|
+
_log.apply(this, ['<'+No+'>'].concat([].slice.call(arguments)))
|
62
|
+
}
|
63
|
+
|
64
|
+
log("Client connected from", conn.remoteAddress+':'+conn.remotePort)
|
65
|
+
|
66
|
+
conn
|
67
|
+
.on('readable', cRead)
|
68
|
+
.on('end', cClose)
|
69
|
+
.on('error', cError)
|
70
|
+
|
71
|
+
function cRead()
|
72
|
+
{
|
73
|
+
var x
|
74
|
+
while(null!=(x=this.read()))
|
75
|
+
body ? queue(x) : headers(x)
|
76
|
+
}
|
77
|
+
|
78
|
+
function cClose()
|
79
|
+
{
|
80
|
+
log('Client disconnected')
|
81
|
+
bye()
|
82
|
+
}
|
83
|
+
|
84
|
+
function cError(e)
|
85
|
+
{
|
86
|
+
log('Client error', e)
|
87
|
+
bye()
|
88
|
+
}
|
89
|
+
|
90
|
+
function bye()
|
91
|
+
{
|
92
|
+
conn.end()
|
93
|
+
if(tls) tls.end()
|
94
|
+
}
|
95
|
+
|
96
|
+
function queue(data)
|
97
|
+
{
|
98
|
+
if(Array.isArray(body))
|
99
|
+
body.push(data)
|
100
|
+
else
|
101
|
+
send(data)
|
102
|
+
}
|
103
|
+
|
104
|
+
function headers(data)
|
105
|
+
{
|
106
|
+
prolog = prolog ? Buffer.concat([prolog, data]) : data
|
107
|
+
while(splitHdrs()){}
|
108
|
+
}
|
109
|
+
|
110
|
+
function splitHdrs()
|
111
|
+
{
|
112
|
+
for(var cr, L=prolog.length, i=0; i<L; i++)
|
113
|
+
if(10==prolog[i])
|
114
|
+
{
|
115
|
+
L = prolog
|
116
|
+
prolog = prolog.slice(i+1)
|
117
|
+
header(L.slice(0, i-(cr ? 1 : 0)).toString())
|
118
|
+
return true
|
119
|
+
}
|
120
|
+
else
|
121
|
+
cr = 13==prolog[i]
|
122
|
+
}
|
123
|
+
|
124
|
+
function header(line)
|
125
|
+
{
|
126
|
+
if(!line.length)
|
127
|
+
tlsConnect()
|
128
|
+
else
|
129
|
+
hs.push(line)
|
130
|
+
}
|
131
|
+
|
132
|
+
function tlsConnect()
|
133
|
+
{
|
134
|
+
body=[prolog]
|
135
|
+
prolog=new Buffer(0)
|
136
|
+
patchHeaders()
|
137
|
+
tls = ssl.connect({
|
138
|
+
servername: Host,
|
139
|
+
host: Host,
|
140
|
+
port: 443
|
141
|
+
})
|
142
|
+
tls
|
143
|
+
.on('secureConnect', tConnect)
|
144
|
+
.on('readable', tData)
|
145
|
+
.on('end', tEnd)
|
146
|
+
.on('error', tError)
|
147
|
+
}
|
148
|
+
|
149
|
+
function patchHeaders()
|
150
|
+
{
|
151
|
+
if(!hs.length) return
|
152
|
+
var verb = hs.shift()
|
153
|
+
hs=['Host', 'Origin']
|
154
|
+
.map(hostHeader)
|
155
|
+
.concat(hs.filter(filterHeader))
|
156
|
+
hs.unshift(verb)
|
157
|
+
}
|
158
|
+
|
159
|
+
function send(data)
|
160
|
+
{
|
161
|
+
if(data.length)
|
162
|
+
tls.write(data)
|
163
|
+
}
|
164
|
+
|
165
|
+
function tConnect()
|
166
|
+
{
|
167
|
+
log('TLS connected', 'Auth='+this.authorized,'CN='+this.getPeerCertificate().subject.CN)
|
168
|
+
send(hs.join('\r\n')+'\r\n\r\n')
|
169
|
+
body.forEach(send)
|
170
|
+
body = true
|
171
|
+
}
|
172
|
+
|
173
|
+
function tData()
|
174
|
+
{
|
175
|
+
var x
|
176
|
+
while(null!=(x=this.read()))
|
177
|
+
if(x.length) conn.write(x)
|
178
|
+
}
|
179
|
+
|
180
|
+
function tError(err)
|
181
|
+
{
|
182
|
+
log('TLS error', err)
|
183
|
+
bye()
|
184
|
+
}
|
185
|
+
|
186
|
+
function tEnd()
|
187
|
+
{
|
188
|
+
log('TLS closed')
|
189
|
+
bye()
|
190
|
+
}
|
191
|
+
}
|
192
|
+
|
193
|
+
function hostHeader(s)
|
194
|
+
{
|
195
|
+
return s+': '+Host
|
196
|
+
}
|
197
|
+
|
198
|
+
function filterHeader(s)
|
199
|
+
{
|
200
|
+
return !/^(?:host|origin):/i.test(s)
|
201
|
+
}
|
202
|
+
|
203
|
+
function log()
|
204
|
+
{
|
205
|
+
var
|
206
|
+
d = new Date()
|
207
|
+
console.info.apply(
|
208
|
+
console,
|
209
|
+
['['+d.toISOString().replace('T', ' ').replace(/Z$/, '')
|
210
|
+
+d.toTimeString().split(/\s+/)[1].replace(/^\w+/, ' ')+']']
|
211
|
+
.concat([].slice.call(arguments)))
|
212
|
+
}
|
data/lib/em/wssh/server.rb
CHANGED
@@ -22,7 +22,7 @@ module Server
|
|
22
22
|
puts <<-EOF
|
23
23
|
Proxy ssh connection through websocket
|
24
24
|
|
25
|
-
|
25
|
+
#{Exe.usage} [options...]
|
26
26
|
EOF
|
27
27
|
helptions
|
28
28
|
end
|
@@ -94,6 +94,12 @@ EOF
|
|
94
94
|
end
|
95
95
|
log "Connecting to", host
|
96
96
|
EM.connect host, 22, Ssh, self
|
97
|
+
pinger
|
98
|
+
end
|
99
|
+
|
100
|
+
def pinger
|
101
|
+
return unless t=Server.options[:ping]
|
102
|
+
@timer=EM::PeriodicTimer.new(t){ws.ping if ws}
|
97
103
|
end
|
98
104
|
|
99
105
|
def ondata msg
|
@@ -148,6 +154,7 @@ EOF
|
|
148
154
|
def bye
|
149
155
|
ssh.close_connection if ssh
|
150
156
|
ws.close if ws
|
157
|
+
@timer.cancel if @timer
|
151
158
|
instance_variables.each{|v| remove_instance_variable v if '@count'!=v.to_s}
|
152
159
|
end
|
153
160
|
end
|
data/lib/em/wssh/service.rb
CHANGED
@@ -17,6 +17,7 @@ module Service
|
|
17
17
|
-d --daemon Run daemonized
|
18
18
|
-h --help Show this help
|
19
19
|
-l --listen=port Listen to port
|
20
|
+
-p --ping[=sec] Periodic ping
|
20
21
|
-v --version Show version
|
21
22
|
EOF
|
22
23
|
exit 1
|
@@ -30,6 +31,7 @@ EOF
|
|
30
31
|
['-d', '--daemon', GetoptLong::NO_ARGUMENT],
|
31
32
|
['-a', '--all', GetoptLong::NO_ARGUMENT],
|
32
33
|
['-v', '--version', GetoptLong::NO_ARGUMENT],
|
34
|
+
['-p', '--ping', GetoptLong::OPTIONAL_ARGUMENT],
|
33
35
|
)
|
34
36
|
begin
|
35
37
|
opts.each do |opt, arg|
|
@@ -42,6 +44,9 @@ EOF
|
|
42
44
|
options[:base]=File.expand_path arg
|
43
45
|
when '-a'
|
44
46
|
options[:host]='0.0.0.0'
|
47
|
+
when '-p'
|
48
|
+
arg=arg.to_i
|
49
|
+
options[:ping]= arg<1 ? 50 : arg
|
45
50
|
when '-v'
|
46
51
|
puts VERSION
|
47
52
|
exit 1
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-wssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stas Ukolov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: em-websocket
|
@@ -87,8 +87,10 @@ files:
|
|
87
87
|
- lib/em/wssh/all.rb
|
88
88
|
- lib/em/wssh/client.rb
|
89
89
|
- lib/em/wssh/connect.rb
|
90
|
+
- lib/em/wssh/ephemeral.rb
|
90
91
|
- lib/em/wssh/exe.rb
|
91
92
|
- lib/em/wssh/help.rb
|
93
|
+
- lib/em/wssh/index.js
|
92
94
|
- lib/em/wssh/server.rb
|
93
95
|
- lib/em/wssh/service.rb
|
94
96
|
- lib/em/wssh/version.rb
|