feat: full feature parity for all 42 SDKs + comprehensive tests
All SDKs now implement 58+ functions matching C reference (un.h): - Execution (8): execute, execute_async, wait_job, get_job, cancel_job, list_jobs, get_languages, detect_language - Sessions (9): list, get, create, destroy, freeze, unfreeze, boost, unboost, execute - Services (17): list, get, create, destroy, freeze, unfreeze, lock, unlock, set_unfreeze_on_demand, redeploy, logs, execute, env_get/set/delete/export, resize - Snapshots (9): list, get, session, service, restore, delete, lock, unlock, clone - Images (13): list, get, publish, delete, lock, unlock, set_visibility, grant/revoke_access, list_trusted, transfer, spawn, clone - PaaS Logs (2): fetch, stream - Utilities (5): validate_keys, hmac_sign, health_check, version, last_error Test suites created for all SDKs with unit, integration, and functional tests. Languages: AWK, Bash, C++, C#, Clojure, COBOL, Crystal, D, Dart, .NET, Elixir, Erlang, F#, Forth, Fortran, Go, Groovy, Haskell, Java, JavaScript, Julia, Kotlin, Lisp, Lua, Nim, Objective-C, OCaml, Perl, PHP, PowerShell, Prolog, Python, R, Raku, Ruby, Rust, Scheme, Swift, Tcl, TypeScript, V, Zig
This commit is contained in:
parent
a5155aed4f
commit
6e746ace44
90 changed files with 28955 additions and 3028 deletions
|
|
@ -413,6 +413,29 @@ class Unsandbox {
|
|||
return $response['snapshots'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details of a specific snapshot.
|
||||
*
|
||||
* @param string $snapshotId Snapshot ID to get details for
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @return array Snapshot details array containing:
|
||||
* - id: Snapshot ID
|
||||
* - name: Snapshot name
|
||||
* - type: "session" or "service"
|
||||
* - source_id: Original resource ID
|
||||
* - hot: Whether snapshot preserves running state
|
||||
* - locked: Whether snapshot is locked
|
||||
* - created_at: Creation timestamp
|
||||
* - size_bytes: Size in bytes
|
||||
* @throws CredentialsException Missing credentials
|
||||
* @throws ApiException API request failed
|
||||
*/
|
||||
public function getSnapshot(string $snapshotId, ?string $publicKey = null, ?string $secretKey = null): array {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
return $this->makeRequest('GET', "/snapshots/{$snapshotId}", $publicKey, $secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore a snapshot.
|
||||
*
|
||||
|
|
@ -1360,6 +1383,22 @@ class Unsandbox {
|
|||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize a service's vCPU allocation.
|
||||
*
|
||||
* @param string $serviceId Service ID to resize
|
||||
* @param int $vcpu Number of vCPUs (1-8 typically)
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @return array Response array with updated service info
|
||||
* @throws CredentialsException Missing credentials
|
||||
* @throws ApiException API request failed
|
||||
*/
|
||||
public function resizeService(string $serviceId, int $vcpu, ?string $publicKey = null, ?string $secretKey = null): array {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
return $this->makeRequest('PATCH', "/services/{$serviceId}", $publicKey, $secretKey, ['vcpu' => $vcpu]);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Key Validation
|
||||
// =========================================================================
|
||||
|
|
@ -1420,6 +1459,172 @@ class Unsandbox {
|
|||
return $this->makeRequest('POST', '/image', $publicKey, $secretKey, $payload);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// PaaS Logs Functions
|
||||
// =========================================================================
|
||||
|
||||
private static ?string $lastError = null;
|
||||
|
||||
/**
|
||||
* Fetch batch logs from the PaaS platform.
|
||||
*
|
||||
* @param string $source Log source - "all", "api", "portal", "pool/cammy", "pool/ai"
|
||||
* @param int $lines Number of lines to fetch (1-10000)
|
||||
* @param string $since Time window - "1m", "5m", "1h", "1d"
|
||||
* @param string|null $grep Optional filter pattern
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @return array Log entries
|
||||
* @throws CredentialsException Missing credentials
|
||||
* @throws ApiException API request failed
|
||||
*/
|
||||
public function logsFetch(
|
||||
string $source = 'all',
|
||||
int $lines = 100,
|
||||
string $since = '5m',
|
||||
?string $grep = null,
|
||||
?string $publicKey = null,
|
||||
?string $secretKey = null
|
||||
): array {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
$path = "/logs?source=" . urlencode($source) . "&lines={$lines}&since=" . urlencode($since);
|
||||
if ($grep !== null) {
|
||||
$path .= "&grep=" . urlencode($grep);
|
||||
}
|
||||
return $this->makeRequest('GET', $path, $publicKey, $secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream logs via Server-Sent Events.
|
||||
*
|
||||
* Blocks until interrupted or server closes connection.
|
||||
*
|
||||
* @param string $source Log source - "all", "api", "portal", "pool/cammy", "pool/ai"
|
||||
* @param string|null $grep Optional filter pattern
|
||||
* @param callable|null $callback Function called for each log line (signature: callback(source, line))
|
||||
* @param string|null $publicKey Optional API key
|
||||
* @param string|null $secretKey Optional API secret
|
||||
* @throws CredentialsException Missing credentials
|
||||
* @throws ApiException API request failed
|
||||
*/
|
||||
public function logsStream(
|
||||
string $source = 'all',
|
||||
?string $grep = null,
|
||||
?callable $callback = null,
|
||||
?string $publicKey = null,
|
||||
?string $secretKey = null
|
||||
): void {
|
||||
[$publicKey, $secretKey] = $this->resolveCredentials($publicKey, $secretKey);
|
||||
|
||||
$path = "/logs/stream?source=" . urlencode($source);
|
||||
if ($grep !== null) {
|
||||
$path .= "&grep=" . urlencode($grep);
|
||||
}
|
||||
|
||||
$timestamp = time();
|
||||
$signature = $this->signRequest($secretKey, $timestamp, 'GET', $path);
|
||||
|
||||
$ch = curl_init(self::API_BASE . $path);
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => false,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
"Authorization: Bearer {$publicKey}",
|
||||
"X-Timestamp: {$timestamp}",
|
||||
"X-Signature: {$signature}",
|
||||
"Accept: text/event-stream",
|
||||
],
|
||||
CURLOPT_WRITEFUNCTION => function($ch, $data) use ($source, $callback) {
|
||||
$lines = explode("\n", $data);
|
||||
foreach ($lines as $line) {
|
||||
if (strpos($line, 'data: ') === 0) {
|
||||
$json = substr($line, 6);
|
||||
$entry = @json_decode($json, true);
|
||||
$entrySource = $entry['source'] ?? $source;
|
||||
$entryLine = $entry['line'] ?? $json;
|
||||
|
||||
if ($callback !== null) {
|
||||
$callback($entrySource, $entryLine);
|
||||
} else {
|
||||
echo "[{$entrySource}] {$entryLine}\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return strlen($data);
|
||||
},
|
||||
]);
|
||||
|
||||
curl_exec($ch);
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
// Utility Functions
|
||||
// =========================================================================
|
||||
|
||||
public const SDK_VERSION = '4.2.0';
|
||||
|
||||
/**
|
||||
* Get the SDK version string.
|
||||
*
|
||||
* @return string Version string (e.g., "4.2.0")
|
||||
*/
|
||||
public static function version(): string {
|
||||
return self::SDK_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the API is healthy and responding.
|
||||
*
|
||||
* @return bool true if API is healthy, false otherwise
|
||||
*/
|
||||
public static function healthCheck(): bool {
|
||||
$ch = curl_init(self::API_BASE . '/health');
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
]);
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($ch);
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
self::$lastError = "Health check failed: {$error}";
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
self::$lastError = "Health check failed: HTTP {$httpCode}";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last error message.
|
||||
*
|
||||
* @return string|null Last error message or null
|
||||
*/
|
||||
public static function lastError(): ?string {
|
||||
return self::$lastError;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a message using HMAC-SHA256.
|
||||
*
|
||||
* This is the underlying signing function used for request authentication.
|
||||
* Exposed for testing and debugging purposes.
|
||||
*
|
||||
* @param string $secretKey The secret key for signing
|
||||
* @param string $message The message to sign
|
||||
* @return string 64-character lowercase hex string
|
||||
*/
|
||||
public static function hmacSign(string $secretKey, string $message): string {
|
||||
return hash_hmac('sha256', $message, $secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path to ~/.unsandbox directory, creating if necessary.
|
||||
*
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue