定制 zeevx/php-brimble-sandbox 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

zeevx/php-brimble-sandbox

Composer 安装命令:

composer require zeevx/php-brimble-sandbox

包简介

Framework-agnostic PHP SDK for the Brimble Sandbox API.

README 文档

README

A framework-agnostic PHP client for the Brimble Sandbox API: ephemeral compute environments with exec, code execution, files, snapshots, and persistent volumes.

  • PHP 8.2+ · Guzzle transport · typed DTOs and enums · SSE streaming exec
  • Typed exception mapping, retry with backoff, and the { message, data } envelope handled for you

Using Laravel? See zeevx/laravel-brimble-sandbox for config, a facade, and the container binding.

Install

composer require zeevx/php-brimble-sandbox

Quick start

use Zeevx\BrimbleSandbox\Sandbox;
use Zeevx\BrimbleSandbox\Requests\ExecInput;
use Zeevx\BrimbleSandbox\Requests\CreateSandbox;

$client = new Sandbox(apiKey: '...');   // or set BRIMBLE_SANDBOX_KEY

$sb = $client->sandboxes()->create(new CreateSandbox(template: 'node-22'));

echo $sb->exec(new ExecInput('node -v'))->stdout;   // "v22.x.x"

$sb->putFile('tmp/app.js', "console.log('hi')");
echo $sb->exec(new ExecInput('node /tmp/app.js'))->stdout;

$sb->destroy();

The API key is resolved from the constructor argument first, then the BRIMBLE_SANDBOX_KEY environment variable.

Running commands and code

use Zeevx\BrimbleSandbox\Requests\CodeInput;
use Zeevx\BrimbleSandbox\Enums\CodeLanguage;

// Shell command (pipes, &&, redirects all work)
$result = $sb->exec(new ExecInput(
    cmd: 'npm install && npm test',
    timeoutSeconds: 120,
    cwd: '/app',
    env: ['NODE_ENV' => 'test'],
));
$result->stdout;   // string
$result->exitCode; // int
$result->succeeded(); // bool

// Code snippet, no shell escaping needed
$sb->code(new CodeInput(CodeLanguage::Python, "print('hello')"));

Streaming output

exec/code can stream stdout/stderr as Server-Sent Events. Iterate the frames as they arrive, then read the final result:

$stream = $sb->execStream(new ExecInput('npm install'));

foreach ($stream as $frame) {
    if ($frame->isStdout()) {
        echo $frame->data;
    } elseif ($frame->isStderr()) {
        fwrite(STDERR, $frame->data);
    }
}

$result = $stream->result();   // ExecResult with the captured output + exit code

Files

Paths are relative to the sandbox root (tmp/notes.txt/tmp/notes.txt). The parent directory must already exist.

$sb->putFile('tmp/notes.txt', 'hello');      // upload raw bytes
$contents = $sb->getFile('tmp/notes.txt');   // download as string
$stream   = $sb->downloadStream('big.bin');  // PSR-7 stream for large files

Lifecycle, egress, and stats

use Zeevx\BrimbleSandbox\Enums\SandboxStatus;
use Zeevx\BrimbleSandbox\Requests\UpdateEgress;
use Zeevx\BrimbleSandbox\Enums\SandboxEgressMode;

$sb->pause();                 // -> ack message
$sb->resume();
$sb->wait(SandboxStatus::Ready);   // client-side poll after a resume

$sb->updateEgress(new UpdateEgress(SandboxEgressMode::Restricted, ['api.openai.com']));

$stats = $sb->stats(hoursAgo: 6);  // CPU / memory / network

Snapshots and volumes

use Zeevx\BrimbleSandbox\Requests\CreateVolume;
use Zeevx\BrimbleSandbox\Enums\VolumeType;

// Snapshots
$snap = $sb->createSnapshot('nightly');
$sb->snapshots();                 // this sandbox, paginated
$client->snapshots()->list();     // all snapshots for the account
$client->snapshots()->delete($snap->id);

// Volumes
$volume = $client->volumes()->create(new CreateVolume(
    name: 'node-cache',
    sizeGB: 10,
    region: $regionId,
    type: VolumeType::Sandbox,
));
$client->volumes()->list();
$client->volumes()->delete($volume->id);

Catalog

$client->regions();     // list<Region>: sandbox-eligible regions
$client->templates();   // list<Template>: available images

Pagination

List endpoints return a Paginated object you can iterate directly:

$page = $client->sandboxes()->list(page: 1, limit: 15);

foreach ($page as $sandbox) { /* SandboxData */ }

$page->totalCount;
$page->currentPage;
$page->hasMorePages();

Error handling

Every non-2xx response raises a typed exception. All API exceptions extend SandboxApiException and carry status, method, endpoint, responseBody, and requestId.

Exception Status
AuthException 401, 403
ValidationException 400, 422
NotFoundException 404
RateLimitException 429 (with ->retryAfter)
SandboxApiException any other non-2xx
TransportException no HTTP response (DNS, connection, timeout)
ConfigurationException bad/missing config (e.g. no API key)
use Zeevx\BrimbleSandbox\Exceptions\NotFoundException;
use Zeevx\BrimbleSandbox\Exceptions\SandboxApiException;

try {
    $client->sandboxes()->get($id);
} catch (NotFoundException $e) {
    // ...
} catch (SandboxApiException $e) {
    error_log("{$e->method} {$e->endpoint} -> {$e->status}: {$e->getMessage()}");
}

Retries

Idempotent methods (GET, PUT, DELETE) are retried automatically on 408, 429, 500, 502, 503, 504 with exponential backoff (honouring Retry-After). A POST is only retried when you pass an idempotency key:

$client->sandboxes()->create($input, idempotencyKey: 'my-unique-key');

Tune it on the client:

$client = new Sandbox(apiKey: '...', timeout: 90.0, maxRetries: 2);

Custom HTTP client

Inject your own Guzzle client (middleware, logging, a mock handler in tests):

use Zeevx\BrimbleSandbox\Config;

$client = Sandbox::fromConfig(new Config(apiKey: '...'), $myGuzzleClient);

Development

composer test      # Pest
composer lint      # Pint
composer analyse   # PHPStan level 8

License

MIT

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 6
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-07-04

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固