pytty 0.1.0 → 0.2.0

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