pytty 0.1.0 → 0.2.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/lib/pytty/client/cli.rb +2 -0
- data/lib/pytty/client/cli/root_command.rb +1 -0
- data/lib/pytty/client/cli/run_command.rb +8 -3
- data/lib/pytty/client/cli/stream_command.rb +40 -0
- data/lib/pytty/daemon/api/chunk.rb +28 -0
- data/lib/pytty/daemon/api/router.rb +11 -2
- data/lib/pytty/daemon/api/server.rb +6 -1
- data/lib/pytty/daemon/api/web_sockets.rb +40 -12
- data/lib/pytty/daemon/components.rb +4 -1
- data/lib/pytty/daemon/components/run.rb +6 -1
- data/lib/pytty/daemon/components/stream.rb +37 -0
- data/lib/pytty/daemon/components/web_handler.rb +11 -2
- data/lib/pytty/daemon/components/web_socket_handler.rb +37 -0
- data/lib/pytty/version.rb +1 -1
- metadata +5 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86943cf397ea5d69b0d735243100ad08ed00629b2b1ffc34157f44acb0ff2316
|
4
|
+
data.tar.gz: 5ee2c4f7c9bd1bbb9e550be3140d1c7c53f5b51f74ae3cad2f60994b1a026374
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04b69e3162611cda3e34a33dfae91a6cbad3226ae31e928d8a77dcf1e210c7b4fd766a173f182e8be7a089c2ca26cd3f6456fb13fab420695108c706649a56c3
|
7
|
+
data.tar.gz: 4a61b1ff318f39adb8918565e78a6ef7ed189c7063bcb97ce3ca9efc27593a2b73e8a9262e5542cd5c6e850eb77ddbe5c9555be8948f136f4422962d3d18c06b
|
data/Gemfile.lock
CHANGED
data/lib/pytty/client/cli.rb
CHANGED
@@ -2,18 +2,23 @@
|
|
2
2
|
require 'async'
|
3
3
|
require 'async/http'
|
4
4
|
require 'async/http/internet'
|
5
|
+
require 'json'
|
5
6
|
|
6
7
|
module Pytty
|
7
8
|
module Client
|
8
9
|
module Cli
|
9
10
|
class RunCommand < Clamp::Command
|
11
|
+
parameter "CMD ...", "command"
|
10
12
|
def execute
|
11
13
|
Async.run do
|
12
14
|
internet = Async::HTTP::Internet.new
|
13
15
|
headers = [['accept', 'application/json']]
|
14
|
-
body =
|
15
|
-
|
16
|
-
|
16
|
+
body = {
|
17
|
+
cmd: cmd_list
|
18
|
+
}.to_json
|
19
|
+
|
20
|
+
response = internet.post("http://localhost:1234/v1/run", headers, [body])
|
21
|
+
puts response.read
|
17
22
|
ensure
|
18
23
|
internet.close
|
19
24
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'async/reactor'
|
3
|
+
require 'async/io/stream'
|
4
|
+
require 'async/http/url_endpoint'
|
5
|
+
require 'async/websocket/client'
|
6
|
+
require 'io/console'
|
7
|
+
|
8
|
+
module Pytty
|
9
|
+
module Client
|
10
|
+
module Cli
|
11
|
+
class StreamCommand < Clamp::Command
|
12
|
+
parameter "CMD ...", "command"
|
13
|
+
def execute
|
14
|
+
env = {
|
15
|
+
"LINES" => IO.console.winsize.first.to_s,
|
16
|
+
"COLUMNS" => IO.console.winsize.last.to_s
|
17
|
+
}
|
18
|
+
|
19
|
+
url = "ws://localhost:1234/v1/stream"
|
20
|
+
endpoint = Async::HTTP::URLEndpoint.parse url
|
21
|
+
Async::Reactor.run do |task|
|
22
|
+
endpoint.connect do |socket|
|
23
|
+
connection = Async::WebSocket::Client.new socket, url
|
24
|
+
|
25
|
+
connection.send_message({
|
26
|
+
cmd: cmd_list,
|
27
|
+
env: env
|
28
|
+
})
|
29
|
+
|
30
|
+
while message = connection.next_message
|
31
|
+
print message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "falcon"
|
2
|
+
require_relative "router"
|
3
|
+
|
4
|
+
module Pytty
|
5
|
+
module Daemon
|
6
|
+
module Api
|
7
|
+
class Chunk
|
8
|
+
|
9
|
+
def call(env)
|
10
|
+
task = Async::Task.current
|
11
|
+
body = Async::HTTP::Body::Writable.new
|
12
|
+
task.async do |task|
|
13
|
+
10.times do
|
14
|
+
body.write "hello"
|
15
|
+
task.sleep 0.5
|
16
|
+
end
|
17
|
+
rescue Exception => ex
|
18
|
+
p ex
|
19
|
+
ensure
|
20
|
+
body.close
|
21
|
+
end
|
22
|
+
|
23
|
+
[200, {'content-type' => 'text/html; charset=utf-8'}, body]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require_relative "web_sockets"
|
2
|
+
require_relative "chunk"
|
3
|
+
|
2
4
|
require_relative "../components"
|
3
5
|
|
4
6
|
module Pytty
|
@@ -8,11 +10,18 @@ module Pytty
|
|
8
10
|
def call(env)
|
9
11
|
req = Rack::Request.new(env)
|
10
12
|
resp = case req.path_info
|
13
|
+
when "/stream"
|
14
|
+
if env["HTTP_UPGRADE"] == "websocket"
|
15
|
+
handler = Pytty::Daemon::Components::WebSocketHandler.new(env)
|
16
|
+
handler.handle
|
17
|
+
end
|
18
|
+
|
19
|
+
[404, {"Content-Type" => "text/html"}, ["websocket only"]]
|
11
20
|
when "/run"
|
12
21
|
handler = Pytty::Daemon::Components::WebHandler.new(env)
|
13
|
-
handler.handle
|
22
|
+
output = handler.handle
|
14
23
|
|
15
|
-
[200, {"Content-Type" => "text/html"}, [
|
24
|
+
[200, {"Content-Type" => "text/html"}, [output]]
|
16
25
|
when "/ws"
|
17
26
|
if env["HTTP_UPGRADE"] == "websocket"
|
18
27
|
ws = WebSockets.new env
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "falcon"
|
2
2
|
require_relative "router"
|
3
|
+
require_relative "chunk"
|
3
4
|
|
4
5
|
module Pytty
|
5
6
|
module Daemon
|
@@ -10,7 +11,11 @@ module Pytty
|
|
10
11
|
|
11
12
|
def run
|
12
13
|
rack_app = Rack::Builder.new do
|
13
|
-
use Rack::CommonLogger
|
14
|
+
#use Rack::CommonLogger
|
15
|
+
|
16
|
+
map "/chunk" do
|
17
|
+
run Chunk.new
|
18
|
+
end
|
14
19
|
map "/v1" do
|
15
20
|
run Router.new
|
16
21
|
end
|
@@ -10,23 +10,51 @@ module Pytty
|
|
10
10
|
|
11
11
|
@connection = Async::WebSocket::Server.open(env)
|
12
12
|
@@connections << @connection
|
13
|
+
|
14
|
+
@messages = Async::Queue.new
|
15
|
+
@writes = Async::Queue.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@@connections.each do |connection|
|
20
|
+
connection.close
|
21
|
+
end
|
22
|
+
@@connections = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def read
|
26
|
+
@messages.dequeue
|
27
|
+
end
|
28
|
+
|
29
|
+
def write(message)
|
30
|
+
@writes.enqueue message
|
13
31
|
end
|
14
32
|
|
15
33
|
def handle
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
34
|
+
Async::Task.current.async do
|
35
|
+
while message = @connection.next_event
|
36
|
+
type = case message
|
37
|
+
when WebSocket::Driver::OpenEvent
|
38
|
+
puts "ws: open #{@env["REMOTE_ADDR"]}"
|
39
|
+
when WebSocket::Driver::CloseEvent
|
40
|
+
puts "ws: close #{@env["REMOTE_ADDR"]}"
|
41
|
+
@@connections.delete @connection
|
42
|
+
when WebSocket::Driver::MessageEvent
|
43
|
+
puts "ws: message #{@env["REMOTE_ADDR"]}"
|
44
|
+
@messages.enqueue message.data
|
45
|
+
else
|
46
|
+
raise "ws: unknown #{message.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Async::Task.current.async do |task|
|
52
|
+
while message = @writes.dequeue
|
25
53
|
@@connections.each do |connection|
|
26
|
-
connection.send_message(message
|
54
|
+
connection.send_message(message)
|
55
|
+
rescue Exception => ex
|
56
|
+
#TODO
|
27
57
|
end
|
28
|
-
else
|
29
|
-
raise "ws: unknown #{message.inspect}"
|
30
58
|
end
|
31
59
|
end
|
32
60
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'pty'
|
3
|
+
require 'io/console'
|
4
|
+
|
5
|
+
module Pytty
|
6
|
+
module Daemon
|
7
|
+
module Components
|
8
|
+
class Stream
|
9
|
+
def initialize(cmd:, env:)
|
10
|
+
@cmd = cmd
|
11
|
+
@env = env
|
12
|
+
end
|
13
|
+
|
14
|
+
def run(stream:)
|
15
|
+
pipe = IO.pipe
|
16
|
+
stderr = Async::IO::Generic.new(pipe.first)
|
17
|
+
stderr_writer = Async::IO::Generic.new(pipe.last)
|
18
|
+
|
19
|
+
|
20
|
+
cmd, args = @cmd
|
21
|
+
process_stdout, process_stdin, pid = PTY.spawn(@env, cmd, *args, err: stderr_writer.fileno)
|
22
|
+
stderr_writer.close
|
23
|
+
|
24
|
+
stdout = Async::IO::Generic.new process_stdout
|
25
|
+
stdin = Async::IO::Generic.new process_stdin
|
26
|
+
Async::Task.current.async do |task|
|
27
|
+
while c = stdout.read(1)
|
28
|
+
stream.write c
|
29
|
+
end
|
30
|
+
stream.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -11,12 +11,21 @@ module Pytty
|
|
11
11
|
|
12
12
|
def handle
|
13
13
|
req = Rack::Request.new(@env)
|
14
|
-
|
14
|
+
body = begin
|
15
|
+
JSON.parse(req.body.read)
|
16
|
+
rescue
|
17
|
+
end
|
18
|
+
|
19
|
+
obj = case req.path_info
|
15
20
|
when "/run"
|
16
|
-
Run.new.
|
21
|
+
Run.new cmd: body.dig("cmd")
|
22
|
+
when "/stream"
|
23
|
+
Stream.new cmd: body.dig("cmd")
|
17
24
|
else
|
18
25
|
raise "Unknown: #{req.path_info}"
|
19
26
|
end
|
27
|
+
|
28
|
+
obj.run
|
20
29
|
end
|
21
30
|
end
|
22
31
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "rack/request"
|
3
|
+
|
4
|
+
module Pytty
|
5
|
+
module Daemon
|
6
|
+
module Components
|
7
|
+
class WebSocketHandler
|
8
|
+
def initialize(env)
|
9
|
+
@env = env
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle
|
13
|
+
req = Rack::Request.new(@env)
|
14
|
+
ws = Pytty::Daemon::Api::WebSockets.new(@env)
|
15
|
+
ws.handle
|
16
|
+
|
17
|
+
klass = case req.path_info
|
18
|
+
when "/stream"
|
19
|
+
Stream
|
20
|
+
else
|
21
|
+
raise "Unknown: #{req.path_info}"
|
22
|
+
end
|
23
|
+
params = ws.read
|
24
|
+
body = begin
|
25
|
+
JSON.parse(params)
|
26
|
+
rescue Exception => ex
|
27
|
+
p ex
|
28
|
+
end
|
29
|
+
|
30
|
+
obj = klass.new cmd: body.dig("cmd"), env: body.dig("env")
|
31
|
+
obj.run stream: ws
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
data/lib/pytty/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pytty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matti Paksula
|
@@ -178,7 +178,9 @@ files:
|
|
178
178
|
- lib/pytty/client/cli.rb
|
179
179
|
- lib/pytty/client/cli/root_command.rb
|
180
180
|
- lib/pytty/client/cli/run_command.rb
|
181
|
+
- lib/pytty/client/cli/stream_command.rb
|
181
182
|
- lib/pytty/common/cli/version_command.rb
|
183
|
+
- lib/pytty/daemon/api/chunk.rb
|
182
184
|
- lib/pytty/daemon/api/router.rb
|
183
185
|
- lib/pytty/daemon/api/server.rb
|
184
186
|
- lib/pytty/daemon/api/web_sockets.rb
|
@@ -187,7 +189,9 @@ files:
|
|
187
189
|
- lib/pytty/daemon/cli/serve_command.rb
|
188
190
|
- lib/pytty/daemon/components.rb
|
189
191
|
- lib/pytty/daemon/components/run.rb
|
192
|
+
- lib/pytty/daemon/components/stream.rb
|
190
193
|
- lib/pytty/daemon/components/web_handler.rb
|
194
|
+
- lib/pytty/daemon/components/web_socket_handler.rb
|
191
195
|
- lib/pytty/version.rb
|
192
196
|
- pytty.gemspec
|
193
197
|
homepage: https://github.com/pyttyhq/pytty-ruby
|