Backup-bdg's picture
Upload 964 files
51ff9e5 verified
import httpx
import tenacity
from openhands.storage.files import FileStore
from openhands.utils.async_utils import EXECUTOR
class WebHookFileStore(FileStore):
"""
File store which includes a web hook to be invoked after any changes occur.
This class wraps another FileStore implementation and sends HTTP requests
to a specified URL whenever files are written or deleted.
Attributes:
file_store: The underlying FileStore implementation
base_url: The base URL for webhook requests
client: The HTTP client used to make webhook requests
"""
file_store: FileStore
base_url: str
client: httpx.Client
def __init__(
self, file_store: FileStore, base_url: str, client: httpx.Client | None = None
):
"""
Initialize a WebHookFileStore.
Args:
file_store: The underlying FileStore implementation
base_url: The base URL for webhook requests
client: Optional HTTP client to use for requests. If None, a new client will be created.
"""
self.file_store = file_store
self.base_url = base_url
if client is None:
client = httpx.Client()
self.client = client
def write(self, path: str, contents: str | bytes) -> None:
"""
Write contents to a file and trigger a webhook.
Args:
path: The path to write to
contents: The contents to write
"""
self.file_store.write(path, contents)
EXECUTOR.submit(self._on_write, path, contents)
def read(self, path: str) -> str:
"""
Read contents from a file.
Args:
path: The path to read from
Returns:
The contents of the file
"""
return self.file_store.read(path)
def list(self, path: str) -> list[str]:
"""
List files in a directory.
Args:
path: The directory path to list
Returns:
A list of file paths
"""
return self.file_store.list(path)
def delete(self, path: str) -> None:
"""
Delete a file and trigger a webhook.
Args:
path: The path to delete
"""
self.file_store.delete(path)
EXECUTOR.submit(self._on_delete, path)
@tenacity.retry(
wait=tenacity.wait_fixed(1),
stop=tenacity.stop_after_attempt(3),
)
def _on_write(self, path: str, contents: str | bytes) -> None:
"""
Send a POST request to the webhook URL when a file is written.
This method is retried up to 3 times with a 1-second delay between attempts.
Args:
path: The path that was written to
contents: The contents that were written
Raises:
httpx.HTTPStatusError: If the webhook request fails
"""
base_url = self.base_url + path
response = self.client.post(base_url, content=contents)
response.raise_for_status()
@tenacity.retry(
wait=tenacity.wait_fixed(1),
stop=tenacity.stop_after_attempt(3),
)
def _on_delete(self, path: str) -> None:
"""
Send a DELETE request to the webhook URL when a file is deleted.
This method is retried up to 3 times with a 1-second delay between attempts.
Args:
path: The path that was deleted
Raises:
httpx.HTTPStatusError: If the webhook request fails
"""
base_url = self.base_url + path
response = self.client.delete(base_url)
response.raise_for_status()