|
|
@@ -136,6 +136,7 @@ class EventStreamRuntime(Runtime):
|
|
|
env_vars: dict[str, str] | None = None,
|
|
|
status_callback: Callable | None = None,
|
|
|
attach_to_existing: bool = False,
|
|
|
+ headless_mode: bool = True,
|
|
|
):
|
|
|
super().__init__(
|
|
|
config,
|
|
|
@@ -145,6 +146,7 @@ class EventStreamRuntime(Runtime):
|
|
|
env_vars,
|
|
|
status_callback,
|
|
|
attach_to_existing,
|
|
|
+ headless_mode,
|
|
|
)
|
|
|
|
|
|
def __init__(
|
|
|
@@ -156,10 +158,13 @@ class EventStreamRuntime(Runtime):
|
|
|
env_vars: dict[str, str] | None = None,
|
|
|
status_callback: Callable | None = None,
|
|
|
attach_to_existing: bool = False,
|
|
|
+ headless_mode: bool = True,
|
|
|
):
|
|
|
self.config = config
|
|
|
self._host_port = 30000 # initial dummy value
|
|
|
self._container_port = 30001 # initial dummy value
|
|
|
+ self._vscode_url: str | None = None # initial dummy value
|
|
|
+ self._runtime_initialized: bool = False
|
|
|
self.api_url = f'{self.config.sandbox.local_runtime_url}:{self._container_port}'
|
|
|
self.session = requests.Session()
|
|
|
self.status_callback = status_callback
|
|
|
@@ -190,6 +195,7 @@ class EventStreamRuntime(Runtime):
|
|
|
env_vars,
|
|
|
status_callback,
|
|
|
attach_to_existing,
|
|
|
+ headless_mode,
|
|
|
)
|
|
|
|
|
|
async def connect(self):
|
|
|
@@ -221,7 +227,10 @@ class EventStreamRuntime(Runtime):
|
|
|
'info', f'Starting runtime with image: {self.runtime_container_image}'
|
|
|
)
|
|
|
await call_sync_from_async(self._init_container)
|
|
|
- self.log('info', f'Container started: {self.container_name}')
|
|
|
+ self.log(
|
|
|
+ 'info',
|
|
|
+ f'Container started: {self.container_name}. VSCode URL: {self.vscode_url}',
|
|
|
+ )
|
|
|
|
|
|
if not self.attach_to_existing:
|
|
|
self.log('info', f'Waiting for client to become ready at {self.api_url}...')
|
|
|
@@ -237,10 +246,11 @@ class EventStreamRuntime(Runtime):
|
|
|
|
|
|
self.log(
|
|
|
'debug',
|
|
|
- f'Container initialized with plugins: {[plugin.name for plugin in self.plugins]}',
|
|
|
+ f'Container initialized with plugins: {[plugin.name for plugin in self.plugins]}. VSCode URL: {self.vscode_url}',
|
|
|
)
|
|
|
if not self.attach_to_existing:
|
|
|
self.send_status_message(' ')
|
|
|
+ self._runtime_initialized = True
|
|
|
|
|
|
@staticmethod
|
|
|
@lru_cache(maxsize=1)
|
|
|
@@ -261,7 +271,6 @@ class EventStreamRuntime(Runtime):
|
|
|
plugin_arg = (
|
|
|
f'--plugins {" ".join([plugin.name for plugin in self.plugins])} '
|
|
|
)
|
|
|
-
|
|
|
self._host_port = self._find_available_port()
|
|
|
self._container_port = (
|
|
|
self._host_port
|
|
|
@@ -270,6 +279,7 @@ class EventStreamRuntime(Runtime):
|
|
|
|
|
|
use_host_network = self.config.sandbox.use_host_network
|
|
|
network_mode: str | None = 'host' if use_host_network else None
|
|
|
+
|
|
|
port_mapping: dict[str, list[dict[str, str]]] | None = (
|
|
|
None
|
|
|
if use_host_network
|
|
|
@@ -290,6 +300,13 @@ class EventStreamRuntime(Runtime):
|
|
|
if self.config.debug or DEBUG:
|
|
|
environment['DEBUG'] = 'true'
|
|
|
|
|
|
+ if self.vscode_enabled:
|
|
|
+ # vscode is on port +1 from container port
|
|
|
+ if isinstance(port_mapping, dict):
|
|
|
+ port_mapping[f'{self._container_port + 1}/tcp'] = [
|
|
|
+ {'HostPort': str(self._host_port + 1)}
|
|
|
+ ]
|
|
|
+
|
|
|
self.log('debug', f'Workspace Base: {self.config.workspace_base}')
|
|
|
if (
|
|
|
self.config.workspace_mount_path is not None
|
|
|
@@ -630,3 +647,30 @@ class EventStreamRuntime(Runtime):
|
|
|
return port
|
|
|
# If no port is found after max_attempts, return the last tried port
|
|
|
return port
|
|
|
+
|
|
|
+ @property
|
|
|
+ def vscode_url(self) -> str | None:
|
|
|
+ if self.vscode_enabled and self._runtime_initialized:
|
|
|
+ if (
|
|
|
+ hasattr(self, '_vscode_url') and self._vscode_url is not None
|
|
|
+ ): # cached value
|
|
|
+ return self._vscode_url
|
|
|
+
|
|
|
+ response = send_request(
|
|
|
+ self.session,
|
|
|
+ 'GET',
|
|
|
+ f'{self.api_url}/vscode/connection_token',
|
|
|
+ timeout=10,
|
|
|
+ )
|
|
|
+ response_json = response.json()
|
|
|
+ assert isinstance(response_json, dict)
|
|
|
+ if response_json['token'] is None:
|
|
|
+ return None
|
|
|
+ self._vscode_url = f'http://localhost:{self._host_port + 1}/?tkn={response_json["token"]}&folder={self.config.workspace_mount_path_in_sandbox}'
|
|
|
+ self.log(
|
|
|
+ 'debug',
|
|
|
+ f'VSCode URL: {self._vscode_url}',
|
|
|
+ )
|
|
|
+ return self._vscode_url
|
|
|
+ else:
|
|
|
+ return None
|