vpsadmin-client 3.0.0.master.20220107.pre.0.57b7b680 → 3.0.0.master.20220121.pre.0.b5a81113

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2cf2f56783b09bcc5716d8b477be832756ac97dc3dec347fd9a6132cab47ee5c
4
- data.tar.gz: 64807447baefa8d78eb3009f574380a646426546dbd1d014c557737a6d66e8df
3
+ metadata.gz: ce5635948bc213752357b413d4e92f8b7f2089306b9a3e02194b76f44f3617c3
4
+ data.tar.gz: 4304acd24bbecf0389a954d61ce680fece999e1128651f84e75306cf61889195
5
5
  SHA512:
6
- metadata.gz: 8d2627afb4def067352bea111d2b9008253d1957578a87662923366785c37ad772ef432ddb08d8ae1cb20f1d6d1eef88fdef2ae144b3700eb1efdc9222513eac
7
- data.tar.gz: 4ebb46b3667f022967aaf0851a0aea2ff43005729cd87df4cb2edd04d3538f1d84f0766e6874c6162ea248519ca02f974e3839c44c90fbb5a56fb477f959e29e
6
+ metadata.gz: b3c0c9029f6d14639adb9f901f4b1cc133d1518360be85d8e506e8aa285fa5a1b3e8be5cfa475ae87d8147fadf78dd55bd168593e945f59c1dc237412f714705
7
+ data.tar.gz: 35e2c3b730bf246d1a14c0a6a7cdf77c08910efa4d460aeb878a52a9d4a0210058a7450c556c7e30a08199b011464a45b17b155b13d965c2da057e14a3878309
@@ -1,5 +1,4 @@
1
- require 'eventmachine'
2
- require 'em-http'
1
+ require 'thread'
3
2
  require 'time'
4
3
  require 'json'
5
4
  require 'base64'
@@ -11,16 +10,35 @@ module VpsAdmin::CLI::Commands
11
10
  args 'VPS_ID'
12
11
  desc 'Open VPS remote console'
13
12
 
14
- class InputHandler < EventMachine::Connection
15
- attr_accessor :buffer
16
-
17
- def initialize
13
+ class InputHandler
14
+ def initialize(http_client)
15
+ @http_client = http_client
18
16
  @private_buffer = ''
19
- @buffer = ''
20
17
  @end_seq = ["\r", "\e", "."]
21
18
  @end_i = 0
19
+ @stop = false
20
+ end
21
+
22
+ def read_from(io)
23
+ begin
24
+ data = io.read_nonblock(4096)
25
+ rescue IO::WaitReadable
26
+ return
27
+ rescue Errno::EIO
28
+ stop
29
+ return
30
+ end
31
+
32
+ write(data)
22
33
  end
23
34
 
35
+ def stop?
36
+ @stop
37
+ end
38
+
39
+ protected
40
+ attr_reader :http_client
41
+
24
42
  # Data is checked on the presence of the end sequence. The first character
25
43
  # in the sequence (ENTER) can be read multiple times in a row and it is
26
44
  # to be forwarded.
@@ -29,38 +47,160 @@ module VpsAdmin::CLI::Commands
29
47
  # but stored in a private buffer. If the sequence is later broken, the private
30
48
  # buffer is forwarded and reset.
31
49
  #
32
- # If the whole end sequence is read, EM event loop is stopped.
33
- def receive_data(data)
50
+ # If the whole end sequence is read, we exit.
51
+ def write(data)
52
+ buffer = ''
53
+
34
54
  data.each_char do |char|
35
55
  if char == @end_seq[ @end_i ]
36
- if @end_i == @end_seq.size-1
37
- EM.stop
56
+ if @end_i == @end_seq.size - 1
57
+ @stop = true
38
58
  return
39
59
  end
40
60
 
41
61
  @end_i += 1
42
62
 
43
63
  if @end_i == 1
44
- @buffer += char
45
-
64
+ buffer += char
46
65
  else
47
66
  @private_buffer += char
48
67
  end
49
68
 
50
69
  elsif char == @end_seq.first
51
- @buffer += char
52
-
70
+ buffer += char
53
71
  else
54
72
  @end_i = 0
55
73
 
