Class: RubynCode::IDE::Client
- Inherits:
-
Object
- Object
- RubynCode::IDE::Client
- Defined in:
- lib/rubyn_code/ide/client.rb
Overview
Sends JSON-RPC requests from the CLI server to the VS Code extension and awaits responses. Enables the CLI to ask the IDE to do things like open diffs, read diagnostics, or navigate to a file.
Uses the server’s write mutex for thread-safe output. Tracks pending responses via a { id => ConditionVariable } map.
Defined Under Namespace
Classes: TimeoutError
Constant Summary collapse
- DEFAULT_TIMEOUT =
seconds
30
Instance Method Summary collapse
-
#initialize(server) ⇒ Client
constructor
A new instance of Client.
-
#pending?(id) ⇒ Boolean
Check if we have a pending request with this id.
-
#request(method, params = {}, timeout: DEFAULT_TIMEOUT) ⇒ Hash
Send a JSON-RPC request to the extension and block until the response arrives or the timeout expires.
-
#resolve(id, result: nil, error: nil) ⇒ Object
Called by the server when it receives a response message (has id + result/error, no method) that matches one of our pending outbound requests.
Constructor Details
#initialize(server) ⇒ Client
Returns a new instance of Client.
16 17 18 19 20 21 |
# File 'lib/rubyn_code/ide/client.rb', line 16 def initialize(server) @server = server @mutex = Mutex.new @next_id = 1000 # Start high to avoid collisions with client IDs @pending = {} # { id => { cv: ConditionVariable, result: nil, error: nil } } end |
Instance Method Details
#pending?(id) ⇒ Boolean
Check if we have a pending request with this id.
88 89 90 |
# File 'lib/rubyn_code/ide/client.rb', line 88 def pending?(id) @mutex.synchronize { @pending.key?(id) } end |
#request(method, params = {}, timeout: DEFAULT_TIMEOUT) ⇒ Hash
Send a JSON-RPC request to the extension and block until the response arrives or the timeout expires.
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/rubyn_code/ide/client.rb', line 32 def request(method, params = {}, timeout: DEFAULT_TIMEOUT) id = allocate_id cv = ConditionVariable.new @mutex.synchronize do @pending[id] = { cv: cv, result: nil, error: nil } end # Write the request via the server's write path write_raw({ 'jsonrpc' => Protocol::JSONRPC_VERSION, 'id' => id, 'method' => method, 'params' => Protocol.send(:stringify_keys_deep, params) }) # Block until the extension responds or we time out @mutex.synchronize do deadline = Time.now + timeout while @pending[id][:result].nil? && @pending[id][:error].nil? remaining = deadline - Time.now if remaining <= 0 @pending.delete(id) raise TimeoutError, "IDE RPC request '#{method}' timed out after #{timeout}s" end cv.wait(@mutex, remaining) end entry = @pending.delete(id) raise StandardError, entry[:error] if entry[:error] entry[:result] end end |
#resolve(id, result: nil, error: nil) ⇒ Object
Called by the server when it receives a response message (has id + result/error, no method) that matches one of our pending outbound requests.
73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/rubyn_code/ide/client.rb', line 73 def resolve(id, result: nil, error: nil) @mutex.synchronize do entry = @pending[id] return unless entry if error entry[:error] = "RPC error #{error['code']}: #{error['message']}" else entry[:result] = result || {} end entry[:cv].signal end end |