Warning
This documentation is actively being updated as the project evolves and may not be complete in all areas.
Adapter Classes and Architecture¶
Adapter Architecture¶
Jumpstarter adapters transform connections established by drivers into different forms or interfaces. The architecture follows a pattern with these key components:
Adapter Base - Adapters typically follow a context manager pattern using Python’s
with
statement for resource management. Each adapter takes a driver client as input and transforms its connection.Connection Transformation - Adapters create a new interface on top of an existing driver connection, such as forwarding ports, providing web interfaces, or offering terminal-like access.
Resource Lifecycle - Adapters handle proper setup and teardown of resources, ensuring connections are properly established and cleaned up.
Unlike drivers, which have a strict client/server architecture, adapters operate entirely on the client side and transform existing connections rather than establishing new ones directly with hardware or virtual devices.
Adapter Types¶
Different types of adapters serve different needs:
Port Forwarding Adapters - Convert network connections to local ports or sockets
Interactive Adapters - Provide interactive shells or console-like interfaces
Protocol Adapters - Transform connections to use different protocols (e.g., SSH, VNC)
UI Adapters - Create user interfaces for interacting with devices (e.g., web-based VNC)
Implementation Patterns¶
Adapters typically implement the context manager protocol (__enter__
and __exit__
) to ensure proper resource management. The general pattern is:
Initialize with a driver client reference
Set up the transformed connection in
__enter__
Return the appropriate interface (URL, address, interactive object)
Clean up resources in
__exit__
This allows adapters to be used in with
statements for clean, deterministic resource handling.
Example Implementation¶
from contextlib import contextmanager
import socket
import threading
from typing import Tuple, Any
class TcpPortforwardAdapter:
"""
Adapter that forwards a remote TCP port to a local TCP port.
Args:
client: A network driver client that provides a connection
local_host: Host to bind to (default: 127.0.0.1)
local_port: Port to bind to (default: 0, which selects a random port)
Returns:
A tuple of (host, port) when used as a context manager
"""
def __init__(self, client, local_host="127.0.0.1", local_port=0):
self.client = client
self.local_host = local_host
self.local_port = local_port
self._server = None
self._thread = None
def __enter__(self) -> Tuple[str, int]:
# Create a socket server
self._server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._server.bind((self.local_host, self.local_port))
self._server.listen(5)
# Get the actual port (if we used port 0)
self.local_host, self.local_port = self._server.getsockname()
# Start a thread to handle connections
self._thread = threading.Thread(target=self._handle_connections, daemon=True)
self._thread.start()
return (self.local_host, self.local_port)
def __exit__(self, exc_type, exc_val, exc_tb):
if self._server:
self._server.close()
self._server = None
# Thread will exit because it's a daemon
self._thread = None
def _handle_connections(self):
while True:
try:
client_socket, _ = self._server.accept()
# For each connection, establish a connection to the remote
# and set up bidirectional forwarding
remote_conn = self.client.connect()
self._start_forwarding(client_socket, remote_conn)
except Exception:
# Server was closed or other error
break
def _start_forwarding(self, local_socket, remote_conn):
# Set up bidirectional forwarding between local_socket and remote_conn
# Typically done with two threads, one for each direction
# Implementation details depend on the specific driver client interface
pass
# Example usage:
def example_usage():
# Assuming 'client' is a network driver client
with TcpPortforwardAdapter(client, local_port=8080) as (host, port):
print(f"Service available at {host}:{port}")
# The service is now accessible at the local address
# while this context is active
Advanced Usage¶
Adapters can be composed and extended for more complex scenarios:
Chaining adapters: Use the output of one adapter as the input to another
Custom adapters: Create specialized adapters for specific hardware or software interfaces
Extended functionality: Add logging, monitoring, or security features on top of base adapters
Best Practices¶
When working with adapters:
Always use context managers (
with
statements) to ensure proper resource cleanupConsider security implications when forwarding ports or providing network access
Implement proper error handling and retries for robust connections
Use appropriate timeouts to prevent hanging connections
Consider performance implications for long-running connections or high-throughput scenarios