56
74
  unless @private_buffer.empty?
57
- @buffer += @private_buffer
75
+ buffer += @private_buffer
58
76
  @private_buffer.clear
59
77
  end
60
78
 
61
- @buffer += char
79
+ buffer += char
62
80
  end
63
81
  end
82
+
83
+ http_client.write(buffer) unless buffer.empty?
84
+ end
85
+ end
86
+
87
+ class HttpClient
88
+ def initialize(vps, token, rate)
89
+ @vps = vps
90
+ @token = token
91
+ @rate = rate
92
+ @mutex = Mutex.new
93
+ @write_buffer = ''
94
+ @stop = false
95
+ @error = false
96
+ end
97
+
98
+ def start
99
+ @thread = Thread.new { run }
100
+ end
101
+
102
+ def stop
103
+ @stop = true
104
+ end
105
+
106
+ def stop?
107
+ @stop
108
+ end
109
+
110
+ def error?
111
+ @error != false
112
+ end
113
+
114
+ def error
115
+ @error
116
+ end
117
+
118
+ def join
119
+ stop
120
+ thread.join
121
+ end
122
+
123
+ def write(data)
124
+ mutex.synchronize do
125
+ write_buffer << data
126
+ end
127
+ end
128
+
129
+ def resize(width, height)
130
+ @width = width
131
+ @height = height
132
+ end
133
+
134
+ protected
135
+ attr_reader :vps, :token, :rate, :width, :height, :write_buffer,
136
+ :mutex, :thread
137
+
138
+ def run
139
+ uri = URI("#{vps.node.location.remote_console_server}/console/feed/#{vps.id}")
140
+ start_args = [uri.host, uri.port, nil, nil, nil, nil, {
141
+ use_ssl: uri.scheme == 'https',
142
+ }]
143
+
144
+ Net::HTTP.start(*start_args) do |http|
145
+ loop do
146
+ break if stop? || error?
147
+
148
+ rate_limit { send_request(http, uri) }
149
+ end
150
+ end
151
+ end
152
+
153
+ def send_request(http, uri)
154
+ req = Net::HTTP::Post.new(uri)
155
+
156
+ keys =
157
+ mutex.synchronize do
158
+ s = write_buffer.dup
159
+ write_buffer.clear
160
+ s
161
+ end
162
+
163
+ req.set_form_data(
164
+ 'session' => token,
165
+ 'keys' => keys,
166
+ 'width' => width,
167
+ 'height' => height,
168
+ )
169
+
170
+ res = http.request(req)
171
+
172
+ unless res.is_a?(Net::HTTPSuccess)
173
+ set_error(
174
+ "Console server returned error: "+
175
+ "HTTP #{res.code} - #{res.message}\n\n#{res.body}"
176
+ )
177
+ stop
178
+ return
179
+ end
180
+
181
+ ret = JSON.parse(res.body, symbolize_names: true)
182
+
183
+ unless ret[:session]
184
+ $stdout.write(ret[:data])
185
+ set_error("Session closed.")
186
+ stop
187
+ return
188
+ end
189
+
190
+ $stdout.write(Base64.decode64(ret[:data]))
191
+ end
192
+
193
+ def rate_limit
194
+ t1 = Time.now
195
+ yield
196
+ t2 = Time.now
197
+
198
+ cooldown = rate - (t2 - t1)
199
+ sleep(cooldown) if cooldown > 0
200
+ end
201
+
202
+ def set_error(str)
203
+ @error = str
64
204
  end
65
205
  end
66
206
 
@@ -93,7 +233,7 @@ module VpsAdmin::CLI::Commands
93
233
  end
94
234
 
95
235
  puts " VPS is on #{vps.node.domain_name}, located in #{vps.node.location.label}."
96
- puts "Console router URL is #{vps.node.location.remote_console_server}"
236
+ puts "Console server URL is #{vps.node.location.remote_console_server}"
97
237
  write "Obtaining authentication token..."
98
238
 
99
239
  begin
@@ -105,31 +245,18 @@ module VpsAdmin::CLI::Commands
105
245
  exit(false)
106
246
  end
107
247
 
108
- @token = t.token
109
-
110
248
  puts
