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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d925871a8895ef6e93d35a265e5c44c3874d14241e08d2474b884acf4352c6b2
4
- data.tar.gz: 9821b6759f9d57b89ed99c199b435c34f93196334be72c4fd5fe53973d348882
3
+ metadata.gz: 86943cf397ea5d69b0d735243100ad08ed00629b2b1ffc34157f44acb0ff2316
4
+ data.tar.gz: 5ee2c4f7c9bd1bbb9e550be3140d1c7c53f5b51f74ae3cad2f60994b1a026374
5
5
  SHA512:
6
- metadata.gz: 6d2e382324e2882f6e394b7db0f9358600bc76057c2d611ac1c7c4d7e248429d984bcd624554cf684a6c1fa42a771127fa088b4ed57a6d88b62e31e9214145f7
7
- data.tar.gz: be054067981dd164378fcd1ad83fbb948ebd9035fc1decb2a559b75332768e21a46426c8332bbe89e5dacad2db32b9aaf85b2e19235a30868f683b5f3789533e
6
+ metadata.gz: 04b69e3162611cda3e34a33dfae91a6cbad3226ae31e928d8a77dcf1e210c7b4fd766a173f182e8be7a089c2ca26cd3f6456fb13fab420695108c706649a56c3
7
+ data.tar.gz: 4a61b1ff318f39adb8918565e78a6ef7ed189c7063bcb97ce3ca9efc27593a2b73e8a9262e5542cd5c6e850eb77ddbe5c9555be8948f136f4422962d3d18c06b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pytty (0.1.0)
4
+ pytty (0.2.0)
5
5
  async-websocket
6
6
  clamp (~> 1.3)
7
7
  falcon
@@ -2,4 +2,6 @@ require "clamp"
2
2
 
3
3
  require_relative "../common/cli/version_command"
4
4
  require_relative "cli/run_command"
5
+ require_relative "cli/stream_command"
6
+
5
7
  require_relative "cli/root_command"
@@ -13,6 +13,7 @@ module Pytty
13
13
 
14
14
  subcommand ["version"], "Show version information", Pytty::Common::Cli::VersionCommand
15
15
  subcommand ["run"], "run", RunCommand
16
+ subcommand ["stream"], "stream", StreamCommand
16
17
 
17
18
  def self.run
18
19
  super
@@ -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
- response = internet.post("http://localhost:1234/v1/run", headers, body)
16
- response.read
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"}, ["ok"]]
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
- while message = @connection.next_event
17
- type = case message
18
- when WebSocket::Driver::OpenEvent
19
- puts "ws: open #{@env["REMOTE_ADDR"]}"
20
- when WebSocket::Driver::CloseEvent
21
- puts "ws: close #{@env["REMOTE_ADDR"]}"
22
- @@connections.delete @connection
23
- when WebSocket::Driver::MessageEvent
24
- puts "ws: message #{@env["REMOTE_ADDR"]}"
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.data.reverse)
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
@@ -1,3 +1,6 @@
1
1
 
2
2
  require_relative "components/run"
3
- require_relative "components/web_handler"
3
+ require_relative "components/stream"
4
+
5
+ require_relative "components/web_handler"
6
+ require_relative "components/web_socket_handler"
@@ -4,8 +4,13 @@ module Pytty
4
4
  module Daemon
5
5
  module Components
6
6
  class Run
7
+ def initialize(cmd:)
8
+ @cmd = cmd
9
+ end
10
+
7
11
  def run
8
- `say hello`
12
+ cmd_string = @cmd.join(" ")
13
+ `#{cmd_string}`
9
14
  end
10
15
  end
11
16
  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
- case req.path_info
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.run
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
@@ -1,3 +1,3 @@
1
1
  module Pytty
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.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