Class: Pssh::Pty

Inherits:
Object
  • Object
show all
Defined in:
lib/pssh/pty.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializePty

Returns a new instance of Pty.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pssh/pty.rb', line 12

def initialize
  @stream = ''
  set_command
  clear_environment
  Thread.new do
    begin
      @read, @write, @pid = PTY.spawn(@command)
      @write.winsize = $stdout.winsize
      if new?
        system("clear")
        pssh = <<-BANNER
# [ pssh terminal ]
# Type `exit` to terminate this terminal.
BANNER
        $stdout.puts pssh
        Signal.trap(:WINCH) do
          resize!
        end
        system("stty raw -echo")
      end
      @active = true
      while @active do
        begin
          io = [@read]
          io << $stdin if new?
          rs, ws = IO.select(io)
          r = rs[0]
          while (data = r.read_nonblock(2048)) do
            if new? && r == $stdin
              @write.write_nonblock data
            else
              $stdout.write_nonblock data if new?
              data.encode!('UTF-16', 'UTF-8', :invalid => :replace, :replace => '')
              data.encode!('UTF-8', 'UTF-16')
              if data.valid_encoding?
                store data
                Pssh.socket.write data
              end
            end
          end
        rescue Exception => e
          if @active
            if e.is_a?(Errno::EAGAIN)
              retry
            else
              system("stty -raw echo") if new?
              puts 'Terminating Pssh.'
              Kernel.exit!
              @active = false
            end
          end
        end
      end
    end
  end
end

Instance Attribute Details

#attach_cmdObject (readonly)

Returns the value of attribute attach_cmd.



10
11
12
# File 'lib/pssh/pty.rb', line 10

def attach_cmd
  @attach_cmd
end

#pathObject (readonly)

Returns the value of attribute path.



9
10
11
# File 'lib/pssh/pty.rb', line 9

def path
  @path
end

#pidObject (readonly)

Returns the value of attribute pid.



7
8
9
# File 'lib/pssh/pty.rb', line 7

def pid
  @pid
end

#readObject (readonly)

Returns the value of attribute read.



4
5
6
# File 'lib/pssh/pty.rb', line 4

def read
  @read
end

#streamObject (readonly)

attr_reader :write



6
7
8
# File 'lib/pssh/pty.rb', line 6

def stream
  @stream
end

Instance Method Details

#clear_environmentObject



69
70
71
72
# File 'lib/pssh/pty.rb', line 69

def clear_environment
  ENV['TMUX'] = nil
  ENV['STY'] = nil
end

#existing?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/pssh/pty.rb', line 78

def existing?
  @existing_socket
end

#new?Boolean

Returns:

  • (Boolean)


74
75
76
# File 'lib/pssh/pty.rb', line 74

def new?
  !existing?
end

#resize!Object

Public: Resizes the PTY session based on all the open windows.

Returns nothing.



122
123
124
125
126
127
128
# File 'lib/pssh/pty.rb', line 122

def resize!
  winsizes = Pssh.socket.sessions.values.map { |sess| sess[:winsize] }
  winsizes << $stdout.winsize if new?
  y = winsizes.map { |w| w[0] }.min
  x = winsizes.map { |w| w[1] }.min
  @write.winsize = [ y, x ]
end

#send_display_message(user) ⇒ Object

Public: Sends a message to the tmux or screen display notifying of a new user that has connected.

Returns nothing.



134
135
136
137
138
139
140
141
142
143
# File 'lib/pssh/pty.rb', line 134

def send_display_message(user)
  if @existing_socket
    case Pssh.command.to_sym
    when :tmux
      `tmux -S #{@path} display-message "#{user} has connected"`
    when :screen
      `screen -S #{@path} -X wall "#{user} has connected"`
    end
  end
end

#set_commandObject



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/pssh/pty.rb', line 82

def set_command
  case Pssh.command.to_sym
  when :tmux
    if ENV['TMUX']
      @path = ENV['TMUX'].split(',').first
      @existing_socket = true
      @command = "tmux -S #{@path} attach"
    else
      @path = "/tmp/#{Pssh.default_socket_path}"
      @command = "tmux -S #{@path} new"
    end
    @attach_cmd = "tmux -S #{@path} attach"
  when :screen
    if ENV['STY']
      @path = ENV['STY']
      @existing_socket = true
      @command = "screen -S #{@path} -X multiuser on && screen -x #{@path}"
    else
      @path = Pssh.default_socket_path
      @command = "screen -S #{@path}"
      puts @command
    end
    @attach_cmd = "screen -x #{@path}"
  else
    @path = nil
    @command = ENV['SHELL'] || (`which zsh` && 'zsh') || (`which sh` && 'sh') || 'bash'
  end
end

#store(data) ⇒ Object

Internal: Store data to the stream so that when a new connection is started we can send all that data and give them the visual.

Returns nothing.



149
150
151
152
# File 'lib/pssh/pty.rb', line 149

def store(data)
  @stream << data
  @stream = @stream[-Pssh.cache_length..-1] if @stream.length > Pssh.cache_length
end

#write(data) ⇒ Object

Public: Writes to the open stream if they have access.

Returns nothing.



114
115
116
# File 'lib/pssh/pty.rb', line 114

def write(data)
  @write.write_nonblock data if Pssh.io_mode['w']
end