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

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 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