pssh 0.2.3 → 0.3.3
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.
- checksums.yaml +15 -0
- data/LICENSE +22 -0
- data/README.md +14 -7
- data/assets/pssh.js +129 -0
- data/assets/style.css +2 -1
- data/assets/term.js +4 -3
- data/lib/pssh.rb +28 -5
- data/lib/pssh/cli.rb +2 -2
- data/lib/pssh/client.rb +9 -6
- data/lib/pssh/console.rb +10 -13
- data/lib/pssh/pty.rb +155 -0
- data/lib/pssh/socket.rb +21 -101
- data/lib/pssh/version.rb +1 -1
- data/lib/pssh/{web_console.rb → web.rb} +1 -1
- data/views/index.haml +22 -20
- metadata +9 -21
- data/assets/wssh.js +0 -134
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MDVmMzVhYTE2ZjRhMGZiMmE0NWM1ZjdmM2Q3ZTUyZjljYTJiOTc1Nw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZDE1MDQ0MTBkOTA4NzhlY2UwMDBmZmJmZTU5NmQ5NmJjZmYyNzZhZA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NWQ4MTAxMTA1OGVjNzNmM2FkMWJjNDYzYjNiNGFhYzMzNzVmMTNlMDhiYjU0
|
10
|
+
MjkwN2I2ZmM5OTQ3MTNhMTZlZjVjNjkwZWUwNTEyMWMxM2RkMzNiODI5MDMz
|
11
|
+
ZTU2YTdkYjY2NzlhNmJlZmRhNmQ4OTI5YTM4ZjZkZDYwNTBmMTk=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
OGRiZTE1OWQ4M2MyY2RkMWUxOGY2MGQ5ZjVmMzBlOTE3ODVlMzZjOGFmNjM0
|
14
|
+
ZDIzZjM2ODMzNGM4ODJiYmI5YjM4MzkyZTJjMWYyY2JkYjY1OTk0ZjdjOWU1
|
15
|
+
MDZmNjQzMmI1ZGM0Yzg4MzE2ZmE4NzQ0OWZhYWIxZjJlNDg3Njc=
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Kelly Martin, except where otherwise noted
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -8,26 +8,32 @@ user, figuring out how the heck to get tmux to integrate everything, and then
|
|
8
8
|
opening up port 22 on your firewall to let everyone know you're ready and willing
|
9
9
|
for the all the brute force attacks your network can handle.
|
10
10
|
|
11
|
-
What if it was as simple as opening up a new tab in tmux or screen,
|
12
|
-
letters, then sharing a URL with a friend?
|
11
|
+
What if it was as simple as opening up a new shell, or a tab in tmux or screen,
|
12
|
+
typing four letters, then sharing a URL with a friend?
|
13
13
|
|
14
14
|
Pssh. Is that even possible?
|
15
15
|
|
16
16
|
Yup.
|
17
17
|
|
18
18
|
```ruby
|
19
|
-
gem install pssh
|
19
|
+
> gem install pssh
|
20
|
+
# to get started, just run it from the command line
|
21
|
+
> pssh
|
20
22
|
```
|
21
23
|
|
22
24
|
It defaults to running on port 8022, but throw in a `-p PORT` flag and you're
|
23
25
|
up and running on whatever port. If you're in a tmux or screen session, it'll
|
24
|
-
share that. If you're not,
|
26
|
+
share that. If you're not, no worries. **Pssh has its own session sharing built in.**
|
27
|
+
And if you want to use tmux or screen, go right ahead and use the `-c tmux` flag.
|
25
28
|
|
26
|
-
|
27
|
-
kick people off, and
|
29
|
+
If you're already in a tmux or screen session, you'll have a pseudo-terminal
|
30
|
+
that lets you see who's connected, kick people off, and a few other handy things.
|
31
|
+
|
32
|
+
If you started `pssh` in a plain shell, you'll be immediately transported into
|
33
|
+
that shell. Just type `exit` to quit and kick everyone else off too.
|
28
34
|
|
29
35
|
Check out all the options with the `-h` flag, or list the console commands by
|
30
|
-
typing `help` when you start up Pssh.
|
36
|
+
typing `help` when you start up Pssh inside tmux/screen.
|
31
37
|
|
32
38
|
There's also support in there for HTTP basic authentication if you're running
|
33
39
|
behind that layer. But that adds to the complexities.
|
@@ -36,3 +42,4 @@ You know what makes all this even easier? <a href="https://getportly.com">Portly
|
|
36
42
|
Install Portly in seconds, add `localhost:8022` to your connections, and you can
|
37
43
|
add authentication and share a classy URL right there on the spot.
|
38
44
|
|
45
|
+
Thanks to those who are working on <a href="https://github.com/chjj/term.js/">term.js</a> and <a href="https://github.com/aluzzardi/wssh">WSSH</a> for making the job easier.
|
data/assets/pssh.js
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
/*
|
2
|
+
PSSH Javascript Client
|
3
|
+
Modeled after WSSH: https://github.com/aluzzardi/wssh
|
4
|
+
|
5
|
+
Usage:
|
6
|
+
|
7
|
+
var client = new PsshClient();
|
8
|
+
|
9
|
+
client.connect({
|
10
|
+
// Connection and authentication parameters
|
11
|
+
username: 'root',
|
12
|
+
hostname: 'localhost',
|
13
|
+
authentication_method: 'password', // can either be password or private_key
|
14
|
+
password: 'secretpassword', // do not provide when using private_key
|
15
|
+
key_passphrase: 'secretpassphrase', // *may* be provided if the private_key is encrypted
|
16
|
+
|
17
|
+
// Callbacks
|
18
|
+
onError: function(error) {
|
19
|
+
// Called upon an error
|
20
|
+
console.error(error);
|
21
|
+
},
|
22
|
+
onConnect: function() {
|
23
|
+
// Called after a successful connection to the server
|
24
|
+
console.debug('Connected!');
|
25
|
+
|
26
|
+
client.send('ls\n'); // You can send data back to the server by using PsshClient.send()
|
27
|
+
},
|
28
|
+
onClose: function() {
|
29
|
+
// Called when the remote closes the connection
|
30
|
+
console.debug('Connection Reset By Peer');
|
31
|
+
},
|
32
|
+
onData: function(data) {
|
33
|
+
// Called when data is received from the server
|
34
|
+
console.debug('Received: ' + data);
|
35
|
+
}
|
36
|
+
});
|
37
|
+
|
38
|
+
*/
|
39
|
+
|
40
|
+
function PsshClient(uuid) {
|
41
|
+
this.uuid=uuid;
|
42
|
+
};
|
43
|
+
|
44
|
+
PsshClient.prototype._generateEndpoint = function(options) {
|
45
|
+
if (window.location.protocol == 'https:') {
|
46
|
+
var protocol = 'wss://';
|
47
|
+
} else {
|
48
|
+
var protocol = 'ws://';
|
49
|
+
}
|
50
|
+
var endpoint = protocol + window.location.host +
|
51
|
+
'/socket?uuid=' + this.uuid + '&username=' + encodeURIComponent(options.username);
|
52
|
+
if (options.authentication_method == 'password') {
|
53
|
+
endpoint += '?password=' + encodeURIComponent(options.password);
|
54
|
+
} else if (options.authentication_method == 'private_key') {
|
55
|
+
endpoint += '?private_key=' + encodeURIComponent(options.private_key);
|
56
|
+
if (options.key_passphrase !== undefined) {
|
57
|
+
endpoint += '&key_passphrase=' + encodeURIComponent(options.key_passphrase);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
return endpoint;
|
61
|
+
};
|
62
|
+
|
63
|
+
PsshClient.prototype.startSocket = function() {
|
64
|
+
|
65
|
+
var ping;
|
66
|
+
var _self = this;
|
67
|
+
var connected = true;
|
68
|
+
|
69
|
+
if (window.WebSocket) {
|
70
|
+
this._connection = new WebSocket(this.endpoint);
|
71
|
+
}
|
72
|
+
else if (window.MozWebSocket) {
|
73
|
+
this._connection = MozWebSocket(this.endpoint);
|
74
|
+
}
|
75
|
+
else {
|
76
|
+
this.options.onError('WebSocket Not Supported');
|
77
|
+
return ;
|
78
|
+
}
|
79
|
+
|
80
|
+
this._connection.onopen = function() {
|
81
|
+
ping = window.setInterval(function() {
|
82
|
+
_self._connection.send('p');
|
83
|
+
}, 10000);
|
84
|
+
_self.options.onConnect();
|
85
|
+
};
|
86
|
+
|
87
|
+
this._connection.onmessage = function (evt) {
|
88
|
+
var data = JSON.parse(evt.data.toString());
|
89
|
+
if (data.error !== undefined) {
|
90
|
+
_self.options.onError(data.error);
|
91
|
+
} else if (data.close !== undefined) {
|
92
|
+
connected = false;
|
93
|
+
} else {
|
94
|
+
_self.options.onData(data.data);
|
95
|
+
}
|
96
|
+
};
|
97
|
+
|
98
|
+
this._connection.onclose = function(evt) {
|
99
|
+
if (connected) {
|
100
|
+
window.clearInterval(ping);
|
101
|
+
_self.reconnect();
|
102
|
+
} else {
|
103
|
+
_self.options.onClose();
|
104
|
+
}
|
105
|
+
};
|
106
|
+
|
107
|
+
};
|
108
|
+
|
109
|
+
PsshClient.prototype.connect = function(options) {
|
110
|
+
this.endpoint = this._generateEndpoint(options);
|
111
|
+
this.options = options;
|
112
|
+
this.startSocket();
|
113
|
+
};
|
114
|
+
|
115
|
+
PsshClient.prototype.send = function(data) {
|
116
|
+
this._connection.send('d' + data);
|
117
|
+
};
|
118
|
+
|
119
|
+
PsshClient.prototype.start = function(width, height) {
|
120
|
+
this._connection.send('s' + height + ',' + width);
|
121
|
+
};
|
122
|
+
|
123
|
+
PsshClient.prototype.resize = function(width, height) {
|
124
|
+
this._connection.send('r' + height + ',' + width);
|
125
|
+
};
|
126
|
+
|
127
|
+
PsshClient.prototype.reconnect = function() {
|
128
|
+
this.startSocket();
|
129
|
+
};
|
data/assets/style.css
CHANGED
data/assets/term.js
CHANGED
@@ -1579,9 +1579,10 @@ Terminal.prototype.write = function(data) {
|
|
1579
1579
|
// Send Device Attributes (Primary DA).
|
1580
1580
|
// CSI > P s c
|
1581
1581
|
// Send Device Attributes (Secondary DA)
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1582
|
+
// We don't need this because we are controlling the device elsewhere.
|
1583
|
+
// case 'c':
|
1584
|
+
// this.sendDeviceAttributes(this.params);
|
1585
|
+
// break;
|
1585
1586
|
|
1586
1587
|
// CSI Pm d
|
1587
1588
|
// Line Position Absolute [row] (default = [1,column]) (VPA).
|
data/lib/pssh.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'haml'
|
2
2
|
require 'io/console'
|
3
3
|
require 'json'
|
4
|
+
require 'open-uri'
|
4
5
|
require 'optparse'
|
5
6
|
require 'pty'
|
6
7
|
require 'readline'
|
@@ -11,15 +12,18 @@ require 'rack/websocket'
|
|
11
12
|
require 'pssh/cli'
|
12
13
|
require 'pssh/client'
|
13
14
|
require 'pssh/console'
|
15
|
+
require 'pssh/pty'
|
14
16
|
require 'pssh/socket'
|
15
17
|
require 'pssh/version'
|
16
|
-
require 'pssh/
|
18
|
+
require 'pssh/web'
|
17
19
|
|
18
20
|
module Pssh
|
19
21
|
|
20
22
|
DEFAULT_IO_MODE = 'rw'
|
21
|
-
DEFAULT_SOCKET_PREFIX = '
|
23
|
+
DEFAULT_SOCKET_PREFIX = 'pssh'
|
22
24
|
DEFAULT_PORT = 8022
|
25
|
+
DEFAULT_CACHE_LENGTH = 4096
|
26
|
+
PSSH_DOMAIN = 'pssh.herokuapp.com'
|
23
27
|
|
24
28
|
class << self
|
25
29
|
|
@@ -29,6 +33,8 @@ module Pssh
|
|
29
33
|
attr_writer :open_sessions
|
30
34
|
attr_writer :port
|
31
35
|
attr_writer :prompt
|
36
|
+
attr_accessor :socket_path
|
37
|
+
attr_accessor :cache_length
|
32
38
|
attr_accessor :client
|
33
39
|
attr_accessor :socket
|
34
40
|
attr_accessor :pty
|
@@ -54,6 +60,23 @@ module Pssh
|
|
54
60
|
@io_mode ||= DEFAULT_IO_MODE
|
55
61
|
end
|
56
62
|
|
63
|
+
# Public: This method retrieves the current IP address and compresses
|
64
|
+
# it into a short url that can be shared to redirect to your site.
|
65
|
+
def share_url
|
66
|
+
return @share_url if @share_url
|
67
|
+
ip = open("http://#{PSSH_DOMAIN}/ip").read
|
68
|
+
.split('.')
|
69
|
+
.map { |x| x.to_i.to_s(36).rjust(2,'0') }
|
70
|
+
.join('')
|
71
|
+
@share_url = "http://#{PSSH_DOMAIN}/#{ip}#{port.to_i.to_s(36)}"
|
72
|
+
end
|
73
|
+
|
74
|
+
# Public: This sets the amount of data that will be stored to show
|
75
|
+
# new connections when they join.
|
76
|
+
def cache_length
|
77
|
+
@cache_length ||= DEFAULT_CACHE_LENGTH
|
78
|
+
end
|
79
|
+
|
57
80
|
# Public: This is the prefix that will be used to set up the socket for tmux or screen.
|
58
81
|
#
|
59
82
|
# Returns a String.
|
@@ -66,7 +89,7 @@ module Pssh
|
|
66
89
|
#
|
67
90
|
# Returns a String.
|
68
91
|
def default_socket_path
|
69
|
-
@
|
92
|
+
@socket_path ||= "#{socket_prefix}-#{SecureRandom.uuid}"
|
70
93
|
end
|
71
94
|
|
72
95
|
# Public: This is the tool which we are going to use for our multiplexing. If
|
@@ -79,9 +102,9 @@ module Pssh
|
|
79
102
|
@command ||=
|
80
103
|
(ENV['TMUX'] && :tmux) ||
|
81
104
|
(ENV['STY'] && :screen) ||
|
82
|
-
(`which tmux` && :tmux) ||
|
83
|
-
(`which screen` && :screen) ||
|
84
105
|
:shell
|
106
|
+
#(`which tmux` && :tmux) ||
|
107
|
+
#(`which screen` && :screen) ||
|
85
108
|
end
|
86
109
|
|
87
110
|
# Public: Allow configuring details of Pssh by making use of a block.
|
data/lib/pssh/cli.rb
CHANGED
@@ -33,8 +33,8 @@ module Pssh
|
|
33
33
|
options[:command] = command
|
34
34
|
end
|
35
35
|
|
36
|
-
opts.on('-s
|
37
|
-
options[:
|
36
|
+
opts.on('-s NAME', '--socket NAME', String, 'Set the socket that will be used for connecting (socket-name)') do |socket|
|
37
|
+
options[:socket_path] = socket
|
38
38
|
end
|
39
39
|
|
40
40
|
opts.on( '-h', '--help', 'Display this help.' ) do
|
data/lib/pssh/client.rb
CHANGED
@@ -2,23 +2,26 @@ module Pssh
|
|
2
2
|
class Client
|
3
3
|
|
4
4
|
def initialize
|
5
|
-
@pty = Pssh.pty = Pssh::
|
6
|
-
@
|
5
|
+
@pty = Pssh.pty = Pssh::Pty.new
|
6
|
+
@socket = Pssh.socket = Pssh::Socket.new
|
7
|
+
@web = Pssh.web = Pssh::Web.new
|
7
8
|
@app = Rack::Builder.new do
|
8
9
|
map "/assets/" do
|
9
10
|
run Rack::File.new "#{Pssh.base_path}/assets/"
|
10
11
|
end
|
11
12
|
map "/socket" do
|
12
|
-
run Pssh.
|
13
|
+
run Pssh.socket
|
13
14
|
end
|
14
15
|
map "/" do
|
15
16
|
run Pssh.web
|
16
17
|
end
|
17
18
|
end
|
18
|
-
Thread.new do
|
19
|
-
@console = Console.new(pty: @pty, web: @web)
|
20
|
-
end
|
21
19
|
Thin::Logging.silent = true
|
20
|
+
if Pssh.pty.existing?
|
21
|
+
Thread.new do
|
22
|
+
@console = Console.new
|
23
|
+
end
|
24
|
+
end
|
22
25
|
Rack::Handler::Thin.run @app, Port: Pssh.port
|
23
26
|
end
|
24
27
|
|
data/lib/pssh/console.rb
CHANGED
@@ -17,17 +17,14 @@ module Pssh
|
|
17
17
|
|
18
18
|
def initialize(opts = {})
|
19
19
|
|
20
|
-
@pty = opts[:pty]
|
21
|
-
@web = opts[:web]
|
22
|
-
|
23
20
|
begin
|
24
21
|
puts "[ pssh terminal ]"
|
25
22
|
puts "Service started on port #{Pssh.port}."
|
23
|
+
puts "Share this url for access: #{Pssh.share_url}"
|
26
24
|
puts "Type 'help' for more information."
|
27
25
|
|
28
26
|
Readline.completion_append_character = " "
|
29
27
|
Readline.completion_proc = completion_proc
|
30
|
-
|
31
28
|
while command = Readline.readline(Pssh.prompt, true)
|
32
29
|
command.strip!
|
33
30
|
command.gsub!(/\s+/, ' ')
|
@@ -35,30 +32,30 @@ module Pssh
|
|
35
32
|
when 'help'
|
36
33
|
puts BANNER.gsub(/^ {6}/,'')
|
37
34
|
when 'exit'
|
38
|
-
|
35
|
+
Pssh.socket.kill_all_sessions
|
39
36
|
Kernel.exit!
|
40
37
|
when 'info'
|
41
38
|
puts 'Current Configuration:'
|
42
|
-
if
|
43
|
-
puts "Socket: #{
|
44
|
-
puts "(Attach to this socket with `#{
|
39
|
+
if Pssh.pty.path
|
40
|
+
puts "Socket: #{Pssh.pty.path}"
|
41
|
+
puts "(Attach to this socket with `#{Pssh.pty.attach_cmd}`)"
|
45
42
|
else
|
46
43
|
puts 'Connections are made to a vanilla shell.'
|
47
44
|
end
|
48
45
|
when 'list sessions', 'list'
|
49
|
-
|
46
|
+
Pssh.socket.sessions.each do |k,v|
|
50
47
|
puts v[:user_string]
|
51
48
|
end
|
52
49
|
when /^kill-sessions?\s?(.*)$/
|
53
50
|
if $1 == '--all'
|
54
51
|
puts 'disconnecting all clients'
|
55
|
-
|
52
|
+
Pssh.socket.kill_all_sessions
|
56
53
|
else
|
57
54
|
puts "disconnecting #{$1}"
|
58
|
-
if
|
59
|
-
|
55
|
+
if Pssh.socket.sessions.keys.include?($1)
|
56
|
+
Pssh.socket.sessions[$1][:socket].close!
|
60
57
|
else
|
61
|
-
|
58
|
+
Pssh.socket.sessions.each do |k, sess|
|
62
59
|
if sess[:username] == $1
|
63
60
|
sess[:socket].close!
|
64
61
|
end
|
data/lib/pssh/pty.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module Pssh
|
2
|
+
class Pty
|
3
|
+
|
4
|
+
attr_reader :read
|
5
|
+
#attr_reader :write
|
6
|
+
attr_reader :stream
|
7
|
+
attr_reader :pid
|
8
|
+
|
9
|
+
attr_reader :path
|
10
|
+
attr_reader :attach_cmd
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@stream = ''
|
14
|
+
set_command
|
15
|
+
clear_environment
|
16
|
+
Thread.new do
|
17
|
+
begin
|
18
|
+
@read, @write, @pid = PTY.spawn(@command)
|
19
|
+
@write.winsize = $stdout.winsize
|
20
|
+
if new?
|
21
|
+
system("clear")
|
22
|
+
pssh = <<-BANNER
|
23
|
+
# [ pssh terminal ]
|
24
|
+
# Type `exit` to terminate this terminal.
|
25
|
+
BANNER
|
26
|
+
$stdout.puts pssh
|
27
|
+
Signal.trap(:WINCH) do
|
28
|
+
resize!
|
29
|
+
end
|
30
|
+
system("stty raw -echo")
|
31
|
+
end
|
32
|
+
@active = true
|
33
|
+
while @active do
|
34
|
+
begin
|
35
|
+
io = [@read]
|
36
|
+
io << $stdin if new?
|
37
|
+
rs, ws = IO.select(io)
|
38
|
+
r = rs[0]
|
39
|
+
while (data = r.read_nonblock(2048)) do
|
40
|
+
if new? && r == $stdin
|
41
|
+
@write.write_nonblock data
|
42
|
+
else
|
43
|
+
$stdout.write_nonblock data if new?
|
44
|
+
data.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
|
45
|
+
data.encode!('UTF-8', 'UTF-16')
|
46
|
+
if data.valid_encoding?
|
47
|
+
store data
|
48
|
+
Pssh.socket.write data
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
rescue Exception => e
|
53
|
+
if @active
|
54
|
+
if e.is_a?(Errno::EAGAIN)
|
55
|
+
retry
|
56
|
+
else
|
57
|
+
system("stty -raw echo") if new?
|
58
|
+
puts 'Terminating Pssh.'
|
59
|
+
Kernel.exit!
|
60
|
+
@active = false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def clear_environment
|
70
|
+
ENV['TMUX'] = nil
|
71
|
+
ENV['STY'] = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def new?
|
75
|
+
!existing?
|
76
|
+
end
|
77
|
+
|
78
|
+
def existing?
|
79
|
+
@existing_socket
|
80
|
+
end
|
81
|
+
|
82
|
+
def set_command
|
83
|
+
case Pssh.command.to_sym
|
84
|
+
when :tmux
|
85
|
+
if ENV['TMUX']
|
86
|
+
@path = ENV['TMUX'].split(',').first
|
87
|
+
@existing_socket = true
|
88
|
+
@command = "tmux -S #{@path} attach"
|
89
|
+
else
|
90
|
+
@path = "/tmp/#{Pssh.default_socket_path}"
|
91
|
+
@command = "tmux -S #{@path} new"
|
92
|
+
end
|
93
|
+
@attach_cmd = "tmux -S #{@path} attach"
|
94
|
+
when :screen
|
95
|
+
if ENV['STY']
|
96
|
+
@path = ENV['STY']
|
97
|
+
@existing_socket = true
|
98
|
+
@command = "screen -S #{@path} -X multiuser on && screen -x #{@path}"
|
99
|
+
else
|
100
|
+
@path = Pssh.default_socket_path
|
101
|
+
@command = "screen -S #{@path}"
|
102
|
+
puts @command
|
103
|
+
end
|
104
|
+
@attach_cmd = "screen -x #{@path}"
|
105
|
+
else
|
106
|
+
@path = nil
|
107
|
+
@command = ENV['SHELL'] || (`which zsh` && 'zsh') || (`which sh` && 'sh') || 'bash'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Public: Writes to the open stream if they have access.
|
112
|
+
#
|
113
|
+
# Returns nothing.
|
114
|
+
def write(data)
|
115
|
+
@write.write_nonblock data if Pssh.io_mode['w']
|
116
|
+
end
|
117
|
+
|
118
|
+
# Public: Resizes the PTY session based on all the open
|
119
|
+
# windows.
|
120
|
+
#
|
121
|
+
# Returns nothing.
|
122
|
+
def resize!
|
123
|
+
winsizes = Pssh.socket.sessions.values.map { |sess| sess[:winsize] }
|
124
|
+
winsizes << $stdout.winsize if new?
|
125
|
+
y = winsizes.map { |w| w[0] }.min
|
126
|
+
x = winsizes.map { |w| w[1] }.min
|
127
|
+
@write.winsize = [ y, x ]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Public: Sends a message to the tmux or screen display notifying of a
|
131
|
+
# new user that has connected.
|
132
|
+
#
|
133
|
+
# Returns nothing.
|
134
|
+
def send_display_message(user)
|
135
|
+
if @existing_socket
|
136
|
+
case Pssh.command.to_sym
|
137
|
+
when :tmux
|
138
|
+
`tmux -S #{@path} display-message "#{user} has connected"`
|
139
|
+
when :screen
|
140
|
+
`screen -S #{@path} -X wall "#{user} has connected"`
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
# Internal: Store data to the stream so that when a new connection
|
146
|
+
# is started we can send all that data and give them the visual.
|
147
|
+
#
|
148
|
+
# Returns nothing.
|
149
|
+
def store(data)
|
150
|
+
@stream << data
|
151
|
+
@stream = @stream[-Pssh.cache_length..-1] if @stream.length > Pssh.cache_length
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
data/lib/pssh/socket.rb
CHANGED
@@ -13,36 +13,6 @@ module Pssh
|
|
13
13
|
@killed_sessions = []
|
14
14
|
@existing_socket = false
|
15
15
|
|
16
|
-
self.send Pssh.command.to_sym
|
17
|
-
end
|
18
|
-
|
19
|
-
def tmux
|
20
|
-
if ENV['TMUX']
|
21
|
-
@path = ENV['TMUX'].split(',').first
|
22
|
-
@existing_socket = true
|
23
|
-
@command = "tmux -S #{@path} attach"
|
24
|
-
else
|
25
|
-
@path = Pssh.default_socket_path
|
26
|
-
@command = "tmux -S #{@path} new"
|
27
|
-
end
|
28
|
-
@attach_cmd = "tmux -S #{@path} attach"
|
29
|
-
end
|
30
|
-
|
31
|
-
def screen
|
32
|
-
if ENV['STY']
|
33
|
-
@path = ENV['STY']
|
34
|
-
@existing_socket = true
|
35
|
-
@command = "screen -S #{@path} -X multiuser on && screen -x #{@path}"
|
36
|
-
else
|
37
|
-
@path = Pssh.default_socket_path
|
38
|
-
@command = "screen -m -S #{@path}"
|
39
|
-
end
|
40
|
-
@attach_cmd = "screen -x #{@path}"
|
41
|
-
end
|
42
|
-
|
43
|
-
def shell
|
44
|
-
@path = nil
|
45
|
-
@command = 'sh'
|
46
16
|
end
|
47
17
|
|
48
18
|
def params(env)
|
@@ -60,13 +30,14 @@ module Pssh
|
|
60
30
|
@sessions[uuid][:active] = true
|
61
31
|
elsif Pssh.open_sessions.keys.include?(uuid)
|
62
32
|
user_string = Pssh.open_sessions[uuid] ? "#{Pssh.open_sessions[uuid]} (#{uuid})" : uuid
|
63
|
-
|
33
|
+
Pssh.pty.send_display_message user_string
|
64
34
|
@sessions[uuid] = {
|
65
35
|
data: [],
|
66
36
|
username: Pssh.open_sessions[uuid],
|
67
37
|
user_string: user_string,
|
68
38
|
active: true,
|
69
|
-
started: false
|
39
|
+
started: false,
|
40
|
+
winsize: []
|
70
41
|
}
|
71
42
|
Pssh.open_sessions.delete uuid
|
72
43
|
else
|
@@ -82,19 +53,23 @@ module Pssh
|
|
82
53
|
Thread.new do
|
83
54
|
sleep 10
|
84
55
|
if @sessions[uuid][:active] == false
|
85
|
-
@sessions[uuid][:read].close
|
86
|
-
@sessions[uuid][:write].close
|
87
56
|
@sessions.delete uuid
|
88
57
|
print "\n#{user_string} detached.\n#{Pssh.prompt}"
|
89
58
|
end
|
90
59
|
end
|
91
60
|
end
|
92
61
|
|
62
|
+
# Public: Writes the same data to all the open sessions.
|
63
|
+
#
|
64
|
+
# Returns nothing.
|
65
|
+
def write(data)
|
66
|
+
@sessions.each do |k,v|
|
67
|
+
v[:socket].send_data({ data: data }.to_json)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
93
71
|
def close_websocket
|
94
|
-
|
95
|
-
@sessions[@uuid][:read].close if @sessions[@uuid][:read]
|
96
|
-
@sessions[@uuid][:write].close if @sessions[@uuid][:write]
|
97
|
-
@sessions[@uuid][:thread].exit if @sessions[@uuid][:thread]
|
72
|
+
self.send_data({ close: true }.to_json)
|
98
73
|
@sessions.delete @uuid
|
99
74
|
super
|
100
75
|
end
|
@@ -110,77 +85,22 @@ module Pssh
|
|
110
85
|
@killed_sessions << @uuid
|
111
86
|
end
|
112
87
|
|
113
|
-
# Internal: Sends a message to the tmux or screen display notifying of a
|
114
|
-
# new user that has connected.
|
115
|
-
#
|
116
|
-
# Returns nothing.
|
117
|
-
def send_display_message(uuid)
|
118
|
-
if @existing_socket
|
119
|
-
case Pssh.command.to_sym
|
120
|
-
when :tmux
|
121
|
-
`tmux -S #{@path} display-message "#{@sessions[uuid][:user_string]} has connected"`
|
122
|
-
when :screen
|
123
|
-
`screen -S #{@path} -X wall "#{@sessions[uuid][:user_string]} has connected"`
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def clear_environment
|
129
|
-
ENV['TMUX'] = nil
|
130
|
-
ENV['STY'] = nil
|
131
|
-
end
|
132
|
-
|
133
88
|
def on_message(env, message)
|
134
89
|
uuid = params(env)['uuid']
|
135
90
|
return unless @sessions[uuid]
|
136
91
|
case message[0]
|
137
92
|
when 's'
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
size = message[1..-1].split ','
|
144
|
-
send_display_message(uuid)
|
145
|
-
clear_environment
|
146
|
-
@sessions[uuid][:read], @sessions[uuid][:write], @sessions[uuid][:pid] = PTY.spawn(@command)
|
147
|
-
@sessions[uuid][:write].winsize = [size[1].to_i, size[0].to_i]
|
148
|
-
|
149
|
-
while(@sessions[uuid] && @sessions[uuid][:active]) do
|
150
|
-
IO.select([@sessions[uuid][:read]])
|
151
|
-
begin
|
152
|
-
while (data = @sessions[uuid][:read].readpartial(2048)) do
|
153
|
-
data.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
|
154
|
-
data.encode!('UTF-8', 'UTF-16')
|
155
|
-
if data.valid_encoding?
|
156
|
-
@sessions[uuid][:socket].send_data({ data: data }.to_json)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
rescue Exception => e
|
160
|
-
if @sessions[uuid]
|
161
|
-
if e.is_a?(Errno::EAGAIN)
|
162
|
-
retry
|
163
|
-
else
|
164
|
-
@sessions[uuid][:active] = false
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
rescue Exception => e
|
172
|
-
puts e.inspect
|
173
|
-
puts e.backtrace
|
174
|
-
puts '---'
|
175
|
-
retry
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
93
|
+
@sessions[uuid][:started] = true
|
94
|
+
size = message[1..-1].split ','
|
95
|
+
@sessions[uuid][:winsize] = [size[0].to_i, size[1].to_i]
|
96
|
+
send_data({ data: Pssh.pty.stream }.to_json)
|
97
|
+
Pssh.pty.resize!
|
179
98
|
when 'd'
|
180
|
-
|
99
|
+
Pssh.pty.write message[1..-1]
|
181
100
|
when 'r'
|
182
101
|
size = message[1..-1].split ','
|
183
|
-
@sessions[uuid][:
|
102
|
+
@sessions[uuid][:winsize] = [size[0].to_i, size[1].to_i]
|
103
|
+
Pssh.pty.resize!
|
184
104
|
end
|
185
105
|
end
|
186
106
|
end
|
data/lib/pssh/version.rb
CHANGED
data/views/index.haml
CHANGED
@@ -1,35 +1,39 @@
|
|
1
1
|
%html
|
2
2
|
%head
|
3
3
|
%script{:src => "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js", :type => "application/javascript"}
|
4
|
-
%script{:src => "assets/
|
4
|
+
%script{:src => "assets/pssh.js", :type => "application/javascript"}
|
5
5
|
%script{:src => "assets/term.js", :type => "application/javascript"}
|
6
6
|
:javascript
|
7
|
-
function
|
7
|
+
jQuery(function() {
|
8
|
+
|
9
|
+
// Calculate the width of a character
|
8
10
|
var k = document.createElement('span.monospace');
|
9
11
|
k.innerHTML = '_';
|
10
12
|
k.style.position = 'absolute';
|
11
13
|
document.body.appendChild(k);
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
k.offsetWidth,
|
16
|
-
13 // k.offsetHeight
|
14
|
+
var size = [
|
15
|
+
k.offsetWidth,
|
16
|
+
13
|
17
17
|
];
|
18
|
-
|
19
|
-
|
20
18
|
document.body.removeChild(k);
|
21
|
-
|
19
|
+
|
20
|
+
// Determine the browser width
|
22
21
|
width = parseInt($(window).width() / size[0]);
|
23
22
|
height = parseInt($(window).height() / size[1]);
|
23
|
+
|
24
|
+
// Set up the socket and the terminal
|
24
25
|
first_time = true;
|
25
|
-
var client = new
|
26
|
+
var client = new PsshClient('#{unique_id}');
|
26
27
|
var term = new Terminal(width, height, function(key) {
|
27
28
|
client.send(key);
|
28
29
|
});
|
29
30
|
term.open();
|
30
31
|
$('.terminal').detach().appendTo('#term');
|
31
|
-
|
32
|
-
|
32
|
+
|
33
|
+
// Pretty sloppy usage that when connected sends over
|
34
|
+
// the browser size so we can request the right size window.
|
35
|
+
// It also handles reconnecting, which could more than likely
|
36
|
+
// be baked into the PsshClient.
|
33
37
|
client.connect($.extend({}, {
|
34
38
|
onError: function(error) {
|
35
39
|
term.write('Error: ' + error + "\\r\\n");
|
@@ -44,26 +48,24 @@
|
|
44
48
|
onClose: function() {
|
45
49
|
term.destroy();
|
46
50
|
$('.terminal').remove();
|
47
|
-
//term.write('Connection Reset By Peer');
|
48
51
|
},
|
49
52
|
onTerminate: function() {
|
50
53
|
},
|
51
54
|
onData: function(data) {
|
52
|
-
console.log(data);
|
53
55
|
term.write(data);
|
54
56
|
}
|
55
57
|
}));
|
56
58
|
|
57
|
-
window
|
59
|
+
// When we resize the window, make sure the terminal changes too.
|
60
|
+
$(window).resize( function() {
|
58
61
|
width = parseInt($(window).width() / size[0]);
|
59
62
|
height = parseInt($(window).height() / size[1]);
|
60
63
|
client.resize(width, height);
|
61
64
|
term.resize(width, height);
|
62
|
-
};
|
65
|
+
});
|
63
66
|
|
64
|
-
|
65
|
-
}
|
67
|
+
});
|
66
68
|
%link{:href => "assets/bootstrap.css", :rel => "stylesheet"}/
|
67
69
|
%link{:href => "assets/style.css", :rel => "stylesheet"}/
|
68
|
-
%body
|
70
|
+
%body
|
69
71
|
#term
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pssh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Kelly Martin
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-16 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: json
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rack
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: thin
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ~>
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ~>
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -62,7 +55,6 @@ dependencies:
|
|
62
55
|
- !ruby/object:Gem::Dependency
|
63
56
|
name: websocket-rack
|
64
57
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
58
|
requirements:
|
67
59
|
- - ~>
|
68
60
|
- !ruby/object:Gem::Version
|
@@ -70,7 +62,6 @@ dependencies:
|
|
70
62
|
type: :runtime
|
71
63
|
prerelease: false
|
72
64
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
65
|
requirements:
|
75
66
|
- - ~>
|
76
67
|
- !ruby/object:Gem::Version
|
@@ -78,7 +69,6 @@ dependencies:
|
|
78
69
|
- !ruby/object:Gem::Dependency
|
79
70
|
name: haml
|
80
71
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
72
|
requirements:
|
83
73
|
- - ~>
|
84
74
|
- !ruby/object:Gem::Version
|
@@ -86,7 +76,6 @@ dependencies:
|
|
86
76
|
type: :runtime
|
87
77
|
prerelease: false
|
88
78
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
79
|
requirements:
|
91
80
|
- - ~>
|
92
81
|
- !ruby/object:Gem::Version
|
@@ -94,7 +83,6 @@ dependencies:
|
|
94
83
|
- !ruby/object:Gem::Dependency
|
95
84
|
name: tilt
|
96
85
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
86
|
requirements:
|
99
87
|
- - ~>
|
100
88
|
- !ruby/object:Gem::Version
|
@@ -102,7 +90,6 @@ dependencies:
|
|
102
90
|
type: :runtime
|
103
91
|
prerelease: false
|
104
92
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
93
|
requirements:
|
107
94
|
- - ~>
|
108
95
|
- !ruby/object:Gem::Version
|
@@ -117,44 +104,45 @@ extra_rdoc_files: []
|
|
117
104
|
files:
|
118
105
|
- Gemfile
|
119
106
|
- Gemfile.lock
|
107
|
+
- LICENSE
|
120
108
|
- README.md
|
121
109
|
- assets/bootstrap.css
|
110
|
+
- assets/pssh.js
|
122
111
|
- assets/style.css
|
123
112
|
- assets/term.js
|
124
|
-
- assets/wssh.js
|
125
113
|
- bin/pssh
|
126
114
|
- lib/pssh.rb
|
127
115
|
- lib/pssh/cli.rb
|
128
116
|
- lib/pssh/client.rb
|
129
117
|
- lib/pssh/console.rb
|
118
|
+
- lib/pssh/pty.rb
|
130
119
|
- lib/pssh/socket.rb
|
131
120
|
- lib/pssh/version.rb
|
132
|
-
- lib/pssh/
|
121
|
+
- lib/pssh/web.rb
|
133
122
|
- pssh.gemspec
|
134
123
|
- views/index.haml
|
135
124
|
homepage: http://pssh.me
|
136
125
|
licenses: []
|
126
|
+
metadata: {}
|
137
127
|
post_install_message:
|
138
128
|
rdoc_options: []
|
139
129
|
require_paths:
|
140
130
|
- lib
|
141
131
|
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
-
none: false
|
143
132
|
requirements:
|
144
133
|
- - ! '>='
|
145
134
|
- !ruby/object:Gem::Version
|
146
135
|
version: '0'
|
147
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
-
none: false
|
149
137
|
requirements:
|
150
138
|
- - ! '>='
|
151
139
|
- !ruby/object:Gem::Version
|
152
140
|
version: '0'
|
153
141
|
requirements: []
|
154
142
|
rubyforge_project:
|
155
|
-
rubygems_version:
|
143
|
+
rubygems_version: 2.0.7
|
156
144
|
signing_key:
|
157
|
-
specification_version:
|
145
|
+
specification_version: 4
|
158
146
|
summary: Pair Programming made user-friendly with your web browser (and Portly helps).
|
159
147
|
test_files: []
|
160
148
|
has_rdoc:
|
data/assets/wssh.js
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
WSSH Javascript Client
|
3
|
-
|
4
|
-
Usage:
|
5
|
-
|
6
|
-
var client = new WSSHClient();
|
7
|
-
|
8
|
-
client.connect({
|
9
|
-
// Connection and authentication parameters
|
10
|
-
username: 'root',
|
11
|
-
hostname: 'localhost',
|
12
|
-
authentication_method: 'password', // can either be password or private_key
|
13
|
-
password: 'secretpassword', // do not provide when using private_key
|
14
|
-
key_passphrase: 'secretpassphrase', // *may* be provided if the private_key is encrypted
|
15
|
-
|
16
|
-
// Callbacks
|
17
|
-
onError: function(error) {
|
18
|
-
// Called upon an error
|
19
|
-
console.error(error);
|
20
|
-
},
|
21
|
-
onConnect: function() {
|
22
|
-
// Called after a successful connection to the server
|
23
|
-
console.debug('Connected!');
|
24
|
-
|
25
|
-
client.send('ls\n'); // You can send data back to the server by using WSSHClient.send()
|
26
|
-
},
|
27
|
-
onClose: function() {
|
28
|
-
// Called when the remote closes the connection
|
29
|
-
console.debug('Connection Reset By Peer');
|
30
|
-
},
|
31
|
-
onData: function(data) {
|
32
|
-
// Called when data is received from the server
|
33
|
-
console.debug('Received: ' + data);
|
34
|
-
}
|
35
|
-
});
|
36
|
-
|
37
|
-
*/
|
38
|
-
|
39
|
-
function WSSHClient(uuid) {
|
40
|
-
this.uuid=uuid;
|
41
|
-
};
|
42
|
-
|
43
|
-
WSSHClient.prototype._generateEndpoint = function(options) {
|
44
|
-
if (window.location.protocol == 'https:') {
|
45
|
-
var protocol = 'wss://';
|
46
|
-
} else {
|
47
|
-
var protocol = 'ws://';
|
48
|
-
}
|
49
|
-
var endpoint = protocol + window.location.host +
|
50
|
-
'/socket?uuid=' + this.uuid; ///' + encodeURIComponent(options.hostname) + '/' +
|
51
|
-
//encodeURIComponent(options.username);
|
52
|
-
/*if (options.authentication_method == 'password') {
|
53
|
-
endpoint += '?password=' + encodeURIComponent(options.password);
|
54
|
-
} else if (options.authentication_method == 'private_key') {
|
55
|
-
endpoint += '?private_key=' + encodeURIComponent(options.private_key);
|
56
|
-
if (options.key_passphrase !== undefined)
|
57
|
-
endpoint += '&key_passphrase=' + encodeURIComponent(
|
58
|
-
options.key_passphrase);
|
59
|
-
}*/
|
60
|
-
return endpoint;
|
61
|
-
};
|
62
|
-
|
63
|
-
WSSHClient.prototype.startSocket = function() {
|
64
|
-
|
65
|
-
var ping;
|
66
|
-
var _self = this;
|
67
|
-
var connected = true;
|
68
|
-
|
69
|
-
if (window.WebSocket) {
|
70
|
-
this._connection = new WebSocket(this.endpoint);
|
71
|
-
}
|
72
|
-
else if (window.MozWebSocket) {
|
73
|
-
this._connection = MozWebSocket(this.endpoint);
|
74
|
-
}
|
75
|
-
else {
|
76
|
-
this.options.onError('WebSocket Not Supported');
|
77
|
-
return ;
|
78
|
-
}
|
79
|
-
|
80
|
-
this._connection.onopen = function() {
|
81
|
-
console.log("connected");
|
82
|
-
ping = window.setInterval(function() {
|
83
|
-
_self._connection.send('p');
|
84
|
-
}, 10000);
|
85
|
-
_self.options.onConnect();
|
86
|
-
};
|
87
|
-
|
88
|
-
this._connection.onmessage = function (evt) {
|
89
|
-
console.log(evt.data);
|
90
|
-
var data = JSON.parse(evt.data.toString());
|
91
|
-
if (data.error !== undefined) {
|
92
|
-
_self.options.onError(data.error);
|
93
|
-
} else if (data.close !== undefined) {
|
94
|
-
connected = false;
|
95
|
-
} else {
|
96
|
-
_self.options.onData(data.data);
|
97
|
-
}
|
98
|
-
};
|
99
|
-
|
100
|
-
this._connection.onclose = function(evt) {
|
101
|
-
if (connected) {
|
102
|
-
window.clearInterval(ping);
|
103
|
-
_self.reconnect();
|
104
|
-
} else {
|
105
|
-
_self.options.onClose();
|
106
|
-
}
|
107
|
-
};
|
108
|
-
|
109
|
-
};
|
110
|
-
|
111
|
-
WSSHClient.prototype.connect = function(options) {
|
112
|
-
|
113
|
-
this.endpoint = this._generateEndpoint(options);
|
114
|
-
this.options = options;
|
115
|
-
|
116
|
-
this.startSocket();
|
117
|
-
|
118
|
-
};
|
119
|
-
|
120
|
-
WSSHClient.prototype.send = function(data) {
|
121
|
-
this._connection.send('d' + data);
|
122
|
-
};
|
123
|
-
|
124
|
-
WSSHClient.prototype.start = function(width, height) {
|
125
|
-
this._connection.send('s' + width + ',' + height);
|
126
|
-
};
|
127
|
-
|
128
|
-
WSSHClient.prototype.resize = function(width, height) {
|
129
|
-
this._connection.send('r' + width + ',' + height);
|
130
|
-
};
|
131
|
-
|
132
|
-
WSSHClient.prototype.reconnect = function() {
|
133
|
-
this.startSocket();
|
134
|
-
};
|