daytona-sdk 0.125.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 +7 -0
- data/.rubocop.yml +16 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/README.md +39 -0
- data/Rakefile +12 -0
- data/lib/daytona/code_toolbox/sandbox_python_code_toolbox.rb +439 -0
- data/lib/daytona/code_toolbox/sandbox_ts_code_toolbox.rb +23 -0
- data/lib/daytona/common/charts.rb +298 -0
- data/lib/daytona/common/code_language.rb +11 -0
- data/lib/daytona/common/daytona.rb +206 -0
- data/lib/daytona/common/file_system.rb +23 -0
- data/lib/daytona/common/git.rb +16 -0
- data/lib/daytona/common/image.rb +493 -0
- data/lib/daytona/common/process.rb +141 -0
- data/lib/daytona/common/pty.rb +306 -0
- data/lib/daytona/common/resources.rb +31 -0
- data/lib/daytona/common/response.rb +28 -0
- data/lib/daytona/common/snapshot.rb +110 -0
- data/lib/daytona/computer_use.rb +549 -0
- data/lib/daytona/config.rb +53 -0
- data/lib/daytona/daytona.rb +278 -0
- data/lib/daytona/file_system.rb +359 -0
- data/lib/daytona/git.rb +287 -0
- data/lib/daytona/lsp_server.rb +130 -0
- data/lib/daytona/object_storage.rb +169 -0
- data/lib/daytona/process.rb +484 -0
- data/lib/daytona/sandbox.rb +376 -0
- data/lib/daytona/sdk/version.rb +7 -0
- data/lib/daytona/sdk.rb +45 -0
- data/lib/daytona/snapshot_service.rb +198 -0
- data/lib/daytona/util.rb +56 -0
- data/lib/daytona/volume.rb +43 -0
- data/lib/daytona/volume_service.rb +49 -0
- data/sig/daytona/sdk.rbs +6 -0
- metadata +149 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'uri'
|
|
6
|
+
|
|
7
|
+
module Daytona
|
|
8
|
+
class Process # rubocop:disable Metrics/ClassLength
|
|
9
|
+
# @return [Daytona::SandboxPythonCodeToolbox,
|
|
10
|
+
attr_reader :code_toolbox
|
|
11
|
+
|
|
12
|
+
# @return [String] The ID of the Sandbox
|
|
13
|
+
attr_reader :sandbox_id
|
|
14
|
+
|
|
15
|
+
# @return [DaytonaApiClient::ToolboxApi] API client for Sandbox operations
|
|
16
|
+
attr_reader :toolbox_api
|
|
17
|
+
|
|
18
|
+
# @return [Proc] Function to get preview link for a port
|
|
19
|
+
attr_reader :get_preview_link
|
|
20
|
+
|
|
21
|
+
# Initialize a new Process instance
|
|
22
|
+
#
|
|
23
|
+
# @param code_toolbox [Daytona::SandboxPythonCodeToolbox, Daytona::SandboxTsCodeToolbox]
|
|
24
|
+
# @param sandbox_id [String] The ID of the Sandbox
|
|
25
|
+
# @param toolbox_api [DaytonaApiClient::ToolboxApi] API client for Sandbox operations
|
|
26
|
+
# @param get_preview_link [Proc] Function to get preview link for a port
|
|
27
|
+
def initialize(code_toolbox:, sandbox_id:, toolbox_api:, get_preview_link:)
|
|
28
|
+
@code_toolbox = code_toolbox
|
|
29
|
+
@sandbox_id = sandbox_id
|
|
30
|
+
@toolbox_api = toolbox_api
|
|
31
|
+
@get_preview_link = get_preview_link
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Execute a shell command in the Sandbox
|
|
35
|
+
#
|
|
36
|
+
# @param command [String] Shell command to execute
|
|
37
|
+
# @param cwd [String, nil] Working directory for command execution. If not specified, uses the sandbox working directory
|
|
38
|
+
# @param env [Hash<String, String>, nil] Environment variables to set for the command
|
|
39
|
+
# @param timeout [Integer, nil] Maximum time in seconds to wait for the command to complete. 0 means wait indefinitely
|
|
40
|
+
# @return [ExecuteResponse] Command execution results containing exit_code, result, and artifacts
|
|
41
|
+
#
|
|
42
|
+
# @example
|
|
43
|
+
# # Simple command
|
|
44
|
+
# response = sandbox.process.exec("echo 'Hello'")
|
|
45
|
+
# puts response.artifacts.stdout
|
|
46
|
+
# => "Hello\n"
|
|
47
|
+
#
|
|
48
|
+
# # Command with working directory
|
|
49
|
+
# result = sandbox.process.exec("ls", cwd: "workspace/src")
|
|
50
|
+
#
|
|
51
|
+
# # Command with timeout
|
|
52
|
+
# result = sandbox.process.exec("sleep 10", timeout: 5)
|
|
53
|
+
def exec(command:, cwd: nil, env: nil, timeout: nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
54
|
+
command = "echo '#{Base64.encode64(command)}' | base64 -d | sh"
|
|
55
|
+
|
|
56
|
+
if env && !env.empty?
|
|
57
|
+
safe_env_exports = env.map do |key, value|
|
|
58
|
+
"export #{key}=$(echo '#{Base64.encode64(value)}' | base64 -d)"
|
|
59
|
+
end.join(';')
|
|
60
|
+
command = "#{safe_env_exports}; #{command}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
command = "sh -c \"#{command}\""
|
|
64
|
+
|
|
65
|
+
response = toolbox_api.execute_command(sandbox_id, DaytonaApiClient::ExecuteRequest.new(command:, cwd:, timeout:))
|
|
66
|
+
# Post-process the output to extract ExecutionArtifacts
|
|
67
|
+
artifacts = parse_output(response.result.split("\n"))
|
|
68
|
+
|
|
69
|
+
# Create new response with processed output and charts
|
|
70
|
+
ExecuteResponse.new(
|
|
71
|
+
exit_code: response.exit_code,
|
|
72
|
+
result: artifacts.stdout,
|
|
73
|
+
artifacts: artifacts
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Execute code in the Sandbox using the appropriate language runtime
|
|
78
|
+
#
|
|
79
|
+
# @param code [String] Code to execute
|
|
80
|
+
# @param params [CodeRunParams, nil] Parameters for code execution
|
|
81
|
+
# @param timeout [Integer, nil] Maximum time in seconds to wait for the code to complete. 0 means wait indefinitely
|
|
82
|
+
# @return [ExecuteResponse] Code execution result containing exit_code, result, and artifacts
|
|
83
|
+
#
|
|
84
|
+
# @example
|
|
85
|
+
# # Run Python code
|
|
86
|
+
# response = sandbox.process.code_run(<<~CODE)
|
|
87
|
+
# x = 10
|
|
88
|
+
# y = 20
|
|
89
|
+
# print(f"Sum: {x + y}")
|
|
90
|
+
# CODE
|
|
91
|
+
# puts response.artifacts.stdout # Prints: Sum: 30
|
|
92
|
+
def code_run(code:, params: nil, timeout: nil)
|
|
93
|
+
exec(command: code_toolbox.get_run_command(code, params), env: params&.env, timeout:)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Creates a new long-running background session in the Sandbox
|
|
97
|
+
#
|
|
98
|
+
# Sessions are background processes that maintain state between commands, making them ideal for
|
|
99
|
+
# scenarios requiring multiple related commands or persistent environment setup.
|
|
100
|
+
#
|
|
101
|
+
# @param session_id [String] Unique identifier for the new session
|
|
102
|
+
# @return [void]
|
|
103
|
+
#
|
|
104
|
+
# @example
|
|
105
|
+
# # Create a new session
|
|
106
|
+
# session_id = "my-session"
|
|
107
|
+
# sandbox.process.create_session(session_id)
|
|
108
|
+
# session = sandbox.process.get_session(session_id)
|
|
109
|
+
# # Do work...
|
|
110
|
+
# sandbox.process.delete_session(session_id)
|
|
111
|
+
def create_session(session_id)
|
|
112
|
+
toolbox_api.create_session(sandbox_id, DaytonaApiClient::CreateSessionRequest.new(session_id:))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Gets a session in the Sandbox
|
|
116
|
+
#
|
|
117
|
+
# @param session_id [String] Unique identifier of the session to retrieve
|
|
118
|
+
# @return [DaytonaApiClient::Session] Session information including session_id and commands
|
|
119
|
+
#
|
|
120
|
+
# @example
|
|
121
|
+
# session = sandbox.process.get_session("my-session")
|
|
122
|
+
# session.commands.each do |cmd|
|
|
123
|
+
# puts "Command: #{cmd.command}"
|
|
124
|
+
# end
|
|
125
|
+
def get_session(session_id) = toolbox_api.get_session(sandbox_id, session_id)
|
|
126
|
+
|
|
127
|
+
# Gets information about a specific command executed in a session
|
|
128
|
+
#
|
|
129
|
+
# @param session_id [String] Unique identifier of the session
|
|
130
|
+
# @param command_id [String] Unique identifier of the command
|
|
131
|
+
# @return [DaytonaApiClient::Command] Command information including id, command, and exit_code
|
|
132
|
+
#
|
|
133
|
+
# @example
|
|
134
|
+
# cmd = sandbox.process.get_session_command(session_id: "my-session", command_id: "cmd-123")
|
|
135
|
+
# if cmd.exit_code == 0
|
|
136
|
+
# puts "Command #{cmd.command} completed successfully"
|
|
137
|
+
# end
|
|
138
|
+
def get_session_command(session_id:, command_id:)
|
|
139
|
+
toolbox_api.get_session_command(sandbox_id, session_id, command_id)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Executes a command in the session
|
|
143
|
+
#
|
|
144
|
+
# @param session_id [String] Unique identifier of the session to use
|
|
145
|
+
# @param req [Daytona::SessionExecuteRequest] Command execution request containing command and run_async
|
|
146
|
+
# @return [Daytona::SessionExecuteResponse] Command execution results containing cmd_id, output, stdout, stderr, and exit_code
|
|
147
|
+
#
|
|
148
|
+
# @example
|
|
149
|
+
# # Execute commands in sequence, maintaining state
|
|
150
|
+
# session_id = "my-session"
|
|
151
|
+
#
|
|
152
|
+
# # Change directory
|
|
153
|
+
# req = Daytona::SessionExecuteRequest.new(command: "cd /workspace")
|
|
154
|
+
# sandbox.process.execute_session_command(session_id:, req:)
|
|
155
|
+
#
|
|
156
|
+
# # Create a file
|
|
157
|
+
# req = Daytona::SessionExecuteRequest.new(command: "echo 'Hello' > test.txt")
|
|
158
|
+
# sandbox.process.execute_session_command(session_id:, req:)
|
|
159
|
+
#
|
|
160
|
+
# # Read the file
|
|
161
|
+
# req = Daytona::SessionExecuteRequest.new(command: "cat test.txt")
|
|
162
|
+
# result = sandbox.process.execute_session_command(session_id:, req:)
|
|
163
|
+
# puts "Command stdout: #{result.stdout}"
|
|
164
|
+
# puts "Command stderr: #{result.stderr}"
|
|
165
|
+
def execute_session_command(session_id:, req:) # rubocop:disable Metrics/MethodLength
|
|
166
|
+
response = toolbox_api.execute_session_command(
|
|
167
|
+
sandbox_id,
|
|
168
|
+
session_id,
|
|
169
|
+
DaytonaApiClient::SessionExecuteRequest.new(command: req.command, run_async: req.run_async)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
stdout, stderr = Util.demux(response.output || '')
|
|
173
|
+
|
|
174
|
+
SessionExecuteResponse.new(
|
|
175
|
+
cmd_id: response.cmd_id,
|
|
176
|
+
output: response.output,
|
|
177
|
+
stdout:,
|
|
178
|
+
stderr:,
|
|
179
|
+
exit_code: response.exit_code,
|
|
180
|
+
# TODO: DaytonaApiClient::SessionExecuteResponse doesn't have additional_properties attribute
|
|
181
|
+
additional_properties: {}
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Get the logs for a command executed in a session
|
|
186
|
+
#
|
|
187
|
+
# @param session_id [String] Unique identifier of the session
|
|
188
|
+
# @param command_id [String] Unique identifier of the command
|
|
189
|
+
# @return [Daytona::SessionCommandLogsResponse] Command logs including output, stdout, and stderr
|
|
190
|
+
#
|
|
191
|
+
# @example
|
|
192
|
+
# logs = sandbox.process.get_session_command_logs(session_id: "my-session", command_id: "cmd-123")
|
|
193
|
+
# puts "Command stdout: #{logs.stdout}"
|
|
194
|
+
# puts "Command stderr: #{logs.stderr}"
|
|
195
|
+
def get_session_command_logs(session_id:, command_id:)
|
|
196
|
+
parse_session_command_logs(
|
|
197
|
+
toolbox_api.get_session_command_logs(
|
|
198
|
+
sandbox_id,
|
|
199
|
+
session_id,
|
|
200
|
+
command_id
|
|
201
|
+
)
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# Asynchronously retrieves and processes the logs for a command executed in a session as they become available
|
|
206
|
+
#
|
|
207
|
+
# @param session_id [String] Unique identifier of the session
|
|
208
|
+
# @param command_id [String] Unique identifier of the command
|
|
209
|
+
# @param on_stdout [Proc] Callback function to handle stdout log chunks as they arrive
|
|
210
|
+
# @param on_stderr [Proc] Callback function to handle stderr log chunks as they arrive
|
|
211
|
+
# @return [WebSocket::Client::Simple::Client]
|
|
212
|
+
#
|
|
213
|
+
# @example
|
|
214
|
+
# sandbox.process.get_session_command_logs_async(
|
|
215
|
+
# session_id: "my-session",
|
|
216
|
+
# command_id: "cmd-123",
|
|
217
|
+
# on_stdout: ->(log) { puts "[STDOUT]: #{log}" },
|
|
218
|
+
# on_stderr: ->(log) { puts "[STDERR]: #{log}" }
|
|
219
|
+
# )
|
|
220
|
+
def get_session_command_logs_async(session_id:, command_id:, on_stdout:, on_stderr:) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
221
|
+
preview_link = get_preview_link.call(WS_PORT)
|
|
222
|
+
url = URI.parse(preview_link.url)
|
|
223
|
+
url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
|
|
224
|
+
url.path = "/process/session/#{session_id}/command/#{command_id}/logs"
|
|
225
|
+
url.query = 'follow=true'
|
|
226
|
+
|
|
227
|
+
WebSocket::Client::Simple.connect(
|
|
228
|
+
url.to_s,
|
|
229
|
+
headers: toolbox_api.api_client.default_headers.dup.merge(
|
|
230
|
+
'X-Daytona-Preview-Token' => preview_link.token,
|
|
231
|
+
'Content-Type' => 'text/plain',
|
|
232
|
+
'Accept' => 'text/plain'
|
|
233
|
+
)
|
|
234
|
+
) do |ws|
|
|
235
|
+
ws.on(:message) do |message|
|
|
236
|
+
if message.type == :close
|
|
237
|
+
ws.close
|
|
238
|
+
next
|
|
239
|
+
else
|
|
240
|
+
stdout, stderr = Util.demux(message.data.to_s)
|
|
241
|
+
|
|
242
|
+
on_stdout.call(stdout) unless stdout.empty?
|
|
243
|
+
on_stderr.call(stderr) unless stderr.empty?
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
#
|
|
250
|
+
# @return [Array<DaytonaApiClient::Session>] List of all sessions in the Sandbox
|
|
251
|
+
#
|
|
252
|
+
# @example
|
|
253
|
+
# sessions = sandbox.process.list_sessions
|
|
254
|
+
# sessions.each do |session|
|
|
255
|
+
# puts "Session #{session.session_id}:"
|
|
256
|
+
# puts " Commands: #{session.commands.length}"
|
|
257
|
+
# end
|
|
258
|
+
def list_sessions = toolbox_api.list_sessions(sandbox_id)
|
|
259
|
+
|
|
260
|
+
# Terminates and removes a session from the Sandbox, cleaning up any resources associated with it
|
|
261
|
+
#
|
|
262
|
+
# @param session_id [String] Unique identifier of the session to delete
|
|
263
|
+
#
|
|
264
|
+
# @example
|
|
265
|
+
# # Create and use a session
|
|
266
|
+
# sandbox.process.create_session("temp-session")
|
|
267
|
+
# # ... use the session ...
|
|
268
|
+
#
|
|
269
|
+
# # Clean up when done
|
|
270
|
+
# sandbox.process.delete_session("temp-session")
|
|
271
|
+
def delete_session(session_id) = toolbox_api.delete_session(sandbox_id, session_id)
|
|
272
|
+
|
|
273
|
+
# Creates a new PTY (pseudo-terminal) session in the Sandbox.
|
|
274
|
+
#
|
|
275
|
+
# Creates an interactive terminal session that can execute commands and handle user input.
|
|
276
|
+
# The PTY session behaves like a real terminal, supporting features like command history.
|
|
277
|
+
#
|
|
278
|
+
# @param id [String] Unique identifier for the PTY session. Must be unique within the Sandbox.
|
|
279
|
+
# @param cwd [String, nil] Working directory for the PTY session. Defaults to the sandbox's working directory.
|
|
280
|
+
# @param envs [Hash<String, String>, nil] Environment variables to set in the PTY session. These will be merged with
|
|
281
|
+
# the Sandbox's default environment variables.
|
|
282
|
+
# @param pty_size [PtySize, nil] Terminal size configuration. Defaults to 80x24 if not specified.
|
|
283
|
+
# @return [PtyHandle] Handle for managing the created PTY session. Use this to send input,
|
|
284
|
+
# receive output, resize the terminal, and manage the session lifecycle.
|
|
285
|
+
#
|
|
286
|
+
# @example
|
|
287
|
+
# # Create a basic PTY session
|
|
288
|
+
# pty_handle = sandbox.process.create_pty_session(id: "my-pty")
|
|
289
|
+
#
|
|
290
|
+
# # Create a PTY session with specific size and environment
|
|
291
|
+
# pty_size = Daytona::PtySize.new(rows: 30, cols: 120)
|
|
292
|
+
# pty_handle = sandbox.process.create_pty_session(
|
|
293
|
+
# id: "my-pty",
|
|
294
|
+
# cwd: "/workspace",
|
|
295
|
+
# envs: {"NODE_ENV" => "development"},
|
|
296
|
+
# pty_size: pty_size
|
|
297
|
+
# )
|
|
298
|
+
#
|
|
299
|
+
# # Use the PTY session
|
|
300
|
+
# pty_handle.wait_for_connection
|
|
301
|
+
# pty_handle.send_input("ls -la\n")
|
|
302
|
+
# result = pty_handle.wait
|
|
303
|
+
# pty_handle.disconnect
|
|
304
|
+
#
|
|
305
|
+
# @raise [Daytona::Sdk::Error] If the PTY session creation fails or the session ID is already in use.
|
|
306
|
+
def create_pty_session(id:, cwd: nil, envs: nil, pty_size: nil) # rubocop:disable Metrics/MethodLength
|
|
307
|
+
response = toolbox_api.create_pty_session(
|
|
308
|
+
sandbox_id,
|
|
309
|
+
DaytonaApiClient::PtyCreateRequest.new(
|
|
310
|
+
id:,
|
|
311
|
+
cwd:,
|
|
312
|
+
envs:,
|
|
313
|
+
cols: pty_size&.cols,
|
|
314
|
+
rows: pty_size&.rows,
|
|
315
|
+
lazy_start: true
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
connect_pty_session(response.session_id)
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Connects to an existing PTY session in the Sandbox.
|
|
323
|
+
#
|
|
324
|
+
# Establishes a WebSocket connection to an existing PTY session, allowing you to
|
|
325
|
+
# interact with a previously created terminal session.
|
|
326
|
+
#
|
|
327
|
+
# @param session_id [String] Unique identifier of the PTY session to connect to.
|
|
328
|
+
# @return [PtyHandle] Handle for managing the connected PTY session.
|
|
329
|
+
#
|
|
330
|
+
# @example
|
|
331
|
+
# # Connect to an existing PTY session
|
|
332
|
+
# pty_handle = sandbox.process.connect_pty_session("my-pty-session")
|
|
333
|
+
# pty_handle.wait_for_connection
|
|
334
|
+
# pty_handle.send_input("echo 'Hello World'\n")
|
|
335
|
+
# result = pty_handle.wait
|
|
336
|
+
# pty_handle.disconnect
|
|
337
|
+
#
|
|
338
|
+
# @raise [Daytona::Sdk::Error] If the PTY session doesn't exist or connection fails.
|
|
339
|
+
def connect_pty_session(session_id) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
340
|
+
preview_link = get_preview_link.call(WS_PORT)
|
|
341
|
+
url = URI.parse(preview_link.url)
|
|
342
|
+
url.scheme = url.scheme == 'https' ? 'wss' : 'ws'
|
|
343
|
+
url.path = "/process/pty/#{session_id}/connect"
|
|
344
|
+
|
|
345
|
+
PtyHandle.new(
|
|
346
|
+
WebSocket::Client::Simple.connect(
|
|
347
|
+
url.to_s,
|
|
348
|
+
headers: toolbox_api.api_client.default_headers.dup.merge(
|
|
349
|
+
'X-Daytona-Preview-Token' => preview_link.token
|
|
350
|
+
)
|
|
351
|
+
),
|
|
352
|
+
session_id:,
|
|
353
|
+
|
|
354
|
+
handle_resize: ->(pty_size) { resize_pty_session(session_id, pty_size) },
|
|
355
|
+
handle_kill: -> { delete_pty_session(session_id) }
|
|
356
|
+
).tap(&:wait_for_connection)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Resizes a PTY session to the specified dimensions
|
|
360
|
+
#
|
|
361
|
+
# @param session_id [String] Unique identifier of the PTY session
|
|
362
|
+
# @param pty_size [PtySize] New terminal size
|
|
363
|
+
# @return [DaytonaApiClient::PtySessionInfo] Updated PTY session information
|
|
364
|
+
#
|
|
365
|
+
# @example
|
|
366
|
+
# pty_size = Daytona::PtySize.new(rows: 30, cols: 120)
|
|
367
|
+
# session_info = sandbox.process.resize_pty_session("my-pty", pty_size)
|
|
368
|
+
# puts "PTY resized to #{session_info.cols}x#{session_info.rows}"
|
|
369
|
+
def resize_pty_session(session_id, pty_size)
|
|
370
|
+
toolbox_api.resize_pty_session(
|
|
371
|
+
sandbox_id,
|
|
372
|
+
session_id,
|
|
373
|
+
DaytonaApiClient::PtyResizeRequest.new(
|
|
374
|
+
cols: pty_size.cols,
|
|
375
|
+
rows: pty_size.rows
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Deletes a PTY session, terminating the associated process
|
|
381
|
+
#
|
|
382
|
+
# @param session_id [String] Unique identifier of the PTY session to delete
|
|
383
|
+
# @return [void]
|
|
384
|
+
#
|
|
385
|
+
# @example
|
|
386
|
+
# sandbox.process.delete_pty_session("my-pty")
|
|
387
|
+
def delete_pty_session(session_id)
|
|
388
|
+
toolbox_api.delete_pty_session(sandbox_id, session_id)
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
# Lists all PTY sessions in the Sandbox
|
|
392
|
+
#
|
|
393
|
+
# @return [Array<DaytonaApiClient::PtySessionInfo>] List of PTY session information
|
|
394
|
+
#
|
|
395
|
+
# @example
|
|
396
|
+
# sessions = sandbox.process.list_pty_sessions
|
|
397
|
+
# sessions.each do |session|
|
|
398
|
+
# puts "PTY Session #{session.id}: #{session.cols}x#{session.rows}"
|
|
399
|
+
# end
|
|
400
|
+
def list_pty_sessions
|
|
401
|
+
toolbox_api.list_pty_sessions(sandbox_id)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Gets detailed information about a specific PTY session
|
|
405
|
+
#
|
|
406
|
+
# Retrieves comprehensive information about a PTY session including its current state,
|
|
407
|
+
# configuration, and metadata.
|
|
408
|
+
#
|
|
409
|
+
# @param session_id [String] Unique identifier of the PTY session to retrieve information for
|
|
410
|
+
# @return [DaytonaApiClient::PtySessionInfo] Detailed information about the PTY session including ID, state,
|
|
411
|
+
# creation time, working directory, environment variables, and more
|
|
412
|
+
#
|
|
413
|
+
# @example
|
|
414
|
+
# # Get details about a specific PTY session
|
|
415
|
+
# session_info = sandbox.process.get_pty_session_info("my-session")
|
|
416
|
+
# puts "Session ID: #{session_info.id}"
|
|
417
|
+
# puts "Active: #{session_info.active}"
|
|
418
|
+
# puts "Working Directory: #{session_info.cwd}"
|
|
419
|
+
# puts "Terminal Size: #{session_info.cols}x#{session_info.rows}"
|
|
420
|
+
def get_pty_session_info(session_id)
|
|
421
|
+
toolbox_api.get_pty_session(sandbox_id, session_id)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
private
|
|
425
|
+
|
|
426
|
+
# Parse the output of a command to extract ExecutionArtifacts
|
|
427
|
+
#
|
|
428
|
+
# @param lines [Array<String>] A list of lines of output from a command
|
|
429
|
+
# @return [Daytona::ExecutionArtifacts] The artifacts from the command execution
|
|
430
|
+
def parse_output(lines)
|
|
431
|
+
artifacts = ExecutionArtifacts.new('', [])
|
|
432
|
+
|
|
433
|
+
lines.each do |line|
|
|
434
|
+
if line.start_with?(ARTIFACT_PREFIX)
|
|
435
|
+
parse_json_line(line:, artifacts:)
|
|
436
|
+
else
|
|
437
|
+
artifacts.stdout += "#{line}\n"
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
artifacts
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
# Parse a JSON line to extract artifacts
|
|
445
|
+
#
|
|
446
|
+
# @param line [String] The line to parse
|
|
447
|
+
# @param artifacts [Daytona::ExecutionArtifacts] The artifacts to add to
|
|
448
|
+
# @return [void]
|
|
449
|
+
def parse_json_line(line:, artifacts:)
|
|
450
|
+
data = JSON.parse(line.sub(ARTIFACT_PREFIX, '').strip, symbolize_names: true)
|
|
451
|
+
|
|
452
|
+
case data.fetch(:type, nil)
|
|
453
|
+
when ArtifactType::CHART
|
|
454
|
+
artifacts.charts.append(Charts.parse(data.fetch(:value, {})))
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Parse combined stdout/stderr output into separate streams
|
|
459
|
+
#
|
|
460
|
+
# @param data [String] Combined log string with STDOUT_PREFIX and STDERR_PREFIX markers
|
|
461
|
+
# @return [SessionCommandLogsResponse] Response with separated stdout and stderr
|
|
462
|
+
def parse_session_command_logs(data)
|
|
463
|
+
stdout, stderr = Util.demux(data)
|
|
464
|
+
|
|
465
|
+
SessionCommandLogsResponse.new(
|
|
466
|
+
output: data,
|
|
467
|
+
stdout:,
|
|
468
|
+
stderr:
|
|
469
|
+
)
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
ARTIFACT_PREFIX = 'dtn_artifact_k39fd2:'
|
|
473
|
+
private_constant :ARTIFACT_PREFIX
|
|
474
|
+
|
|
475
|
+
WS_PORT = 2280
|
|
476
|
+
private_constant :WS_PORT
|
|
477
|
+
|
|
478
|
+
module ArtifactType
|
|
479
|
+
ALL = [
|
|
480
|
+
CHART = 'chart'
|
|
481
|
+
].freeze
|
|
482
|
+
end
|
|
483
|
+
end
|
|
484
|
+
end
|