111
- puts "Connecting to remote console..."
249
+ puts "Connecting to the remote console..."
112
250
  puts "Press ENTER ESC . to exit"
113
251
  puts
114
252
 
115
253
  raw_mode do
116
- EventMachine.run do
117
- @input = EventMachine.open_keyboard(InputHandler)
118
-
119
- @http = EventMachine::HttpRequest.new(
120
- "#{vps.node.location.remote_console_server}/console/feed/#{vps_id}",
121
- ssl: {verify_peer: true},
122
- )
123
- communicate
124
- end
254
+ run_console(vps, t.token)
125
255
  end
126
256
  end
127
257
 
128
258
  protected
129
- def write(s)
130
- $stdout.write(s)
131
- $stdout.flush
132
- end
259
+ attr_reader :client
133
260
 
134
261
  def raw_mode
135
262
  state = `stty -g`
@@ -140,6 +267,7 @@ module VpsAdmin::CLI::Commands
140
267
 
141
268
  Signal.trap('WINCH') do
142
269
  @size = Terminal.size!
270
+ client.resize(@size[:width], @size[:height]) if client
143
271
  end
144
272
 
145
273
  yield
@@ -151,38 +279,35 @@ module VpsAdmin::CLI::Commands
151
279
  puts
152
280
  end
153
281
 
154
- def communicate
155
- post = @http.post(
156
- body: {
157
- session: @token,
158
- keys: @input.buffer,
159
- width: @size[:width],
160
- height: @size[:height],
161
- },
162
- keepalive: true
163
- )
282
+ def run_console(vps, token)
283
+ Thread.abort_on_exception = true
164
284
 
165
- @input.buffer = ''
285
+ @client = HttpClient.new(vps, token, @opts[:rate])
286
+ client.resize(@size[:width], @size[:height])
166
287
 
167
- post.errback do
168
- puts "Error: connection to console router failed"
169
- EventMachine.stop
170
- end
288
+ input = InputHandler.new(client)
289
+ client.start
171
290
 
172
- post.callback do
173
- ret = JSON.parse(post.response, symbolize_names: true)
291
+ loop do
292
+ res = IO.select([$stdin], [], [], 1)
293
+ input.read_from($stdin) if res
174
294
 
175
- unless ret[:session]
176
- $stdout.write(ret[:data])
177
- puts "\nSession closed."
178
- EM.stop
179
- next
180
- end
295
+ if input.stop? || client.stop?
296
+ client.join
181
297
 
182
- $stdout.write(Base64.decode64(ret[:data]))
298
+ if client.error?
299
+ write("\n")
300
+ write(client.error)
301
+ end
183
302
 
184
- EM.add_timer(@opts[:rate]) { communicate }
303
+ return
304
+ end
185
305
  end
186
306
  end
307
+
308
+ def write(s)
309
+ $stdout.write(s)
310
+ $stdout.flush
311
+ end
187
312
  end
188
313
  end
@@ -1,5 +1,5 @@
1
1
  module VpsAdmin
2
2
  module Client
3
- VERSION = '3.0.0.master.20220107-0.57b7b680'
3
+ VERSION = '3.0.0.master.20220121-0.b5a81113'
4
4
  end
5
5
  end
@@ -22,8 +22,6 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rake'
23
23
 
24
24
  spec.add_runtime_dependency 'haveapi-client', '~> 0.15.1'
25
- spec.add_runtime_dependency 'eventmachine', '~> 1.2.7'
26
- spec.add_runtime_dependency 'em-http-request', '~> 1.1.6'
27
25
  spec.add_runtime_dependency 'json'
28
26
  spec.add_runtime_dependency 'curses'
29
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vpsadmin-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.master.20220107.pre.0.57b7b680
4
+ version: 3.0.0.master.20220121.pre.0.b5a81113
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Skokan
@@ -52,34 +52,6 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.15.1
55
- - !ruby/object:Gem::Dependency
56
- name: eventmachine
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 1.2.7
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 1.2.7
69
- - !ruby/object:Gem::Dependency
70
- name: em-http-request
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 1.1.6
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 1.1.6
83
55
  - !ruby/object:Gem::Dependency
84
56
  name: json
85
57
  requirement: !ruby/object:Gem::Requirement