- Renamed src/unsandbox.c -> src/un.c - Renamed src/unsandbox.h -> src/un.h - Updated all references in Makefile, README.md, IMPLEMENTATION.md - Matches un.py, un.js, un.go, etc. naming pattern
12 KiB
un.com C SDK
A complete, production-ready C SDK for the un.com code execution API.
Features
- Synchronous execution (
unsandbox_execute) - Get results immediately - Asynchronous execution (
unsandbox_execute_async+unsandbox_wait_job) - Fire and forget with polling - Job management - Query, cancel, and list jobs
- Language detection - Automatically detect language from file extensions
- Language support - 50+ languages including Python, JavaScript, Go, Rust, etc.
- Credential management - 4-tier priority system (args > env > ~/.unsandbox/ > ./accounts.csv)
- HMAC-SHA256 authentication - Built-in OpenSSL integration
- HTTP client - libcurl-based requests with proper error handling
- Memory safe - Proper allocation and deallocation patterns
- No heavy dependencies - Only requires libcurl and OpenSSL (standard on Linux)
Installation
Dependencies
sudo apt install build-essential libcurl4-openssl-dev libssl-dev
Building
# Build library and examples
cd clients/c
make
# Just build the library (src/un.c and src/unsandbox.h)
make lib
# Build examples (hello_world, fibonacci)
make examples
# Run tests
make test
# Clean
make clean
Quick Start
As a Library
Include the header and link with libcurl and libssl:
#include "unsandbox.h"
int main(void) {
// Execute code synchronously
unsandbox_result_t *result = unsandbox_execute(
"python",
"print('Hello, World!')",
NULL, // uses env vars or ~/.unsandbox/accounts.csv
NULL
);
if (result && result->success) {
printf("Output: %s\n", result->stdout);
unsandbox_free_result(result);
} else {
printf("Error: %s\n", unsandbox_last_error());
return 1;
}
return 0;
}
Compile:
gcc -o myapp myapp.c src/un.c -Isrc -lcurl -lssl -lcrypto
Examples
Hello World (Synchronous)
#include "unsandbox.h"
int main(void) {
// Execute immediately, wait for result
unsandbox_result_t *result = unsandbox_execute(
"python",
"print('Hello')",
NULL, NULL
);
if (result) {
printf("%s", result->stdout);
unsandbox_free_result(result);
}
return 0;
}
Run the example:
cd examples
gcc -o hello_world hello_world.c ../src/un.c -I../src -lcurl -lssl -lcrypto
./hello_world
Fibonacci (Asynchronous)
#include "unsandbox.h"
int main(void) {
// Submit job
char *job_id = unsandbox_execute_async("python",
"def fib(n): return n if n<2 else fib(n-1)+fib(n-2)\n"
"print(fib(10))",
NULL, NULL);
if (job_id) {
printf("Job: %s\n", job_id);
// Wait for completion (with exponential backoff polling)
unsandbox_result_t *result = unsandbox_wait_job(job_id, NULL, NULL);
if (result) {
printf("Result: %s\n", result->stdout);
unsandbox_free_result(result);
}
free(job_id);
}
return 0;
}
Run the example:
cd examples
./fibonacci
API Reference
Core Functions
unsandbox_execute(language, code, public_key, secret_key)
Execute code synchronously and return result immediately.
unsandbox_result_t *result = unsandbox_execute("python", "print(42)", NULL, NULL);
if (result->success) {
printf("stdout: %s\n", result->stdout);
printf("stderr: %s\n", result->stderr);
printf("exit_code: %d\n", result->exit_code);
unsandbox_free_result(result);
}
Parameters:
language(const char *) - Language identifier (e.g., "python", "javascript")code(const char *) - Code to executepublic_key(const char *) - API public key (NULL to use env/config)secret_key(const char *) - API secret key (NULL to use env/config)
Returns: unsandbox_result_t * - Result struct or NULL on error
Result struct:
typedef struct {
char *stdout; // Program output
char *stderr; // Error output
int exit_code; // Process exit code
char *language; // Language used
double execution_time; // Time in seconds
int success; // 1 if successful, 0 if error
char *error_message; // Error description (if any)
} unsandbox_result_t;
unsandbox_execute_async(language, code, public_key, secret_key)
Submit code for async execution, returns immediately with job ID.
char *job_id = unsandbox_execute_async("python", "print(42)", NULL, NULL);
if (job_id) {
printf("Job ID: %s\n", job_id);
free(job_id);
}
Returns: char * - Job ID string (must be freed) or NULL on error
unsandbox_wait_job(job_id, public_key, secret_key)
Wait for async job completion using exponential backoff polling.
unsandbox_result_t *result = unsandbox_wait_job(job_id, NULL, NULL);
if (result) {
// Process result
unsandbox_free_result(result);
}
Returns: unsandbox_result_t * - Result when job completes
unsandbox_get_job(job_id, public_key, secret_key)
Get current job status without waiting.
unsandbox_job_t *job = unsandbox_get_job(job_id, NULL, NULL);
if (job) {
printf("Status: %s\n", job->status); // "pending", "running", "completed"
unsandbox_free_job(job);
}
unsandbox_cancel_job(job_id, public_key, secret_key)
Cancel a running job.
int result = unsandbox_cancel_job(job_id, NULL, NULL);
if (result == 0) {
printf("Job cancelled\n");
}
unsandbox_list_jobs(public_key, secret_key)
List all active jobs for the user.
unsandbox_job_list_t *jobs = unsandbox_list_jobs(NULL, NULL);
if (jobs) {
for (size_t i = 0; i < jobs->count; i++) {
printf("%s: %s\n", jobs->jobs[i].id, jobs->jobs[i].status);
}
unsandbox_free_job_list(jobs);
}
Language Functions
unsandbox_detect_language(filename)
Detect language from file extension.
const char *lang = unsandbox_detect_language("script.py"); // Returns "python"
Supported extensions:
- Python:
.py - JavaScript:
.js, TypeScript:.ts - Go:
.go, Rust:.rs, C:.c, C++:.cpp - Ruby:
.rb, PHP:.php, Bash:.sh - And 40+ more languages...
unsandbox_get_languages(public_key, secret_key)
Get list of all supported languages from the API.
unsandbox_languages_t *langs = unsandbox_get_languages(NULL, NULL);
if (langs) {
for (size_t i = 0; i < langs->count; i++) {
printf("%s\n", langs->languages[i]);
}
unsandbox_free_languages(langs);
}
Credential Management
4-Tier Priority System
Credentials are resolved in this order:
- Function arguments -
unsandbox_execute("python", code, "key", "secret") - Environment variables -
UNSANDBOX_PUBLIC_KEY,UNSANDBOX_SECRET_KEY - Home directory -
~/.unsandbox/accounts.csv(line 0, orUNSANDBOX_ACCOUNT=N) - Current directory -
./accounts.csv(same format)
accounts.csv Format
public_key_1,secret_key_1
public_key_2,secret_key_2
public_key_3,secret_key_3
Usage Examples
# Option 1: Environment variables
export UNSANDBOX_PUBLIC_KEY="unsb-pk-..."
export UNSANDBOX_SECRET_KEY="unsb-sk-..."
./myapp
# Option 2: Config file
mkdir -p ~/.unsandbox
echo "unsb-pk-...,unsb-sk-..." > ~/.unsandbox/accounts.csv
chmod 600 ~/.unsandbox/accounts.csv
./myapp
# Option 3: Multiple accounts (select with UNSANDBOX_ACCOUNT)
echo "unsb-pk-1,unsb-sk-1" > ~/.unsandbox/accounts.csv
echo "unsb-pk-2,unsb-sk-2" >> ~/.unsandbox/accounts.csv
UNSANDBOX_ACCOUNT=1 ./myapp # Uses account 2 (0-indexed)
# Option 4: Inline (least secure)
./myapp --public-key=unsb-pk-... --secret-key=unsb-sk-...
Manual Credential Resolution
char *public_key = NULL, *secret_key = NULL;
if (unsandbox_resolve_credentials(&public_key, &secret_key, NULL, NULL) == 0) {
// Use public_key and secret_key
unsandbox_result_t *result = unsandbox_execute("python", code,
public_key, secret_key);
// Clean up
free(public_key);
free(secret_key);
unsandbox_free_result(result);
}
Memory Management
Always clean up allocated memory:
void unsandbox_free_result(unsandbox_result_t *result);
void unsandbox_free_job(unsandbox_job_t *job);
void unsandbox_free_job_list(unsandbox_job_list_t *jobs);
void unsandbox_free_languages(unsandbox_languages_t *langs);
void unsandbox_free_quota(unsandbox_quota_t *quota);
Utility Functions
unsandbox_last_error()
Get the last error message from a failed operation.
unsandbox_result_t *result = unsandbox_execute("python", "code", NULL, NULL);
if (!result) {
printf("Error: %s\n", unsandbox_last_error());
}
unsandbox_health_check()
Check if the API is available.
int status = unsandbox_health_check();
// Returns: 1 = available, 0 = unavailable, -1 = error
if (status == 1) {
printf("API is up\n");
}
unsandbox_version()
Get SDK version.
printf("SDK version: %s\n", unsandbox_version());
Supported Languages (50+)
Interpreted: Python, JavaScript, TypeScript, Ruby, PHP, Bash, Perl, Lua, R, Clojure, CommonLisp, Elixir, Erlang, Groovy, Idris2, Julia, Nim, Raku, Scheme, Tcl, Dart, Deno, Crystal, Kotlin
Compiled: C, C++, Go, Rust, Java, C#, F#, Haskell, OCaml, Cobol, D, Fortran, Odin, Pascal, V, Zig, Objective-C
Other: Prolog, Forth, WASM (C/C++/Rust/Zig/Go via Emscripten)
Error Handling
All functions return NULL or negative values on error. Check unsandbox_last_error() for details:
unsandbox_result_t *result = unsandbox_execute("python", "code", NULL, NULL);
if (!result) {
fprintf(stderr, "Error: %s\n", unsandbox_last_error());
return 1;
}
// Check execution errors
if (result->exit_code != 0) {
fprintf(stderr, "Execution failed (exit %d): %s\n",
result->exit_code, result->stderr);
}
unsandbox_free_result(result);
Authentication
Requests are authenticated using HMAC-SHA256:
Authorization: Bearer <public_key>
X-Timestamp: <unix_seconds>
X-Signature: HMAC-SHA256(secret_key, "timestamp:METHOD:path:body")
The SDK handles this automatically.
Testing
# Run all tests
make test
# Test specific functionality
make test-library
# Run examples
./examples/hello_world
./examples/fibonacci
Performance
- Synchronous execution: 50-200ms (Python/Bash) to 5-30s (JVM languages)
- Asynchronous execution: ~50ms allocation + background execution
- Polling backoff: 300ms → 450ms → 700ms → 900ms → ... → 2000ms (capped)
Limitations
- Max request body: 1MB per execution
- Max concurrent jobs per API key: Based on subscription tier
- Timeout: 30 seconds per request
- JSON parsing is simplified (use a real JSON library for complex responses)
Troubleshooting
"No credentials found"
Set credentials via environment, config file, or function arguments:
export UNSANDBOX_PUBLIC_KEY="your-key"
export UNSANDBOX_SECRET_KEY="your-secret"
./myapp
"HTTP 401 Unauthorized"
Check your credentials are valid:
curl -H "Authorization: Bearer $UNSANDBOX_PUBLIC_KEY" https://api.un.com/health
Compilation errors
Ensure dependencies are installed:
sudo apt install libcurl4-openssl-dev libssl-dev
Check include paths:
gcc -I/usr/include -c src/un.c
License
PUBLIC DOMAIN - NO LICENSE, NO WARRANTY
Use freely for any purpose.
Examples Directory
hello_world.c- Basic synchronous executionfibonacci.c- Asynchronous execution with polling
Compile examples:
cd examples
make -C .. examples # Or:
gcc -o hello_world hello_world.c ../src/un.c -I../src -lcurl -lssl -lcrypto
./hello_world
See Also
- Python SDK:
../python/sync/src/un.py - Go SDK:
../go/sync/src/un.go - API Documentation:
https://api.un.com/