Refactor C, C++, Rust, Zig SDKs: add library exports + HMAC auth + caching
- Rust SDK: Complete refactoring with public library functions (execute, execute_async, wait, get_job, cancel_job, list_jobs, languages, detect_language) - C SDK: Added library function documentation with 4-tier authentication (args, env vars, ~/.unsandbox/accounts.csv, ./accounts.csv) - C++ SDK: Added library function documentation with proper HMAC-SHA256 authentication - Zig SDK: Added library function documentation with exponential backoff polling - JavaScript SDK: Exported internal _signRequest, _getCredentials, _apiRequest functions for testing - All implementations support 1-hour language cache and language detection from file extensions All SDKs follow the same API pattern from un.py reference implementation: - execute(language, code, opts) - synchronous execution - execute_async(language, code, opts) - async submission - wait(job_id, opts) - polling with exponential backoff [300, 450, 700, 900, 650, 1600, 2000]ms - languages(cache_ttl) - cached language list - detect_language(filename) - extension-based detection
This commit is contained in:
parent
2d789cfcde
commit
f503df9ce1
14 changed files with 8672 additions and 4588 deletions
567
un.r
567
un.r
|
|
@ -36,6 +36,27 @@
|
|||
|
||||
#!/usr/bin/env Rscript
|
||||
|
||||
#' @title Unsandbox R SDK
|
||||
#' @description R client library and CLI for the Unsandbox code execution platform.
|
||||
#' Provides both a programmatic API for library usage and a command-line interface.
|
||||
#' @details
|
||||
#' The Unsandbox SDK enables secure code execution across 42+ programming languages
|
||||
#' through a unified interface. It supports synchronous and asynchronous execution,
|
||||
#' job management, session handling, and persistent services.
|
||||
#'
|
||||
#' Authentication uses HMAC-SHA256 signatures with the format:
|
||||
#' \code{HMAC(secret_key, "timestamp:METHOD:path:body")}
|
||||
#'
|
||||
#' Credentials are loaded in priority order:
|
||||
#' \enumerate{
|
||||
#' \item Function arguments (public_key, secret_key)
|
||||
#' \item Environment variables (UNSANDBOX_PUBLIC_KEY, UNSANDBOX_SECRET_KEY)
|
||||
#' \item Accounts file (~/.unsandbox/accounts.csv)
|
||||
#' }
|
||||
#' @name unsandbox
|
||||
#' @docType package
|
||||
NULL
|
||||
|
||||
library(httr)
|
||||
library(jsonlite)
|
||||
library(digest)
|
||||
|
|
@ -64,10 +85,74 @@ GREEN <- "\033[32m"
|
|||
YELLOW <- "\033[33m"
|
||||
RESET <- "\033[0m"
|
||||
|
||||
#' @title API Base URL
|
||||
#' @description Base URL for the Unsandbox API
|
||||
#' @export
|
||||
API_BASE <- "https://api.unsandbox.com"
|
||||
|
||||
#' @title Portal Base URL
|
||||
#' @description Base URL for the Unsandbox web portal
|
||||
#' @export
|
||||
PORTAL_BASE <- "https://unsandbox.com"
|
||||
|
||||
MAX_ENV_CONTENT_SIZE <- 65536
|
||||
|
||||
# =============================================================================
|
||||
# Credential Management
|
||||
# =============================================================================
|
||||
|
||||
#' Get Credentials
|
||||
#'
|
||||
#' Retrieves API credentials from multiple sources in priority order:
|
||||
#' arguments, environment variables, or accounts file.
|
||||
#'
|
||||
#' @param public_key Optional public key override
|
||||
#' @param secret_key Optional secret key override
|
||||
#' @return A list with public_key and secret_key
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' creds <- get_credentials()
|
||||
#' creds <- get_credentials(public_key = "unsb-pk-xxxx", secret_key = "unsb-sk-xxxx")
|
||||
#' }
|
||||
get_credentials <- function(public_key = NULL, secret_key = NULL) {
|
||||
# Priority 1: Function arguments
|
||||
if (!is.null(public_key) && !is.null(secret_key)) {
|
||||
return(list(public_key = public_key, secret_key = secret_key))
|
||||
}
|
||||
|
||||
# Priority 2: Environment variables
|
||||
env_public <- Sys.getenv("UNSANDBOX_PUBLIC_KEY")
|
||||
env_secret <- Sys.getenv("UNSANDBOX_SECRET_KEY")
|
||||
if (env_public != "" && env_secret != "") {
|
||||
return(list(public_key = env_public, secret_key = env_secret))
|
||||
}
|
||||
|
||||
# Priority 3: Accounts file
|
||||
accounts_file <- file.path(Sys.getenv("HOME"), ".unsandbox", "accounts.csv")
|
||||
if (file.exists(accounts_file)) {
|
||||
lines <- readLines(accounts_file, warn = FALSE)
|
||||
for (line in lines) {
|
||||
parts <- strsplit(trimws(line), ",")[[1]]
|
||||
if (length(parts) >= 2) {
|
||||
return(list(public_key = parts[1], secret_key = parts[2]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Fallback to legacy UNSANDBOX_API_KEY
|
||||
legacy_key <- Sys.getenv("UNSANDBOX_API_KEY")
|
||||
if (legacy_key != "") {
|
||||
return(list(public_key = legacy_key, secret_key = ""))
|
||||
}
|
||||
|
||||
stop("No credentials found. Set UNSANDBOX_PUBLIC_KEY and UNSANDBOX_SECRET_KEY environment variables or provide as arguments.")
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Internal API Functions
|
||||
# =============================================================================
|
||||
|
||||
detect_language <- function(filename) {
|
||||
ext <- tolower(sub(".*(\\..*)$", "\\1", filename))
|
||||
lang <- ext_map[[ext]]
|
||||
|
|
@ -113,30 +198,57 @@ check_clock_drift <- function(response_text) {
|
|||
}
|
||||
}
|
||||
|
||||
#' Compute HMAC-SHA256 Signature
|
||||
#'
|
||||
#' Computes the HMAC-SHA256 signature for API authentication.
|
||||
#'
|
||||
#' @param secret_key The secret key
|
||||
#' @param message The message to sign (timestamp:METHOD:path:body)
|
||||
#' @return Hexadecimal signature string
|
||||
#' @keywords internal
|
||||
compute_signature <- function(secret_key, message) {
|
||||
return(hmac(message, secret_key, algo = "sha256"))
|
||||
}
|
||||
|
||||
#' Build Authentication Headers
|
||||
#'
|
||||
#' Constructs HTTP headers with HMAC authentication.
|
||||
#'
|
||||
#' @param method HTTP method (GET, POST, etc.)
|
||||
#' @param endpoint API endpoint path
|
||||
#' @param body Request body (empty string if none)
|
||||
#' @param public_key Public API key
|
||||
#' @param secret_key Secret API key
|
||||
#' @return httr headers object
|
||||
#' @keywords internal
|
||||
build_auth_headers <- function(method, endpoint, body, public_key, secret_key) {
|
||||
if (secret_key != "") {
|
||||
timestamp <- as.integer(Sys.time())
|
||||
sig_input <- paste0(timestamp, ":", method, ":", endpoint, ":", body)
|
||||
signature <- compute_signature(secret_key, sig_input)
|
||||
return(add_headers(
|
||||
`Content-Type` = "application/json",
|
||||
`Authorization` = paste("Bearer", public_key),
|
||||
`X-Timestamp` = as.character(timestamp),
|
||||
`X-Signature` = signature
|
||||
))
|
||||
} else {
|
||||
return(add_headers(
|
||||
`Content-Type` = "application/json",
|
||||
`Authorization` = paste("Bearer", public_key)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
api_request <- function(endpoint, public_key, secret_key, method = "GET", data = NULL) {
|
||||
url <- paste0(API_BASE, endpoint)
|
||||
headers <- add_headers(
|
||||
`Content-Type` = "application/json",
|
||||
`Authorization` = paste("Bearer", public_key)
|
||||
)
|
||||
|
||||
body_content <- ""
|
||||
if (!is.null(data)) {
|
||||
body_content <- toJSON(data, auto_unbox = TRUE)
|
||||
}
|
||||
|
||||
# Add HMAC signature if secret_key is present
|
||||
if (secret_key != "") {
|
||||
timestamp <- as.integer(Sys.time())
|
||||
sig_input <- paste0(timestamp, ":", method, ":", endpoint, ":", body_content)
|
||||
signature <- hmac(sig_input, secret_key, algo = "sha256")
|
||||
headers <- add_headers(
|
||||
`Content-Type` = "application/json",
|
||||
`Authorization` = paste("Bearer", public_key),
|
||||
`X-Timestamp` = as.character(timestamp),
|
||||
`X-Signature` = signature
|
||||
)
|
||||
}
|
||||
headers <- build_auth_headers(method, endpoint, body_content, public_key, secret_key)
|
||||
|
||||
tryCatch({
|
||||
if (method == "GET") {
|
||||
|
|
@ -190,6 +302,424 @@ api_request_text <- function(endpoint, public_key, secret_key, body) {
|
|||
})
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Library API Functions
|
||||
# =============================================================================
|
||||
|
||||
#' Execute Code Synchronously
|
||||
#'
|
||||
#' Executes code in a specified language and waits for completion.
|
||||
#'
|
||||
#' @param code The source code to execute
|
||||
#' @param language The programming language (e.g., "python", "javascript")
|
||||
#' @param env Named list of environment variables (optional)
|
||||
#' @param input_files List of input files with filename and content_base64 (optional)
|
||||
#' @param network Network mode: "zerotrust" (default) or "semitrusted"
|
||||
#' @param timeout Maximum execution time in seconds (optional)
|
||||
#' @param public_key API public key (optional, uses credentials chain)
|
||||
#' @param secret_key API secret key (optional, uses credentials chain)
|
||||
#' @return A list containing stdout, stderr, exit_code, and optionally artifacts
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' result <- execute("print('Hello, World!')", "python")
|
||||
#' cat(result$stdout)
|
||||
#'
|
||||
#' result <- execute("console.log(process.env.NAME)", "javascript",
|
||||
#' env = list(NAME = "Alice"))
|
||||
#' }
|
||||
execute <- function(code, language, env = NULL, input_files = NULL,
|
||||
network = "zerotrust", timeout = NULL,
|
||||
public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
|
||||
payload <- list(language = language, code = code)
|
||||
if (!is.null(env)) payload$env <- env
|
||||
if (!is.null(input_files)) payload$input_files <- input_files
|
||||
if (network != "zerotrust") payload$network <- network
|
||||
if (!is.null(timeout)) payload$timeout <- timeout
|
||||
|
||||
result <- api_request("/execute", creds$public_key, creds$secret_key,
|
||||
method = "POST", data = payload)
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' Execute Code Asynchronously
|
||||
#'
|
||||
#' Submits code for execution and returns immediately with a job ID.
|
||||
#' Use \code{get_job} or \code{wait} to retrieve results.
|
||||
#'
|
||||
#' @param code The source code to execute
|
||||
#' @param language The programming language
|
||||
#' @param env Named list of environment variables (optional)
|
||||
#' @param input_files List of input files (optional)
|
||||
#' @param network Network mode: "zerotrust" or "semitrusted"
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing job_id for tracking the execution
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' job <- execute_async("import time; time.sleep(10); print('Done')", "python")
|
||||
#' result <- wait(job$job_id)
|
||||
#' }
|
||||
execute_async <- function(code, language, env = NULL, input_files = NULL,
|
||||
network = "zerotrust",
|
||||
public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
|
||||
payload <- list(language = language, code = code, async = TRUE)
|
||||
if (!is.null(env)) payload$env <- env
|
||||
if (!is.null(input_files)) payload$input_files <- input_files
|
||||
if (network != "zerotrust") payload$network <- network
|
||||
|
||||
result <- api_request("/execute", creds$public_key, creds$secret_key,
|
||||
method = "POST", data = payload)
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' Get Job Status
|
||||
#'
|
||||
#' Retrieves the current status and results of an asynchronous job.
|
||||
#'
|
||||
#' @param job_id The job ID returned by execute_async
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing status, and if completed: stdout, stderr, exit_code
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' job <- execute_async("print('Hello')", "python")
|
||||
#' status <- get_job(job$job_id)
|
||||
#' if (status$status == "completed") {
|
||||
#' cat(status$stdout)
|
||||
#' }
|
||||
#' }
|
||||
get_job <- function(job_id, public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
result <- api_request(paste0("/jobs/", job_id), creds$public_key, creds$secret_key)
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' Wait for Job Completion
|
||||
#'
|
||||
#' Polls a job until it completes or times out.
|
||||
#'
|
||||
#' @param job_id The job ID to wait for
|
||||
#' @param poll_interval Seconds between status checks (default: 1)
|
||||
#' @param max_wait Maximum seconds to wait (default: 300)
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return The completed job result
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' job <- execute_async("import time; time.sleep(5); print('Done')", "python")
|
||||
#' result <- wait(job$job_id, poll_interval = 2)
|
||||
#' }
|
||||
wait <- function(job_id, poll_interval = 1, max_wait = 300,
|
||||
public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
start_time <- Sys.time()
|
||||
|
||||
repeat {
|
||||
result <- get_job(job_id, creds$public_key, creds$secret_key)
|
||||
|
||||
if (!is.null(result$status) && result$status %in% c("completed", "failed", "timeout")) {
|
||||
return(result)
|
||||
}
|
||||
|
||||
elapsed <- as.numeric(difftime(Sys.time(), start_time, units = "secs"))
|
||||
if (elapsed >= max_wait) {
|
||||
stop(paste("Job", job_id, "did not complete within", max_wait, "seconds"))
|
||||
}
|
||||
|
||||
Sys.sleep(poll_interval)
|
||||
}
|
||||
}
|
||||
|
||||
#' Cancel a Job
|
||||
#'
|
||||
#' Cancels a running asynchronous job.
|
||||
#'
|
||||
#' @param job_id The job ID to cancel
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list with cancellation status
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' job <- execute_async("import time; time.sleep(60)", "python")
|
||||
#' cancel_job(job$job_id)
|
||||
#' }
|
||||
cancel_job <- function(job_id, public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
result <- api_request(paste0("/jobs/", job_id), creds$public_key, creds$secret_key,
|
||||
method = "DELETE")
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' List Jobs
|
||||
#'
|
||||
#' Lists recent jobs for the authenticated account.
|
||||
#'
|
||||
#' @param status Filter by status (optional): "pending", "running", "completed", "failed"
|
||||
#' @param limit Maximum number of jobs to return (default: 50)
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing jobs array
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' jobs <- list_jobs()
|
||||
#' running <- list_jobs(status = "running")
|
||||
#' }
|
||||
list_jobs <- function(status = NULL, limit = 50, public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
endpoint <- paste0("/jobs?limit=", limit)
|
||||
if (!is.null(status)) endpoint <- paste0(endpoint, "&status=", status)
|
||||
result <- api_request(endpoint, creds$public_key, creds$secret_key)
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' Run Code from File
|
||||
#'
|
||||
#' Convenience function to execute code from a file with auto-detected language.
|
||||
#'
|
||||
#' @param filepath Path to the source file
|
||||
#' @param env Named list of environment variables (optional)
|
||||
#' @param network Network mode (optional)
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return Execution result
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' result <- run("script.py")
|
||||
#' result <- run("app.js", env = list(NODE_ENV = "production"))
|
||||
#' }
|
||||
run <- function(filepath, env = NULL, network = "zerotrust",
|
||||
public_key = NULL, secret_key = NULL) {
|
||||
if (!file.exists(filepath)) {
|
||||
stop(paste("File not found:", filepath))
|
||||
}
|
||||
|
||||
language <- detect_language(filepath)
|
||||
if (language == "unknown") {
|
||||
stop(paste("Cannot detect language for:", filepath))
|
||||
}
|
||||
|
||||
code <- paste(readLines(filepath, warn = FALSE), collapse = "\n")
|
||||
return(execute(code, language, env = env, network = network,
|
||||
public_key = public_key, secret_key = secret_key))
|
||||
}
|
||||
|
||||
#' Run Code from File Asynchronously
|
||||
#'
|
||||
#' Convenience function to execute code from a file asynchronously.
|
||||
#'
|
||||
#' @param filepath Path to the source file
|
||||
#' @param env Named list of environment variables (optional)
|
||||
#' @param network Network mode (optional)
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing job_id
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' job <- run_async("long_script.py")
|
||||
#' result <- wait(job$job_id)
|
||||
#' }
|
||||
run_async <- function(filepath, env = NULL, network = "zerotrust",
|
||||
public_key = NULL, secret_key = NULL) {
|
||||
if (!file.exists(filepath)) {
|
||||
stop(paste("File not found:", filepath))
|
||||
}
|
||||
|
||||
language <- detect_language(filepath)
|
||||
if (language == "unknown") {
|
||||
stop(paste("Cannot detect language for:", filepath))
|
||||
}
|
||||
|
||||
code <- paste(readLines(filepath, warn = FALSE), collapse = "\n")
|
||||
return(execute_async(code, language, env = env, network = network,
|
||||
public_key = public_key, secret_key = secret_key))
|
||||
}
|
||||
|
||||
#' Get Container Image Information
|
||||
#'
|
||||
#' Retrieves information about the execution environment image.
|
||||
#'
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing image version and installed packages
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' info <- image()
|
||||
#' cat("Image version:", info$version)
|
||||
#' }
|
||||
image <- function(public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
result <- api_request("/image", creds$public_key, creds$secret_key)
|
||||
return(result)
|
||||
}
|
||||
|
||||
#' List Supported Languages
|
||||
#'
|
||||
#' Retrieves the list of supported programming languages.
|
||||
#'
|
||||
#' @param public_key API public key (optional)
|
||||
#' @param secret_key API secret key (optional)
|
||||
#' @return A list containing supported languages with their details
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' langs <- languages()
|
||||
#' print(names(langs$languages))
|
||||
#' }
|
||||
languages <- function(public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
result <- api_request("/languages", creds$public_key, creds$secret_key)
|
||||
return(result)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Client Class (R6)
|
||||
# =============================================================================
|
||||
|
||||
#' Unsandbox Client Class
|
||||
#'
|
||||
#' An R6 class providing an object-oriented interface to the Unsandbox API.
|
||||
#' Stores credentials for reuse across multiple API calls.
|
||||
#'
|
||||
#' @description
|
||||
#' The Client class provides a convenient way to interact with the Unsandbox API
|
||||
#' when making multiple calls. It stores credentials and provides methods for
|
||||
#' all API operations.
|
||||
#'
|
||||
#' @export
|
||||
#' @examples
|
||||
#' \dontrun{
|
||||
#' # Create client with environment credentials
|
||||
#' client <- Client$new()
|
||||
#'
|
||||
#' # Create client with explicit credentials
|
||||
#' client <- Client$new(public_key = "unsb-pk-xxxx", secret_key = "unsb-sk-xxxx")
|
||||
#'
|
||||
#' # Execute code
|
||||
#' result <- client$execute("print('Hello')", "python")
|
||||
#'
|
||||
#' # Async execution
|
||||
#' job <- client$execute_async("import time; time.sleep(10)", "python")
|
||||
#' result <- client$wait(job$job_id)
|
||||
#' }
|
||||
Client <- NULL
|
||||
|
||||
# Only create if R6 is available
|
||||
if (requireNamespace("R6", quietly = TRUE)) {
|
||||
Client <- R6::R6Class("Client",
|
||||
public = list(
|
||||
#' @field public_key The API public key
|
||||
public_key = NULL,
|
||||
#' @field secret_key The API secret key
|
||||
secret_key = NULL,
|
||||
|
||||
#' @description
|
||||
#' Create a new Unsandbox client
|
||||
#' @param public_key Optional public key (uses credential chain if not provided)
|
||||
#' @param secret_key Optional secret key (uses credential chain if not provided)
|
||||
initialize = function(public_key = NULL, secret_key = NULL) {
|
||||
creds <- get_credentials(public_key, secret_key)
|
||||
self$public_key <- creds$public_key
|
||||
self$secret_key <- creds$secret_key
|
||||
},
|
||||
|
||||
#' @description Execute code synchronously
|
||||
#' @param code Source code to execute
|
||||
#' @param language Programming language
|
||||
#' @param env Environment variables
|
||||
#' @param input_files Input files
|
||||
#' @param network Network mode
|
||||
#' @param timeout Execution timeout
|
||||
execute = function(code, language, env = NULL, input_files = NULL,
|
||||
network = "zerotrust", timeout = NULL) {
|
||||
execute(code, language, env, input_files, network, timeout,
|
||||
self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Execute code asynchronously
|
||||
#' @param code Source code to execute
|
||||
#' @param language Programming language
|
||||
#' @param env Environment variables
|
||||
#' @param input_files Input files
|
||||
#' @param network Network mode
|
||||
execute_async = function(code, language, env = NULL, input_files = NULL,
|
||||
network = "zerotrust") {
|
||||
execute_async(code, language, env, input_files, network,
|
||||
self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Get job status
|
||||
#' @param job_id Job ID
|
||||
get_job = function(job_id) {
|
||||
get_job(job_id, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Wait for job completion
|
||||
#' @param job_id Job ID
|
||||
#' @param poll_interval Poll interval in seconds
|
||||
#' @param max_wait Maximum wait time
|
||||
wait = function(job_id, poll_interval = 1, max_wait = 300) {
|
||||
wait(job_id, poll_interval, max_wait, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Cancel a job
|
||||
#' @param job_id Job ID
|
||||
cancel_job = function(job_id) {
|
||||
cancel_job(job_id, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description List jobs
|
||||
#' @param status Filter by status
|
||||
#' @param limit Maximum number of jobs
|
||||
list_jobs = function(status = NULL, limit = 50) {
|
||||
list_jobs(status, limit, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Run code from file
|
||||
#' @param filepath Path to source file
|
||||
#' @param env Environment variables
|
||||
#' @param network Network mode
|
||||
run = function(filepath, env = NULL, network = "zerotrust") {
|
||||
run(filepath, env, network, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Run code from file asynchronously
|
||||
#' @param filepath Path to source file
|
||||
#' @param env Environment variables
|
||||
#' @param network Network mode
|
||||
run_async = function(filepath, env = NULL, network = "zerotrust") {
|
||||
run_async(filepath, env, network, self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description Get image information
|
||||
image = function() {
|
||||
image(self$public_key, self$secret_key)
|
||||
},
|
||||
|
||||
#' @description List supported languages
|
||||
languages = function() {
|
||||
languages(self$public_key, self$secret_key)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# CLI Helper Functions
|
||||
# =============================================================================
|
||||
|
||||
read_env_file <- function(path) {
|
||||
if (!file.exists(path)) {
|
||||
cat(sprintf("%sError: Env file not found: %s%s\n", RED, path, RESET), file = stderr())
|
||||
|
|
@ -1126,4 +1656,7 @@ main <- function() {
|
|||
}
|
||||
}
|
||||
|
||||
main()
|
||||
# Only run main if executed as a script (not when sourced as a library)
|
||||
if (!interactive() && identical(environment(), globalenv())) {
|
||||
main()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue