Class: Abalone::Terminal
- Inherits:
-
Object
- Object
- Abalone::Terminal
- Defined in:
- lib/abalone/terminal.rb
Instance Method Summary collapse
- #alive? ⇒ Boolean
-
#initialize(settings, ws, params) ⇒ Terminal
constructor
A new instance of Terminal.
- #modes=(message) ⇒ Object
- #reconnect(ws) ⇒ Object
- #resize(rows, cols) ⇒ Object
- #stop! ⇒ Object
- #terminate! ⇒ Object
- #write(message) ⇒ Object
Constructor Details
#initialize(settings, ws, params) ⇒ Terminal
Returns a new instance of Terminal.
6 7 8 9 10 11 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 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/abalone/terminal.rb', line 6 def initialize(settings, ws, params) @settings = settings @ws = ws @params = params @modes = nil @buffer = Abalone::Buffer.new ENV['TERM'] ||= 'xterm-256color' # make sure we've got a somewhat sane environment if settings.respond_to?(:bannerfile) @ws.send({'data' => File.read(settings.).encode(crlf_newline: true)}.to_json) @ws.send({'data' => "\r\n\r\n"}.to_json) end reader, @writer, @pid = PTY.spawn(*shell_command) @writer.winsize = [24,80] # there must be some form of event driven pty interaction, EM or some gem maybe? reader.sync = true @term = Thread.new do carry = [] loop do begin PTY.check(@pid, true) output = reader.read_nonblock(512).unpack('C*') # we read non-blocking to stream data as quickly as we can last_low = output.rindex { |x| x < 128 } # find the last low bit trailing = last_low +1 # use inclusive slices here data = (carry + output[0..last_low]).pack('C*').force_encoding('UTF-8') # repack into a string up until the last low bit carry = output[trailing..-1] # save the any remaining high bits and partial chars for next go-round @ws.send({'data' => data}.to_json) rescue IO::WaitReadable IO.select([reader]) retry rescue PTY::ChildExited => e warn('Terminal has exited!') @ws.close_connection @timer.terminate rescue nil @timer.join rescue nil Thread.exit end sleep(0.05) end end if @settings.respond_to? :timeout @timer = Thread.new do expiration = Time.now + @settings.timeout loop do remaining = expiration - Time.now if remaining < 0 terminate! Thread.exit end format = (remaining > 3600) ? "%H:%M:%S" : "%M:%S" time = { 'event' => 'time', 'data' => Time.at(remaining).utc.strftime(format), } @ws.send(time.to_json) sleep 1 end end end end |
Instance Method Details
#alive? ⇒ Boolean
79 80 81 |
# File 'lib/abalone/terminal.rb', line 79 def alive? @term.alive? end |
#modes=(message) ⇒ Object
109 110 111 112 113 114 |
# File 'lib/abalone/terminal.rb', line 109 def modes=() raise 'Invalid modes data type' unless .is_a? Hash @modes = .select do |key, val| ['cursorBlink', 'cursorVisible', 'bracketedPaste', 'applicationCursor'].include? key end end |
#reconnect(ws) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/abalone/terminal.rb', line 83 def reconnect(ws) if @ttl # stop the countdown warn "Stopping timeout" @ttl.terminate rescue nil @ttl.join rescue nil @ttl = nil end @ws.close_connection if @ws @ws = ws sleep 0.25 # allow the terminal to finish initialization before we blast it. if @modes @ws.send({ 'event' => 'modes', 'data' => @modes }.to_json) end @ws.send({'data' => @buffer.replay}.to_json) @writer.write "\cl" # ctrl-l forces a screen redraw end |
#resize(rows, cols) ⇒ Object
141 142 143 |
# File 'lib/abalone/terminal.rb', line 141 def resize(rows, cols) @writer.winsize = [rows, cols] end |
#stop! ⇒ Object
116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/abalone/terminal.rb', line 116 def stop! if @settings.respond_to? :ttl @ws = @buffer @ttl = Thread.new do warn "Providing a shutdown grace period of #{@settings.ttl} seconds." sleep @settings.ttl terminate! end else terminate! end end |
#terminate! ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/abalone/terminal.rb', line 129 def terminate! warn "Terminating session." Process.kill('TERM', @pid) rescue nil sleep 1 Process.kill('KILL', @pid) rescue nil [@ttl, @timer, @term].each do |thread| thread.terminate rescue nil thread.join rescue nil end end |
#write(message) ⇒ Object
105 106 107 |
# File 'lib/abalone/terminal.rb', line 105 def write() @writer.write end |