libtmux-async 0.1.0.alpha.1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +90 -0
- data/lib/libtmux/async/control.rb +345 -0
- data/lib/libtmux/async/process.rb +310 -0
- data/lib/libtmux/async/scope.rb +390 -0
- data/lib/libtmux/async/server.rb +77 -0
- data/lib/libtmux/async/version.rb +7 -0
- data/lib/libtmux/async.rb +55 -0
- data/sig/libtmux-async.rbs +58 -0
- metadata +77 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LibTmux
|
|
4
|
+
module Async
|
|
5
|
+
class Server < LibTmux::Server
|
|
6
|
+
def initialize(scope, source)
|
|
7
|
+
raise ArgumentError, "server must be a bound LibTmux::Server" unless source.is_a?(LibTmux::Server)
|
|
8
|
+
|
|
9
|
+
@scope, @source = scope, source
|
|
10
|
+
@mutex = Mutex.new
|
|
11
|
+
source.__send__(:with_bound_endpoint) { |endpoint, pin| @endpoint, @pin = endpoint, pin }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def run(argv, input: "".b, timeout: 5.0, cancel: nil)
|
|
15
|
+
ensure_owner
|
|
16
|
+
ensure_open
|
|
17
|
+
validate_argv(argv)
|
|
18
|
+
raise ArgumentError, "raw commands cannot override endpoint flags" if argv.first.start_with?("-")
|
|
19
|
+
|
|
20
|
+
@scope.__send__(:execute, @pin.command_prefix + argv, input: input, timeout: timeout, cancel: cancel)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def close
|
|
24
|
+
@scope.close
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Scope counters remain readable after this facade closes its scope.
|
|
28
|
+
def diagnostics
|
|
29
|
+
@scope.diagnostics
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def open_control(session:, **options)
|
|
33
|
+
session_id = target(session, :session)
|
|
34
|
+
control = @scope.__send__(:open_control, binding: @pin, session_id: session_id, **options)
|
|
35
|
+
return control unless block_given?
|
|
36
|
+
|
|
37
|
+
failure = result = nil
|
|
38
|
+
begin
|
|
39
|
+
result = yield control
|
|
40
|
+
rescue Exception => error
|
|
41
|
+
failure = error
|
|
42
|
+
ensure
|
|
43
|
+
begin
|
|
44
|
+
control.close
|
|
45
|
+
rescue Exception => error
|
|
46
|
+
details = ["Async control close failed (#{error.class})"]
|
|
47
|
+
details.concat(error.cleanup_errors) if error.is_a?(Error)
|
|
48
|
+
Async.__send__(:attach_cleanup, failure, details) if failure
|
|
49
|
+
failure ||= error
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
raise failure if failure
|
|
53
|
+
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def attach(**)
|
|
58
|
+
raise UnsupportedFeatureError.new("interactive terminal attachment requires the blocking core facade", phase: :admission)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def self.start(**)
|
|
62
|
+
raise UnsupportedFeatureError.new("create an owned core server before opening its Async scope", phase: :admission)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def ensure_owner
|
|
68
|
+
@scope.__send__(:ensure_owner)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def ensure_open
|
|
72
|
+
@scope.__send__(:ensure_open)
|
|
73
|
+
@source.__send__(:with_bound_endpoint) { nil }
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "libtmux"
|
|
4
|
+
require "async"
|
|
5
|
+
require "libtmux/async/version"
|
|
6
|
+
require "libtmux/async/server"
|
|
7
|
+
require "libtmux/async/scope"
|
|
8
|
+
require "libtmux/async/control"
|
|
9
|
+
|
|
10
|
+
module LibTmux
|
|
11
|
+
module Async
|
|
12
|
+
module CleanupDetails
|
|
13
|
+
attr_reader :async_cleanup_errors
|
|
14
|
+
end
|
|
15
|
+
private_constant :CleanupDetails
|
|
16
|
+
|
|
17
|
+
def self.attach_cleanup(error, details)
|
|
18
|
+
return if details.empty?
|
|
19
|
+
|
|
20
|
+
if error.is_a?(Error)
|
|
21
|
+
error.__send__(:attach_cleanup_errors, details)
|
|
22
|
+
else
|
|
23
|
+
error.extend(CleanupDetails)
|
|
24
|
+
error.instance_variable_set(:@async_cleanup_errors, ((error.async_cleanup_errors || []) + details).freeze)
|
|
25
|
+
end
|
|
26
|
+
rescue FrozenError, TypeError
|
|
27
|
+
nil
|
|
28
|
+
end
|
|
29
|
+
private_class_method :attach_cleanup
|
|
30
|
+
|
|
31
|
+
def self.open(server:, parent: ::Async::Task.current, **options)
|
|
32
|
+
raise ArgumentError, "Async scope requires a block" unless block_given?
|
|
33
|
+
|
|
34
|
+
scope = Scope.new(parent: parent, server: server, **options)
|
|
35
|
+
failure = result = nil
|
|
36
|
+
begin
|
|
37
|
+
result = yield scope
|
|
38
|
+
rescue Exception => error
|
|
39
|
+
failure = error
|
|
40
|
+
ensure
|
|
41
|
+
begin
|
|
42
|
+
scope.close
|
|
43
|
+
rescue Exception => error
|
|
44
|
+
details = ["Async scope close failed (#{error.class})"]
|
|
45
|
+
details.concat(error.cleanup_errors) if error.is_a?(Error)
|
|
46
|
+
attach_cleanup(failure, details) if failure
|
|
47
|
+
failure ||= error
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
raise failure if failure
|
|
51
|
+
|
|
52
|
+
result
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module LibTmux
|
|
2
|
+
module Async
|
|
3
|
+
VERSION: String
|
|
4
|
+
|
|
5
|
+
def self.open: [T] (server: LibTmux::Server, ?parent: untyped, **untyped) { (Scope) -> T } -> T
|
|
6
|
+
|
|
7
|
+
type scope_diagnostics = {
|
|
8
|
+
transport: :async_process, closed: bool, admitted_requests: Integer,
|
|
9
|
+
reserved_process_slots: Integer,
|
|
10
|
+
waiting_requests: Integer, active_process_slots: Integer,
|
|
11
|
+
reserved_request_bytes: Integer, retained_output_bytes: Integer,
|
|
12
|
+
control_connections: Integer, maps: Integer,
|
|
13
|
+
limits: {concurrency: Integer, max_requests: Integer, max_controls: Integer,
|
|
14
|
+
max_queue_bytes: Integer, max_output_bytes: Integer,
|
|
15
|
+
stdout_limit: Integer, stderr_limit: Integer, input_limit: Integer,
|
|
16
|
+
argv_limit: Integer, cleanup_timeout: Numeric, drain_timeout: Numeric,
|
|
17
|
+
close_timeout: Numeric}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
class Scope
|
|
21
|
+
def initialize: (parent: untyped, server: LibTmux::Server, ?concurrency: Integer, ?max_requests: Integer,
|
|
22
|
+
?max_controls: Integer, ?max_queue_bytes: Integer, ?max_output_bytes: Integer,
|
|
23
|
+
?stdout_limit: Integer, ?stderr_limit: Integer, ?input_limit: Integer, ?argv_limit: Integer,
|
|
24
|
+
?cleanup_timeout: Numeric, ?drain_timeout: Numeric) -> void
|
|
25
|
+
attr_reader server: Server
|
|
26
|
+
def map: [Input, Output] (Enumerable[Input], ?concurrency: Integer, ?max_items: Integer,
|
|
27
|
+
?max_bytes: Integer, ?result_bytes: ^(Output) -> Integer) { (Input) -> Output } -> Array[Output]
|
|
28
|
+
def close: () -> nil
|
|
29
|
+
def closed?: () -> bool
|
|
30
|
+
def diagnostics: () -> scope_diagnostics
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
class Server < LibTmux::Server
|
|
34
|
+
def initialize: (Scope, LibTmux::Server) -> void
|
|
35
|
+
def run: (Array[String], ?input: String, ?timeout: Numeric, ?cancel: untyped) -> CommandResult
|
|
36
|
+
def close: () -> nil
|
|
37
|
+
def diagnostics: () -> scope_diagnostics
|
|
38
|
+
def open_control: [T] (session: EntityRef, ?reconnect: LibTmux::ControlConnection?, **Integer) { (ControlConnection) -> T } -> T
|
|
39
|
+
| (session: EntityRef, ?reconnect: LibTmux::ControlConnection?, **Integer) -> ControlConnection
|
|
40
|
+
def attach: (**untyped) -> bot
|
|
41
|
+
def self.start: (**untyped) -> bot
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class ControlConnection < LibTmux::ControlConnection
|
|
45
|
+
def initialize: (scope: Scope, binding: untyped, session_id: String, ?reconnect: LibTmux::ControlConnection?, **Integer) -> void
|
|
46
|
+
attr_reader events: ControlSubscription
|
|
47
|
+
def exchange: (String, ?timeout: Numeric, ?cancel: untyped) -> GuardedReply
|
|
48
|
+
def subscribe: (?pane_id: String?, ?mode: :reliable | :tail, ?max_bytes: Integer, ?max_events: Integer) -> ControlSubscription
|
|
49
|
+
def close: (?timeout: Numeric) -> nil
|
|
50
|
+
def closed?: () -> bool
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
class ControlSubscription < LibTmux::ControlSubscription
|
|
54
|
+
def initialize: (scope: Scope, **untyped) -> void
|
|
55
|
+
def next: (?timeout: Numeric?) -> ControlEvent
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: libtmux-async
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0.alpha.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- libtmux contributors
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: libtmux
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - '='
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.1.0.alpha.1
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - '='
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.1.0.alpha.1
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: async
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 2.46.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 2.46.0
|
|
40
|
+
description: Run concurrent libtmux commands and bounded control subscriptions inside
|
|
41
|
+
application-owned Async tasks.
|
|
42
|
+
executables: []
|
|
43
|
+
extensions: []
|
|
44
|
+
extra_rdoc_files: []
|
|
45
|
+
files:
|
|
46
|
+
- LICENSE
|
|
47
|
+
- README.md
|
|
48
|
+
- lib/libtmux/async.rb
|
|
49
|
+
- lib/libtmux/async/control.rb
|
|
50
|
+
- lib/libtmux/async/process.rb
|
|
51
|
+
- lib/libtmux/async/scope.rb
|
|
52
|
+
- lib/libtmux/async/server.rb
|
|
53
|
+
- lib/libtmux/async/version.rb
|
|
54
|
+
- sig/libtmux-async.rbs
|
|
55
|
+
homepage: https://github.com/libtmux/libtmux-ruby
|
|
56
|
+
licenses:
|
|
57
|
+
- MIT
|
|
58
|
+
metadata:
|
|
59
|
+
source_code_uri: https://github.com/libtmux/libtmux-ruby
|
|
60
|
+
rdoc_options: []
|
|
61
|
+
require_paths:
|
|
62
|
+
- lib
|
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.3'
|
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0'
|
|
73
|
+
requirements: []
|
|
74
|
+
rubygems_version: 4.0.20
|
|
75
|
+
specification_version: 4
|
|
76
|
+
summary: Optional Async integration for libtmux
|
|
77
|
+
test_files: []
|