Spaces:
Build error
Build error
File size: 3,628 Bytes
51ff9e5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
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()
|