pssh 0.2.3 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
};
|