Class: Chocomint::Console::WorkerProcess
- Inherits:
-
Object
- Object
- Chocomint::Console::WorkerProcess
- Defined in:
- lib/chocomint/console/worker_process.rb
Overview
コンソールワーカーを「新規コンソール付き」で spawn し、名前付きパイプで 双方向にやり取りするための橋渡し。
なぜ名前付きパイプか (重要): ConPTY はコンソール付きプロセスからしか 正しく動かない (chocomint-conpty メモの制約)。CREATE_NEW_CONSOLE で新規 コンソールを与える必要があるが、STARTF_USESTDHANDLES で stdout をパイプへ リダイレクトすると新規コンソールとの関連付けが壊れ、ConPTY 出力が 16 バイトの 初期シーケンスで止まる (実測で確認)。そこで stdio は触らず、制御通信は 独立した名前付きパイプで行う。ワーカーはコンソールを完全に保持できる。
Defined Under Namespace
Modules: Native Classes: Error
Instance Method Summary collapse
- #alive? ⇒ Boolean
- #close ⇒ Object
-
#initialize(command:, cols:, rows:, cwd:, ruby_exe: nil, worker_script: nil) ⇒ WorkerProcess
constructor
A new instance of WorkerProcess.
- #open? ⇒ Boolean
-
#read_message ⇒ Object
ワーカーからの JSON 行を 1 つ読む。無ければ nil (ノンブロッキング)。.
- #send_input(bytes) ⇒ Object
- #send_message(hash) ⇒ Object
- #send_resize(cols, rows) ⇒ Object
-
#start ⇒ Object
名前付きパイプを 2 本作り、ワーカーを新規コンソール付きで spawn して接続を待つ。.
Constructor Details
#initialize(command:, cols:, rows:, cwd:, ruby_exe: nil, worker_script: nil) ⇒ WorkerProcess
Returns a new instance of WorkerProcess.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/chocomint/console/worker_process.rb', line 69 def initialize(command:, cols:, rows:, cwd:, ruby_exe: nil, worker_script: nil) @command = command @cols = cols @rows = rows @cwd = cwd @ruby_exe = ruby_exe || default_ruby_exe @worker_script = worker_script || default_worker_script # 双方向を 1 本のパイプで共有すると read/write が競合してブロックするため、 # 方向ごとに 2 本張る (c2w: 親→worker, w2c: worker→親)。 base = "\\\\.\\pipe\\chocomint-console-#{SecureRandom.hex(8)}" @c2w_name = "#{base}-c2w" @w2c_name = "#{base}-w2c" @open = false end |
Instance Method Details
#alive? ⇒ Boolean
124 125 126 127 128 129 130 131 |
# File 'lib/chocomint/console/worker_process.rb', line 124 def alive? return false unless @proc_handle code = FFI::MemoryPointer.new(:uint32) return false if Native.GetExitCodeProcess(@proc_handle, code).zero? code.read(:uint32) == Native::STILL_ACTIVE end |
#close ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/chocomint/console/worker_process.rb', line 133 def close return unless @open Native.TerminateProcess(@proc_handle, 0) if alive? [@c2w, @w2c].each do |h| next unless h Native.DisconnectNamedPipe(h) Native.CloseHandle(h) end Native.CloseHandle(@proc_handle) if @proc_handle @open = false nil end |
#open? ⇒ Boolean
84 85 86 |
# File 'lib/chocomint/console/worker_process.rb', line 84 def open? @open end |
#read_message ⇒ Object
ワーカーからの JSON 行を 1 つ読む。無ければ nil (ノンブロッキング)。
115 116 117 118 119 120 121 122 |
# File 'lib/chocomint/console/worker_process.rb', line 115 def line = read_line return nil if line.nil? || line.empty? JSON.parse(line) rescue JSON::ParserError nil end |
#send_input(bytes) ⇒ Object
106 107 108 |
# File 'lib/chocomint/console/worker_process.rb', line 106 def send_input(bytes) ("type" => "input", "data" => Base64.strict_encode64(bytes.b)) end |
#send_message(hash) ⇒ Object
102 103 104 |
# File 'lib/chocomint/console/worker_process.rb', line 102 def (hash) write_bytes("#{JSON.generate(hash)}\n".b) end |
#send_resize(cols, rows) ⇒ Object
110 111 112 |
# File 'lib/chocomint/console/worker_process.rb', line 110 def send_resize(cols, rows) ("type" => "resize", "cols" => cols, "rows" => rows) end |
#start ⇒ Object
名前付きパイプを 2 本作り、ワーカーを新規コンソール付きで spawn して接続を待つ。
89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/chocomint/console/worker_process.rb', line 89 def start raise Error, "already started" if @open @c2w = create_named_pipe(@c2w_name) @w2c = create_named_pipe(@w2c_name) spawn_worker # ワーカーが両パイプに接続してくるのを待つ (順序はワーカーの open と一致させる)。 Native.ConnectNamedPipe(@c2w, nil) Native.ConnectNamedPipe(@w2c, nil) @open = true self end |