chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:58 +08:00
commit b16403ea71
789 changed files with 115226 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
import httpx
import json
from typing import Callable, Optional
from e2b.envd.rpc import format_terminated_exception
from e2b.exceptions import (
SandboxException,
NotFoundException,
AuthenticationException,
InvalidArgumentException,
NotEnoughSpaceException,
RateLimitException,
format_sandbox_timeout_exception,
)
ENVD_API_FILES_ROUTE = "/files"
ENVD_API_HEALTH_ROUTE = "/health"
_DEFAULT_API_ERROR_MAP: dict[int, Callable[[str], Exception]] = {
400: InvalidArgumentException,
401: AuthenticationException,
404: NotFoundException,
429: lambda message: RateLimitException(
f"{message}: The requests are being rate limited."
),
502: format_sandbox_timeout_exception,
507: NotEnoughSpaceException,
}
HEALTH_CHECK_TIMEOUT = 5 # seconds
def check_sandbox_health(envd_api: httpx.Client) -> Optional[bool]:
"""Probe the sandbox's envd health endpoint.
:return: ``True`` if the sandbox is running, ``False`` if it is not, ``None`` if its state could not be determined.
"""
try:
r = envd_api.get(ENVD_API_HEALTH_ROUTE, timeout=HEALTH_CHECK_TIMEOUT)
if r.status_code == 502:
return False
if r.is_success:
return True
return None
except Exception:
return None
async def acheck_sandbox_health(envd_api: httpx.AsyncClient) -> Optional[bool]:
"""Async version of :func:`check_sandbox_health`."""
try:
r = await envd_api.get(ENVD_API_HEALTH_ROUTE, timeout=HEALTH_CHECK_TIMEOUT)
if r.status_code == 502:
return False
if r.is_success:
return True
return None
except Exception:
return None
def handle_envd_api_transport_exception(
e: Exception,
sandbox_running: Optional[bool] = None,
) -> Exception:
"""Handle transport-level errors from envd API requests.
:param e: The caught exception, expected to be a transport-level ``httpx`` error.
:param sandbox_running: Result of a sandbox health probe (``None`` when unknown), used to disambiguate a connection dropped mid-request.
:return: A ``TimeoutException`` when the connection dropped mid-request and the sandbox is confirmed gone, or the original exception unchanged otherwise.
"""
# A remote protocol error (e.g. an HTTP/2 stream reset) means the connection to the
# sandbox was dropped mid-request — either the sandbox died or the network failed
if isinstance(e, httpx.RemoteProtocolError):
return format_terminated_exception(e, sandbox_running)
return e
def handle_envd_api_transport_exception_with_health(
e: Exception,
envd_api: httpx.Client,
) -> Exception:
"""Like :func:`handle_envd_api_transport_exception`, but when the connection to the
sandbox was dropped mid-request it probes the sandbox health to tell apart the sandbox
being killed from a transient network failure (e.g. a load balancer dropping the connection).
"""
sandbox_running = (
check_sandbox_health(envd_api)
if isinstance(e, httpx.RemoteProtocolError)
else None
)
return handle_envd_api_transport_exception(e, sandbox_running)
async def ahandle_envd_api_transport_exception_with_health(
e: Exception,
envd_api: httpx.AsyncClient,
) -> Exception:
"""Async version of :func:`handle_envd_api_transport_exception_with_health`."""
sandbox_running = (
await acheck_sandbox_health(envd_api)
if isinstance(e, httpx.RemoteProtocolError)
else None
)
return handle_envd_api_transport_exception(e, sandbox_running)
def get_message(e: httpx.Response) -> str:
try:
message = e.json().get("message", e.text)
except json.JSONDecodeError:
message = e.text
return message
def handle_envd_api_exception(
res: httpx.Response,
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
):
"""Handle errors from envd API responses by mapping HTTP status codes to specific exception types.
:param res: The HTTP response.
:param error_map: Optional map of HTTP status codes to exception factories that override the defaults.
:return: The corresponding exception, or ``None`` if the response is successful.
"""
if res.is_success:
return
res.read()
return format_envd_api_exception(res.status_code, get_message(res), error_map)
async def ahandle_envd_api_exception(
res: httpx.Response,
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
):
"""Async version of :func:`handle_envd_api_exception`."""
if res.is_success:
return
await res.aread()
return format_envd_api_exception(res.status_code, get_message(res), error_map)
def format_envd_api_exception(
status_code: int,
message: str,
error_map: Optional[dict[int, Callable[[str], Exception]]] = None,
):
"""Map an HTTP status code and message to the appropriate exception.
:param status_code: The HTTP status code.
:param message: The error message from the response body.
:param error_map: Optional map of HTTP status codes to exception factories that override the defaults.
:return: The corresponding exception.
"""
if error_map and status_code in error_map:
return error_map[status_code](message)
if status_code in _DEFAULT_API_ERROR_MAP:
return _DEFAULT_API_ERROR_MAP[status_code](message)
return SandboxException(f"{status_code}: {message}")
@@ -0,0 +1,193 @@
# Code generated by protoc-gen-connect-python 0.1.0.dev2, DO NOT EDIT.
from typing import Any, Generator, Coroutine, AsyncGenerator, Optional
from httpcore import ConnectionPool, AsyncConnectionPool
import e2b_connect as connect
from e2b.envd.filesystem import filesystem_pb2 as filesystem_dot_filesystem__pb2
FilesystemName = "filesystem.Filesystem"
class FilesystemClient:
def __init__(
self,
base_url: str,
*,
pool: Optional[ConnectionPool] = None,
async_pool: Optional[AsyncConnectionPool] = None,
compressor=None,
json=False,
**opts,
):
self._stat = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/Stat",
response_type=filesystem_dot_filesystem__pb2.StatResponse,
compressor=compressor,
json=json,
**opts,
)
self._make_dir = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/MakeDir",
response_type=filesystem_dot_filesystem__pb2.MakeDirResponse,
compressor=compressor,
json=json,
**opts,
)
self._move = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/Move",
response_type=filesystem_dot_filesystem__pb2.MoveResponse,
compressor=compressor,
json=json,
**opts,
)
self._list_dir = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/ListDir",
response_type=filesystem_dot_filesystem__pb2.ListDirResponse,
compressor=compressor,
json=json,
**opts,
)
self._remove = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/Remove",
response_type=filesystem_dot_filesystem__pb2.RemoveResponse,
compressor=compressor,
json=json,
**opts,
)
self._watch_dir = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/WatchDir",
response_type=filesystem_dot_filesystem__pb2.WatchDirResponse,
compressor=compressor,
json=json,
**opts,
)
self._create_watcher = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/CreateWatcher",
response_type=filesystem_dot_filesystem__pb2.CreateWatcherResponse,
compressor=compressor,
json=json,
**opts,
)
self._get_watcher_events = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/GetWatcherEvents",
response_type=filesystem_dot_filesystem__pb2.GetWatcherEventsResponse,
compressor=compressor,
json=json,
**opts,
)
self._remove_watcher = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{FilesystemName}/RemoveWatcher",
response_type=filesystem_dot_filesystem__pb2.RemoveWatcherResponse,
compressor=compressor,
json=json,
**opts,
)
def stat(
self, req: filesystem_dot_filesystem__pb2.StatRequest, **opts
) -> filesystem_dot_filesystem__pb2.StatResponse:
return self._stat.call_unary(req, **opts)
def astat(
self, req: filesystem_dot_filesystem__pb2.StatRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.StatResponse]:
return self._stat.acall_unary(req, **opts)
def make_dir(
self, req: filesystem_dot_filesystem__pb2.MakeDirRequest, **opts
) -> filesystem_dot_filesystem__pb2.MakeDirResponse:
return self._make_dir.call_unary(req, **opts)
def amake_dir(
self, req: filesystem_dot_filesystem__pb2.MakeDirRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.MakeDirResponse]:
return self._make_dir.acall_unary(req, **opts)
def move(
self, req: filesystem_dot_filesystem__pb2.MoveRequest, **opts
) -> filesystem_dot_filesystem__pb2.MoveResponse:
return self._move.call_unary(req, **opts)
def amove(
self, req: filesystem_dot_filesystem__pb2.MoveRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.MoveResponse]:
return self._move.acall_unary(req, **opts)
def list_dir(
self, req: filesystem_dot_filesystem__pb2.ListDirRequest, **opts
) -> filesystem_dot_filesystem__pb2.ListDirResponse:
return self._list_dir.call_unary(req, **opts)
def alist_dir(
self, req: filesystem_dot_filesystem__pb2.ListDirRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.ListDirResponse]:
return self._list_dir.acall_unary(req, **opts)
def remove(
self, req: filesystem_dot_filesystem__pb2.RemoveRequest, **opts
) -> filesystem_dot_filesystem__pb2.RemoveResponse:
return self._remove.call_unary(req, **opts)
def aremove(
self, req: filesystem_dot_filesystem__pb2.RemoveRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.RemoveResponse]:
return self._remove.acall_unary(req, **opts)
def watch_dir(
self, req: filesystem_dot_filesystem__pb2.WatchDirRequest, **opts
) -> Generator[filesystem_dot_filesystem__pb2.WatchDirResponse, Any, None]:
return self._watch_dir.call_server_stream(req, **opts)
def awatch_dir(
self, req: filesystem_dot_filesystem__pb2.WatchDirRequest, **opts
) -> AsyncGenerator[filesystem_dot_filesystem__pb2.WatchDirResponse, Any]:
return self._watch_dir.acall_server_stream(req, **opts)
def create_watcher(
self, req: filesystem_dot_filesystem__pb2.CreateWatcherRequest, **opts
) -> filesystem_dot_filesystem__pb2.CreateWatcherResponse:
return self._create_watcher.call_unary(req, **opts)
def acreate_watcher(
self, req: filesystem_dot_filesystem__pb2.CreateWatcherRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.CreateWatcherResponse]:
return self._create_watcher.acall_unary(req, **opts)
def get_watcher_events(
self, req: filesystem_dot_filesystem__pb2.GetWatcherEventsRequest, **opts
) -> filesystem_dot_filesystem__pb2.GetWatcherEventsResponse:
return self._get_watcher_events.call_unary(req, **opts)
def aget_watcher_events(
self, req: filesystem_dot_filesystem__pb2.GetWatcherEventsRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.GetWatcherEventsResponse]:
return self._get_watcher_events.acall_unary(req, **opts)
def remove_watcher(
self, req: filesystem_dot_filesystem__pb2.RemoveWatcherRequest, **opts
) -> filesystem_dot_filesystem__pb2.RemoveWatcherResponse:
return self._remove_watcher.call_unary(req, **opts)
def aremove_watcher(
self, req: filesystem_dot_filesystem__pb2.RemoveWatcherRequest, **opts
) -> Coroutine[Any, Any, filesystem_dot_filesystem__pb2.RemoveWatcherResponse]:
return self._remove_watcher.acall_unary(req, **opts)
@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: filesystem/filesystem.proto
# Protobuf Python Version: 5.26.1
"""Generated protocol buffer code."""
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x66ilesystem/filesystem.proto\x12\nfilesystem\x1a\x1fgoogle/protobuf/timestamp.proto\"G\n\x0bMoveRequest\x12\x16\n\x06source\x18\x01 \x01(\tR\x06source\x12 \n\x0b\x64\x65stination\x18\x02 \x01(\tR\x0b\x64\x65stination\";\n\x0cMoveResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"$\n\x0eMakeDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\">\n\x0fMakeDirResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"#\n\rRemoveRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\"\x10\n\x0eRemoveResponse\"!\n\x0bStatRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\";\n\x0cStatResponse\x12+\n\x05\x65ntry\x18\x01 \x01(\x0b\x32\x15.filesystem.EntryInfoR\x05\x65ntry\"\xd1\x03\n\tEntryInfo\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12(\n\x04type\x18\x02 \x01(\x0e\x32\x14.filesystem.FileTypeR\x04type\x12\x12\n\x04path\x18\x03 \x01(\tR\x04path\x12\x12\n\x04size\x18\x04 \x01(\x03R\x04size\x12\x12\n\x04mode\x18\x05 \x01(\rR\x04mode\x12 \n\x0bpermissions\x18\x06 \x01(\tR\x0bpermissions\x12\x14\n\x05owner\x18\x07 \x01(\tR\x05owner\x12\x14\n\x05group\x18\x08 \x01(\tR\x05group\x12?\n\rmodified_time\x18\t \x01(\x0b\x32\x1a.google.protobuf.TimestampR\x0cmodifiedTime\x12*\n\x0esymlink_target\x18\n \x01(\tH\x00R\rsymlinkTarget\x88\x01\x01\x12?\n\x08metadata\x18\x0b \x03(\x0b\x32#.filesystem.EntryInfo.MetadataEntryR\x08metadata\x1a;\n\rMetadataEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\tR\x05value:\x02\x38\x01\x42\x11\n\x0f_symlink_target\":\n\x0eListDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x14\n\x05\x64\x65pth\x18\x02 \x01(\rR\x05\x64\x65pth\"B\n\x0fListDirResponse\x12/\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x15.filesystem.EntryInfoR\x07\x65ntries\"\x9a\x01\n\x0fWatchDirRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x1c\n\trecursive\x18\x02 \x01(\x08R\trecursive\x12#\n\rinclude_entry\x18\x03 \x01(\x08R\x0cincludeEntry\x12\x30\n\x14\x61llow_network_mounts\x18\x04 \x01(\x08R\x12\x61llowNetworkMounts\"\x8c\x01\n\x0f\x46ilesystemEvent\x12\x12\n\x04name\x18\x01 \x01(\tR\x04name\x12)\n\x04type\x18\x02 \x01(\x0e\x32\x15.filesystem.EventTypeR\x04type\x12\x30\n\x05\x65ntry\x18\x03 \x01(\x0b\x32\x15.filesystem.EntryInfoH\x00R\x05\x65ntry\x88\x01\x01\x42\x08\n\x06_entry\"\xfe\x01\n\x10WatchDirResponse\x12?\n\x05start\x18\x01 \x01(\x0b\x32\'.filesystem.WatchDirResponse.StartEventH\x00R\x05start\x12=\n\nfilesystem\x18\x02 \x01(\x0b\x32\x1b.filesystem.FilesystemEventH\x00R\nfilesystem\x12\x46\n\tkeepalive\x18\x03 \x01(\x0b\x32&.filesystem.WatchDirResponse.KeepAliveH\x00R\tkeepalive\x1a\x0c\n\nStartEvent\x1a\x0b\n\tKeepAliveB\x07\n\x05\x65vent\"\x9f\x01\n\x14\x43reateWatcherRequest\x12\x12\n\x04path\x18\x01 \x01(\tR\x04path\x12\x1c\n\trecursive\x18\x02 \x01(\x08R\trecursive\x12#\n\rinclude_entry\x18\x03 \x01(\x08R\x0cincludeEntry\x12\x30\n\x14\x61llow_network_mounts\x18\x04 \x01(\x08R\x12\x61llowNetworkMounts\"6\n\x15\x43reateWatcherResponse\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"8\n\x17GetWatcherEventsRequest\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"O\n\x18GetWatcherEventsResponse\x12\x33\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x1b.filesystem.FilesystemEventR\x06\x65vents\"5\n\x14RemoveWatcherRequest\x12\x1d\n\nwatcher_id\x18\x01 \x01(\tR\twatcherId\"\x17\n\x15RemoveWatcherResponse*R\n\x08\x46ileType\x12\x19\n\x15\x46ILE_TYPE_UNSPECIFIED\x10\x00\x12\x12\n\x0e\x46ILE_TYPE_FILE\x10\x01\x12\x17\n\x13\x46ILE_TYPE_DIRECTORY\x10\x02*\x98\x01\n\tEventType\x12\x1a\n\x16\x45VENT_TYPE_UNSPECIFIED\x10\x00\x12\x15\n\x11\x45VENT_TYPE_CREATE\x10\x01\x12\x14\n\x10\x45VENT_TYPE_WRITE\x10\x02\x12\x15\n\x11\x45VENT_TYPE_REMOVE\x10\x03\x12\x15\n\x11\x45VENT_TYPE_RENAME\x10\x04\x12\x14\n\x10\x45VENT_TYPE_CHMOD\x10\x05\x32\x9f\x05\n\nFilesystem\x12\x39\n\x04Stat\x12\x17.filesystem.StatRequest\x1a\x18.filesystem.StatResponse\x12\x42\n\x07MakeDir\x12\x1a.filesystem.MakeDirRequest\x1a\x1b.filesystem.MakeDirResponse\x12\x39\n\x04Move\x12\x17.filesystem.MoveRequest\x1a\x18.filesystem.MoveResponse\x12\x42\n\x07ListDir\x12\x1a.filesystem.ListDirRequest\x1a\x1b.filesystem.ListDirResponse\x12?\n\x06Remove\x12\x19.filesystem.RemoveRequest\x1a\x1a.filesystem.RemoveResponse\x12G\n\x08WatchDir\x12\x1b.filesystem.WatchDirRequest\x1a\x1c.filesystem.WatchDirResponse0\x01\x12T\n\rCreateWatcher\x12 .filesystem.CreateWatcherRequest\x1a!.filesystem.CreateWatcherResponse\x12]\n\x10GetWatcherEvents\x12#.filesystem.GetWatcherEventsRequest\x1a$.filesystem.GetWatcherEventsResponse\x12T\n\rRemoveWatcher\x12 .filesystem.RemoveWatcherRequest\x1a!.filesystem.RemoveWatcherResponseBi\n\x0e\x63om.filesystemB\x0f\x46ilesystemProtoP\x01\xa2\x02\x03\x46XX\xaa\x02\nFilesystem\xca\x02\nFilesystem\xe2\x02\x16\x46ilesystem\\GPBMetadata\xea\x02\nFilesystemb\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'filesystem.filesystem_pb2', _globals)
if not _descriptor._USE_C_DESCRIPTORS:
_globals['DESCRIPTOR']._loaded_options = None
_globals['DESCRIPTOR']._serialized_options = b'\n\016com.filesystemB\017FilesystemProtoP\001\242\002\003FXX\252\002\nFilesystem\312\002\nFilesystem\342\002\026Filesystem\\GPBMetadata\352\002\nFilesystem'
_globals['_ENTRYINFO_METADATAENTRY']._loaded_options = None
_globals['_ENTRYINFO_METADATAENTRY']._serialized_options = b'8\001'
_globals['_FILETYPE']._serialized_start=2053
_globals['_FILETYPE']._serialized_end=2135
_globals['_EVENTTYPE']._serialized_start=2138
_globals['_EVENTTYPE']._serialized_end=2290
_globals['_MOVEREQUEST']._serialized_start=76
_globals['_MOVEREQUEST']._serialized_end=147
_globals['_MOVERESPONSE']._serialized_start=149
_globals['_MOVERESPONSE']._serialized_end=208
_globals['_MAKEDIRREQUEST']._serialized_start=210
_globals['_MAKEDIRREQUEST']._serialized_end=246
_globals['_MAKEDIRRESPONSE']._serialized_start=248
_globals['_MAKEDIRRESPONSE']._serialized_end=310
_globals['_REMOVEREQUEST']._serialized_start=312
_globals['_REMOVEREQUEST']._serialized_end=347
_globals['_REMOVERESPONSE']._serialized_start=349
_globals['_REMOVERESPONSE']._serialized_end=365
_globals['_STATREQUEST']._serialized_start=367
_globals['_STATREQUEST']._serialized_end=400
_globals['_STATRESPONSE']._serialized_start=402
_globals['_STATRESPONSE']._serialized_end=461
_globals['_ENTRYINFO']._serialized_start=464
_globals['_ENTRYINFO']._serialized_end=929
_globals['_ENTRYINFO_METADATAENTRY']._serialized_start=851
_globals['_ENTRYINFO_METADATAENTRY']._serialized_end=910
_globals['_LISTDIRREQUEST']._serialized_start=931
_globals['_LISTDIRREQUEST']._serialized_end=989
_globals['_LISTDIRRESPONSE']._serialized_start=991
_globals['_LISTDIRRESPONSE']._serialized_end=1057
_globals['_WATCHDIRREQUEST']._serialized_start=1060
_globals['_WATCHDIRREQUEST']._serialized_end=1214
_globals['_FILESYSTEMEVENT']._serialized_start=1217
_globals['_FILESYSTEMEVENT']._serialized_end=1357
_globals['_WATCHDIRRESPONSE']._serialized_start=1360
_globals['_WATCHDIRRESPONSE']._serialized_end=1614
_globals['_WATCHDIRRESPONSE_STARTEVENT']._serialized_start=1580
_globals['_WATCHDIRRESPONSE_STARTEVENT']._serialized_end=1592
_globals['_WATCHDIRRESPONSE_KEEPALIVE']._serialized_start=1594
_globals['_WATCHDIRRESPONSE_KEEPALIVE']._serialized_end=1605
_globals['_CREATEWATCHERREQUEST']._serialized_start=1617
_globals['_CREATEWATCHERREQUEST']._serialized_end=1776
_globals['_CREATEWATCHERRESPONSE']._serialized_start=1778
_globals['_CREATEWATCHERRESPONSE']._serialized_end=1832
_globals['_GETWATCHEREVENTSREQUEST']._serialized_start=1834
_globals['_GETWATCHEREVENTSREQUEST']._serialized_end=1890
_globals['_GETWATCHEREVENTSRESPONSE']._serialized_start=1892
_globals['_GETWATCHEREVENTSRESPONSE']._serialized_end=1971
_globals['_REMOVEWATCHERREQUEST']._serialized_start=1973
_globals['_REMOVEWATCHERREQUEST']._serialized_end=2026
_globals['_REMOVEWATCHERRESPONSE']._serialized_start=2028
_globals['_REMOVEWATCHERRESPONSE']._serialized_end=2051
_globals['_FILESYSTEM']._serialized_start=2293
_globals['_FILESYSTEM']._serialized_end=2964
# @@protoc_insertion_point(module_scope)
+272
View File
@@ -0,0 +1,272 @@
from google.protobuf import timestamp_pb2 as _timestamp_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import (
ClassVar as _ClassVar,
Iterable as _Iterable,
Mapping as _Mapping,
Optional as _Optional,
Union as _Union,
)
DESCRIPTOR: _descriptor.FileDescriptor
class FileType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
FILE_TYPE_UNSPECIFIED: _ClassVar[FileType]
FILE_TYPE_FILE: _ClassVar[FileType]
FILE_TYPE_DIRECTORY: _ClassVar[FileType]
class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
EVENT_TYPE_UNSPECIFIED: _ClassVar[EventType]
EVENT_TYPE_CREATE: _ClassVar[EventType]
EVENT_TYPE_WRITE: _ClassVar[EventType]
EVENT_TYPE_REMOVE: _ClassVar[EventType]
EVENT_TYPE_RENAME: _ClassVar[EventType]
EVENT_TYPE_CHMOD: _ClassVar[EventType]
FILE_TYPE_UNSPECIFIED: FileType
FILE_TYPE_FILE: FileType
FILE_TYPE_DIRECTORY: FileType
EVENT_TYPE_UNSPECIFIED: EventType
EVENT_TYPE_CREATE: EventType
EVENT_TYPE_WRITE: EventType
EVENT_TYPE_REMOVE: EventType
EVENT_TYPE_RENAME: EventType
EVENT_TYPE_CHMOD: EventType
class MoveRequest(_message.Message):
__slots__ = ("source", "destination")
SOURCE_FIELD_NUMBER: _ClassVar[int]
DESTINATION_FIELD_NUMBER: _ClassVar[int]
source: str
destination: str
def __init__(
self, source: _Optional[str] = ..., destination: _Optional[str] = ...
) -> None: ...
class MoveResponse(_message.Message):
__slots__ = ("entry",)
ENTRY_FIELD_NUMBER: _ClassVar[int]
entry: EntryInfo
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
class MakeDirRequest(_message.Message):
__slots__ = ("path",)
PATH_FIELD_NUMBER: _ClassVar[int]
path: str
def __init__(self, path: _Optional[str] = ...) -> None: ...
class MakeDirResponse(_message.Message):
__slots__ = ("entry",)
ENTRY_FIELD_NUMBER: _ClassVar[int]
entry: EntryInfo
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
class RemoveRequest(_message.Message):
__slots__ = ("path",)
PATH_FIELD_NUMBER: _ClassVar[int]
path: str
def __init__(self, path: _Optional[str] = ...) -> None: ...
class RemoveResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class StatRequest(_message.Message):
__slots__ = ("path",)
PATH_FIELD_NUMBER: _ClassVar[int]
path: str
def __init__(self, path: _Optional[str] = ...) -> None: ...
class StatResponse(_message.Message):
__slots__ = ("entry",)
ENTRY_FIELD_NUMBER: _ClassVar[int]
entry: EntryInfo
def __init__(self, entry: _Optional[_Union[EntryInfo, _Mapping]] = ...) -> None: ...
class EntryInfo(_message.Message):
__slots__ = (
"name",
"type",
"path",
"size",
"mode",
"permissions",
"owner",
"group",
"modified_time",
"symlink_target",
"metadata",
)
class MetadataEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: str
def __init__(
self, key: _Optional[str] = ..., value: _Optional[str] = ...
) -> None: ...
NAME_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
PATH_FIELD_NUMBER: _ClassVar[int]
SIZE_FIELD_NUMBER: _ClassVar[int]
MODE_FIELD_NUMBER: _ClassVar[int]
PERMISSIONS_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
GROUP_FIELD_NUMBER: _ClassVar[int]
MODIFIED_TIME_FIELD_NUMBER: _ClassVar[int]
SYMLINK_TARGET_FIELD_NUMBER: _ClassVar[int]
METADATA_FIELD_NUMBER: _ClassVar[int]
name: str
type: FileType
path: str
size: int
mode: int
permissions: str
owner: str
group: str
modified_time: _timestamp_pb2.Timestamp
symlink_target: str
metadata: _containers.ScalarMap[str, str]
def __init__(
self,
name: _Optional[str] = ...,
type: _Optional[_Union[FileType, str]] = ...,
path: _Optional[str] = ...,
size: _Optional[int] = ...,
mode: _Optional[int] = ...,
permissions: _Optional[str] = ...,
owner: _Optional[str] = ...,
group: _Optional[str] = ...,
modified_time: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...,
symlink_target: _Optional[str] = ...,
metadata: _Optional[_Mapping[str, str]] = ...,
) -> None: ...
class ListDirRequest(_message.Message):
__slots__ = ("path", "depth")
PATH_FIELD_NUMBER: _ClassVar[int]
DEPTH_FIELD_NUMBER: _ClassVar[int]
path: str
depth: int
def __init__(
self, path: _Optional[str] = ..., depth: _Optional[int] = ...
) -> None: ...
class ListDirResponse(_message.Message):
__slots__ = ("entries",)
ENTRIES_FIELD_NUMBER: _ClassVar[int]
entries: _containers.RepeatedCompositeFieldContainer[EntryInfo]
def __init__(
self, entries: _Optional[_Iterable[_Union[EntryInfo, _Mapping]]] = ...
) -> None: ...
class WatchDirRequest(_message.Message):
__slots__ = ("path", "recursive", "include_entry", "allow_network_mounts")
PATH_FIELD_NUMBER: _ClassVar[int]
RECURSIVE_FIELD_NUMBER: _ClassVar[int]
INCLUDE_ENTRY_FIELD_NUMBER: _ClassVar[int]
ALLOW_NETWORK_MOUNTS_FIELD_NUMBER: _ClassVar[int]
path: str
recursive: bool
include_entry: bool
allow_network_mounts: bool
def __init__(
self,
path: _Optional[str] = ...,
recursive: bool = ...,
include_entry: bool = ...,
allow_network_mounts: bool = ...,
) -> None: ...
class FilesystemEvent(_message.Message):
__slots__ = ("name", "type", "entry")
NAME_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
ENTRY_FIELD_NUMBER: _ClassVar[int]
name: str
type: EventType
entry: EntryInfo
def __init__(
self,
name: _Optional[str] = ...,
type: _Optional[_Union[EventType, str]] = ...,
entry: _Optional[_Union[EntryInfo, _Mapping]] = ...,
) -> None: ...
class WatchDirResponse(_message.Message):
__slots__ = ("start", "filesystem", "keepalive")
class StartEvent(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class KeepAlive(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
START_FIELD_NUMBER: _ClassVar[int]
FILESYSTEM_FIELD_NUMBER: _ClassVar[int]
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
start: WatchDirResponse.StartEvent
filesystem: FilesystemEvent
keepalive: WatchDirResponse.KeepAlive
def __init__(
self,
start: _Optional[_Union[WatchDirResponse.StartEvent, _Mapping]] = ...,
filesystem: _Optional[_Union[FilesystemEvent, _Mapping]] = ...,
keepalive: _Optional[_Union[WatchDirResponse.KeepAlive, _Mapping]] = ...,
) -> None: ...
class CreateWatcherRequest(_message.Message):
__slots__ = ("path", "recursive", "include_entry", "allow_network_mounts")
PATH_FIELD_NUMBER: _ClassVar[int]
RECURSIVE_FIELD_NUMBER: _ClassVar[int]
INCLUDE_ENTRY_FIELD_NUMBER: _ClassVar[int]
ALLOW_NETWORK_MOUNTS_FIELD_NUMBER: _ClassVar[int]
path: str
recursive: bool
include_entry: bool
allow_network_mounts: bool
def __init__(
self,
path: _Optional[str] = ...,
recursive: bool = ...,
include_entry: bool = ...,
allow_network_mounts: bool = ...,
) -> None: ...
class CreateWatcherResponse(_message.Message):
__slots__ = ("watcher_id",)
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
watcher_id: str
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
class GetWatcherEventsRequest(_message.Message):
__slots__ = ("watcher_id",)
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
watcher_id: str
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
class GetWatcherEventsResponse(_message.Message):
__slots__ = ("events",)
EVENTS_FIELD_NUMBER: _ClassVar[int]
events: _containers.RepeatedCompositeFieldContainer[FilesystemEvent]
def __init__(
self, events: _Optional[_Iterable[_Union[FilesystemEvent, _Mapping]]] = ...
) -> None: ...
class RemoveWatcherRequest(_message.Message):
__slots__ = ("watcher_id",)
WATCHER_ID_FIELD_NUMBER: _ClassVar[int]
watcher_id: str
def __init__(self, watcher_id: _Optional[str] = ...) -> None: ...
class RemoveWatcherResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
+174
View File
@@ -0,0 +1,174 @@
# Code generated by protoc-gen-connect-python 0.1.0.dev2, DO NOT EDIT.
from typing import Any, Generator, Coroutine, AsyncGenerator, Optional
from httpcore import ConnectionPool, AsyncConnectionPool
import e2b_connect as connect
from e2b.envd.process import process_pb2 as process_dot_process__pb2
ProcessName = "process.Process"
class ProcessClient:
def __init__(
self,
base_url: str,
*,
pool: Optional[ConnectionPool] = None,
async_pool: Optional[AsyncConnectionPool] = None,
compressor=None,
json=False,
**opts,
):
self._list = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/List",
response_type=process_dot_process__pb2.ListResponse,
compressor=compressor,
json=json,
**opts,
)
self._connect = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/Connect",
response_type=process_dot_process__pb2.ConnectResponse,
compressor=compressor,
json=json,
**opts,
)
self._start = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/Start",
response_type=process_dot_process__pb2.StartResponse,
compressor=compressor,
json=json,
**opts,
)
self._update = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/Update",
response_type=process_dot_process__pb2.UpdateResponse,
compressor=compressor,
json=json,
**opts,
)
self._stream_input = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/StreamInput",
response_type=process_dot_process__pb2.StreamInputResponse,
compressor=compressor,
json=json,
**opts,
)
self._send_input = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/SendInput",
response_type=process_dot_process__pb2.SendInputResponse,
compressor=compressor,
json=json,
**opts,
)
self._send_signal = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/SendSignal",
response_type=process_dot_process__pb2.SendSignalResponse,
compressor=compressor,
json=json,
**opts,
)
self._close_stdin = connect.Client(
pool=pool,
async_pool=async_pool,
url=f"{base_url}/{ProcessName}/CloseStdin",
response_type=process_dot_process__pb2.CloseStdinResponse,
compressor=compressor,
json=json,
**opts,
)
def list(
self, req: process_dot_process__pb2.ListRequest, **opts
) -> process_dot_process__pb2.ListResponse:
return self._list.call_unary(req, **opts)
def alist(
self, req: process_dot_process__pb2.ListRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.ListResponse]:
return self._list.acall_unary(req, **opts)
def connect(
self, req: process_dot_process__pb2.ConnectRequest, **opts
) -> Generator[process_dot_process__pb2.ConnectResponse, Any, None]:
return self._connect.call_server_stream(req, **opts)
def aconnect(
self, req: process_dot_process__pb2.ConnectRequest, **opts
) -> AsyncGenerator[process_dot_process__pb2.ConnectResponse, Any]:
return self._connect.acall_server_stream(req, **opts)
def start(
self, req: process_dot_process__pb2.StartRequest, **opts
) -> Generator[process_dot_process__pb2.StartResponse, Any, None]:
return self._start.call_server_stream(req, **opts)
def astart(
self, req: process_dot_process__pb2.StartRequest, **opts
) -> AsyncGenerator[process_dot_process__pb2.StartResponse, Any]:
return self._start.acall_server_stream(req, **opts)
def update(
self, req: process_dot_process__pb2.UpdateRequest, **opts
) -> process_dot_process__pb2.UpdateResponse:
return self._update.call_unary(req, **opts)
def aupdate(
self, req: process_dot_process__pb2.UpdateRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.UpdateResponse]:
return self._update.acall_unary(req, **opts)
def stream_input(
self, req: process_dot_process__pb2.StreamInputRequest, **opts
) -> process_dot_process__pb2.StreamInputResponse:
return self._stream_input.call_client_stream(req, **opts)
def astream_input(
self, req: process_dot_process__pb2.StreamInputRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.StreamInputResponse]:
return self._stream_input.acall_client_stream(req, **opts)
def send_input(
self, req: process_dot_process__pb2.SendInputRequest, **opts
) -> process_dot_process__pb2.SendInputResponse:
return self._send_input.call_unary(req, **opts)
def asend_input(
self, req: process_dot_process__pb2.SendInputRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.SendInputResponse]:
return self._send_input.acall_unary(req, **opts)
def send_signal(
self, req: process_dot_process__pb2.SendSignalRequest, **opts
) -> process_dot_process__pb2.SendSignalResponse:
return self._send_signal.call_unary(req, **opts)
def asend_signal(
self, req: process_dot_process__pb2.SendSignalRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.SendSignalResponse]:
return self._send_signal.acall_unary(req, **opts)
def close_stdin(
self, req: process_dot_process__pb2.CloseStdinRequest, **opts
) -> process_dot_process__pb2.CloseStdinResponse:
return self._close_stdin.call_unary(req, **opts)
def aclose_stdin(
self, req: process_dot_process__pb2.CloseStdinRequest, **opts
) -> Coroutine[Any, Any, process_dot_process__pb2.CloseStdinResponse]:
return self._close_stdin.acall_unary(req, **opts)
File diff suppressed because one or more lines are too long
+316
View File
@@ -0,0 +1,316 @@
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import (
ClassVar as _ClassVar,
Iterable as _Iterable,
Mapping as _Mapping,
Optional as _Optional,
Union as _Union,
)
DESCRIPTOR: _descriptor.FileDescriptor
class Signal(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = ()
SIGNAL_UNSPECIFIED: _ClassVar[Signal]
SIGNAL_SIGTERM: _ClassVar[Signal]
SIGNAL_SIGKILL: _ClassVar[Signal]
SIGNAL_UNSPECIFIED: Signal
SIGNAL_SIGTERM: Signal
SIGNAL_SIGKILL: Signal
class PTY(_message.Message):
__slots__ = ("size",)
class Size(_message.Message):
__slots__ = ("cols", "rows")
COLS_FIELD_NUMBER: _ClassVar[int]
ROWS_FIELD_NUMBER: _ClassVar[int]
cols: int
rows: int
def __init__(
self, cols: _Optional[int] = ..., rows: _Optional[int] = ...
) -> None: ...
SIZE_FIELD_NUMBER: _ClassVar[int]
size: PTY.Size
def __init__(self, size: _Optional[_Union[PTY.Size, _Mapping]] = ...) -> None: ...
class ProcessConfig(_message.Message):
__slots__ = ("cmd", "args", "envs", "cwd")
class EnvsEntry(_message.Message):
__slots__ = ("key", "value")
KEY_FIELD_NUMBER: _ClassVar[int]
VALUE_FIELD_NUMBER: _ClassVar[int]
key: str
value: str
def __init__(
self, key: _Optional[str] = ..., value: _Optional[str] = ...
) -> None: ...
CMD_FIELD_NUMBER: _ClassVar[int]
ARGS_FIELD_NUMBER: _ClassVar[int]
ENVS_FIELD_NUMBER: _ClassVar[int]
CWD_FIELD_NUMBER: _ClassVar[int]
cmd: str
args: _containers.RepeatedScalarFieldContainer[str]
envs: _containers.ScalarMap[str, str]
cwd: str
def __init__(
self,
cmd: _Optional[str] = ...,
args: _Optional[_Iterable[str]] = ...,
envs: _Optional[_Mapping[str, str]] = ...,
cwd: _Optional[str] = ...,
) -> None: ...
class ListRequest(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class ProcessInfo(_message.Message):
__slots__ = ("config", "pid", "tag")
CONFIG_FIELD_NUMBER: _ClassVar[int]
PID_FIELD_NUMBER: _ClassVar[int]
TAG_FIELD_NUMBER: _ClassVar[int]
config: ProcessConfig
pid: int
tag: str
def __init__(
self,
config: _Optional[_Union[ProcessConfig, _Mapping]] = ...,
pid: _Optional[int] = ...,
tag: _Optional[str] = ...,
) -> None: ...
class ListResponse(_message.Message):
__slots__ = ("processes",)
PROCESSES_FIELD_NUMBER: _ClassVar[int]
processes: _containers.RepeatedCompositeFieldContainer[ProcessInfo]
def __init__(
self, processes: _Optional[_Iterable[_Union[ProcessInfo, _Mapping]]] = ...
) -> None: ...
class StartRequest(_message.Message):
__slots__ = ("process", "pty", "tag", "stdin")
PROCESS_FIELD_NUMBER: _ClassVar[int]
PTY_FIELD_NUMBER: _ClassVar[int]
TAG_FIELD_NUMBER: _ClassVar[int]
STDIN_FIELD_NUMBER: _ClassVar[int]
process: ProcessConfig
pty: PTY
tag: str
stdin: bool
def __init__(
self,
process: _Optional[_Union[ProcessConfig, _Mapping]] = ...,
pty: _Optional[_Union[PTY, _Mapping]] = ...,
tag: _Optional[str] = ...,
stdin: bool = ...,
) -> None: ...
class UpdateRequest(_message.Message):
__slots__ = ("process", "pty")
PROCESS_FIELD_NUMBER: _ClassVar[int]
PTY_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
pty: PTY
def __init__(
self,
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
pty: _Optional[_Union[PTY, _Mapping]] = ...,
) -> None: ...
class UpdateResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class ProcessEvent(_message.Message):
__slots__ = ("start", "data", "end", "keepalive")
class StartEvent(_message.Message):
__slots__ = ("pid",)
PID_FIELD_NUMBER: _ClassVar[int]
pid: int
def __init__(self, pid: _Optional[int] = ...) -> None: ...
class DataEvent(_message.Message):
__slots__ = ("stdout", "stderr", "pty")
STDOUT_FIELD_NUMBER: _ClassVar[int]
STDERR_FIELD_NUMBER: _ClassVar[int]
PTY_FIELD_NUMBER: _ClassVar[int]
stdout: bytes
stderr: bytes
pty: bytes
def __init__(
self,
stdout: _Optional[bytes] = ...,
stderr: _Optional[bytes] = ...,
pty: _Optional[bytes] = ...,
) -> None: ...
class EndEvent(_message.Message):
__slots__ = ("exit_code", "exited", "status", "error")
EXIT_CODE_FIELD_NUMBER: _ClassVar[int]
EXITED_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
ERROR_FIELD_NUMBER: _ClassVar[int]
exit_code: int
exited: bool
status: str
error: str
def __init__(
self,
exit_code: _Optional[int] = ...,
exited: bool = ...,
status: _Optional[str] = ...,
error: _Optional[str] = ...,
) -> None: ...
class KeepAlive(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
START_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
END_FIELD_NUMBER: _ClassVar[int]
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
start: ProcessEvent.StartEvent
data: ProcessEvent.DataEvent
end: ProcessEvent.EndEvent
keepalive: ProcessEvent.KeepAlive
def __init__(
self,
start: _Optional[_Union[ProcessEvent.StartEvent, _Mapping]] = ...,
data: _Optional[_Union[ProcessEvent.DataEvent, _Mapping]] = ...,
end: _Optional[_Union[ProcessEvent.EndEvent, _Mapping]] = ...,
keepalive: _Optional[_Union[ProcessEvent.KeepAlive, _Mapping]] = ...,
) -> None: ...
class StartResponse(_message.Message):
__slots__ = ("event",)
EVENT_FIELD_NUMBER: _ClassVar[int]
event: ProcessEvent
def __init__(
self, event: _Optional[_Union[ProcessEvent, _Mapping]] = ...
) -> None: ...
class ConnectResponse(_message.Message):
__slots__ = ("event",)
EVENT_FIELD_NUMBER: _ClassVar[int]
event: ProcessEvent
def __init__(
self, event: _Optional[_Union[ProcessEvent, _Mapping]] = ...
) -> None: ...
class SendInputRequest(_message.Message):
__slots__ = ("process", "input")
PROCESS_FIELD_NUMBER: _ClassVar[int]
INPUT_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
input: ProcessInput
def __init__(
self,
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
input: _Optional[_Union[ProcessInput, _Mapping]] = ...,
) -> None: ...
class SendInputResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class ProcessInput(_message.Message):
__slots__ = ("stdin", "pty")
STDIN_FIELD_NUMBER: _ClassVar[int]
PTY_FIELD_NUMBER: _ClassVar[int]
stdin: bytes
pty: bytes
def __init__(
self, stdin: _Optional[bytes] = ..., pty: _Optional[bytes] = ...
) -> None: ...
class StreamInputRequest(_message.Message):
__slots__ = ("start", "data", "keepalive")
class StartEvent(_message.Message):
__slots__ = ("process",)
PROCESS_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
def __init__(
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
) -> None: ...
class DataEvent(_message.Message):
__slots__ = ("input",)
INPUT_FIELD_NUMBER: _ClassVar[int]
input: ProcessInput
def __init__(
self, input: _Optional[_Union[ProcessInput, _Mapping]] = ...
) -> None: ...
class KeepAlive(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
START_FIELD_NUMBER: _ClassVar[int]
DATA_FIELD_NUMBER: _ClassVar[int]
KEEPALIVE_FIELD_NUMBER: _ClassVar[int]
start: StreamInputRequest.StartEvent
data: StreamInputRequest.DataEvent
keepalive: StreamInputRequest.KeepAlive
def __init__(
self,
start: _Optional[_Union[StreamInputRequest.StartEvent, _Mapping]] = ...,
data: _Optional[_Union[StreamInputRequest.DataEvent, _Mapping]] = ...,
keepalive: _Optional[_Union[StreamInputRequest.KeepAlive, _Mapping]] = ...,
) -> None: ...
class StreamInputResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class SendSignalRequest(_message.Message):
__slots__ = ("process", "signal")
PROCESS_FIELD_NUMBER: _ClassVar[int]
SIGNAL_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
signal: Signal
def __init__(
self,
process: _Optional[_Union[ProcessSelector, _Mapping]] = ...,
signal: _Optional[_Union[Signal, str]] = ...,
) -> None: ...
class SendSignalResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class CloseStdinRequest(_message.Message):
__slots__ = ("process",)
PROCESS_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
def __init__(
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
) -> None: ...
class CloseStdinResponse(_message.Message):
__slots__ = ()
def __init__(self) -> None: ...
class ConnectRequest(_message.Message):
__slots__ = ("process",)
PROCESS_FIELD_NUMBER: _ClassVar[int]
process: ProcessSelector
def __init__(
self, process: _Optional[_Union[ProcessSelector, _Mapping]] = ...
) -> None: ...
class ProcessSelector(_message.Message):
__slots__ = ("pid", "tag")
PID_FIELD_NUMBER: _ClassVar[int]
TAG_FIELD_NUMBER: _ClassVar[int]
pid: int
tag: str
def __init__(
self, pid: _Optional[int] = ..., tag: _Optional[str] = ...
) -> None: ...
+139
View File
@@ -0,0 +1,139 @@
import base64
import httpcore
from typing import Awaitable, Callable, Optional
from packaging.version import Version
from e2b_connect.client import Code, ConnectException
from e2b.exceptions import (
SandboxException,
InvalidArgumentException,
NotFoundException,
TimeoutException,
format_sandbox_timeout_exception,
AuthenticationException,
RateLimitException,
)
from e2b.connection_config import Username, default_username
from e2b.envd.versions import ENVD_DEFAULT_USER
_DEFAULT_RPC_ERROR_MAP: dict[Code, Callable[[str], Exception]] = {
Code.invalid_argument: InvalidArgumentException,
Code.unauthenticated: AuthenticationException,
Code.not_found: NotFoundException,
Code.unavailable: format_sandbox_timeout_exception,
Code.resource_exhausted: lambda message: RateLimitException(
f"{message}: Rate limit exceeded, please try again later."
),
Code.canceled: lambda message: TimeoutException(
f"{message}: This error is likely due to exceeding 'request_timeout'. You can pass the request timeout value as an option when making the request."
),
Code.deadline_exceeded: lambda message: TimeoutException(
f"{message}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active. It can be modified by passing 'timeout' when making the request. Use '0' to disable the timeout."
),
}
def format_terminated_exception(
e: Exception,
sandbox_running: Optional[bool],
) -> Exception:
"""Handle an exception for a connection to the sandbox dropped mid-request: when a
sandbox health probe confirmed the sandbox is gone (``sandbox_running is False``),
return a ``TimeoutException``; otherwise return the original error unchanged."""
if sandbox_running is False:
return TimeoutException(
f"{e}: The sandbox was killed or reached its end of life while the request was in flight."
)
return e
def handle_rpc_exception(
e: Exception,
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
sandbox_running: Optional[bool] = None,
):
"""Handle errors from envd RPC calls by mapping gRPC status codes to specific exception types.
:param e: The caught exception, expected to be a ``ConnectException`` or a transport-level ``httpcore`` error.
:param error_map: Optional map of gRPC codes to exception factories that override the defaults.
:param sandbox_running: Result of a sandbox health probe (``None`` when unknown), used to disambiguate a connection dropped mid-request.
:return: The corresponding exception. A connection dropped mid-request with the sandbox confirmed gone becomes a ``TimeoutException``; non-``ConnectException`` errors are otherwise returned as-is.
"""
if isinstance(e, ConnectException):
if error_map and e.status in error_map:
return error_map[e.status](e.message)
if e.status in _DEFAULT_RPC_ERROR_MAP:
return _DEFAULT_RPC_ERROR_MAP[e.status](e.message)
return SandboxException(f"{e.status}: {e.message}")
# A remote protocol error (e.g. an HTTP/2 stream reset) means the connection to the
# sandbox was dropped mid-request — either the sandbox died or the network failed
if isinstance(e, httpcore.RemoteProtocolError):
return format_terminated_exception(e, sandbox_running)
# A transport-level timeout from httpcore means a configured timeout was exceeded
# before the server responded: `request_timeout` on a unary call's read phase, or
# `connect`/`pool`/`write` on a stream's setup/send phase. Streams have no read
# timeout — the command `timeout` is enforced server-side and surfaces as a
# `deadline_exceeded` ConnectException instead. Unlike the JS SDK, where the
# request timeout is an `AbortSignal` that connect normalizes into a `Code.canceled`
# ConnectError, httpcore raises this raw transport error outside the ConnectException
# path, so we map it here to a `TimeoutException` for a consistent timeout error.
if isinstance(e, httpcore.TimeoutException):
return TimeoutException(
f"{e}: This error is likely due to exceeding 'timeout' — the total time a long running request (like process or directory watch) can be active — or 'request_timeout'. You can modify these by passing 'timeout' or 'request_timeout' when making the request. Use '0' to disable the timeout."
)
return e
def handle_rpc_exception_with_health(
e: Exception,
check_health: Optional[Callable[[], Optional[bool]]] = None,
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
):
"""Like :func:`handle_rpc_exception`, but when the connection to the sandbox was
dropped mid-request it probes the sandbox health to tell apart the sandbox being
killed from a transient network failure (e.g. a load balancer dropping the connection).
"""
sandbox_running = None
if check_health is not None and isinstance(e, httpcore.RemoteProtocolError):
try:
sandbox_running = check_health()
except Exception:
sandbox_running = None
return handle_rpc_exception(e, error_map, sandbox_running)
async def ahandle_rpc_exception_with_health(
e: Exception,
check_health: Optional[Callable[[], Awaitable[Optional[bool]]]] = None,
error_map: Optional[dict[Code, Callable[[str], Exception]]] = None,
):
"""Async version of :func:`handle_rpc_exception_with_health`."""
sandbox_running = None
if check_health is not None and isinstance(e, httpcore.RemoteProtocolError):
try:
sandbox_running = await check_health()
except Exception:
sandbox_running = None
return handle_rpc_exception(e, error_map, sandbox_running)
def authentication_header(
envd_version: Version, user: Optional[Username] = None
) -> dict[str, str]:
if user is None and envd_version < ENVD_DEFAULT_USER:
user = default_username
if not user:
return {}
value = f"{user}:"
encoded = base64.b64encode(value.encode("utf-8")).decode("utf-8")
return {"Authorization": f"Basic {encoded}"}
+11
View File
@@ -0,0 +1,11 @@
from packaging.version import Version
ENVD_VERSION_RECURSIVE_WATCH = Version("0.1.4")
ENVD_DEBUG_FALLBACK = Version("99.99.99")
ENVD_COMMANDS_STDIN = Version("0.3.0")
ENVD_DEFAULT_USER = Version("0.4.0")
ENVD_ENVD_CLOSE = Version("0.5.2")
ENVD_OCTET_STREAM_UPLOAD = Version("0.5.7")
ENVD_FILE_METADATA = Version("0.6.2")
ENVD_VERSION_FS_EVENT_ENTRY_INFO = Version("0.6.3")
ENVD_VERSION_WATCH_NETWORK_MOUNTS = Version("0.6.4")