Develop #16

Merged
tao.chen merged 273 commits from develop into main 2026-08-21 10:42:09 +08:00
3 changed files with 23 additions and 17 deletions
Showing only changes of commit 245f4d346d - Show all commits
+13 -15
View File
@@ -371,7 +371,7 @@ async def upload_script(
context: RequestContext = Depends(request_context), context: RequestContext = Depends(request_context),
session: AsyncSession = Depends(database_session), session: AsyncSession = Depends(database_session),
) -> dict[str, Any]: ) -> dict[str, Any]:
suffix = Path(file_name).suffix.lower() suffix = PurePosixPath(file_name).suffix.lower()
if suffix not in {".py", ".ipynb"}: if suffix not in {".py", ".ipynb"}:
raise HTTPException( raise HTTPException(
status.HTTP_422_UNPROCESSABLE_ENTITY, status.HTTP_422_UNPROCESSABLE_ENTITY,
@@ -637,6 +637,7 @@ async def update_script(
status.HTTP_409_CONFLICT, status.HTTP_409_CONFLICT,
"script has no workspace path", "script has no workspace path",
) )
old_object_id = script.current_object_id
storage_data = await request.app.state.storage_client.create_server_object( storage_data = await request.app.state.storage_client.create_server_object(
workspace_id=context.workspace.workspace_id, workspace_id=context.workspace.workspace_id,
user_id=script.owner_user_id, user_id=script.owner_user_id,
@@ -653,12 +654,16 @@ async def update_script(
f"{hashlib.sha256(content).hexdigest()}" f"{hashlib.sha256(content).hexdigest()}"
), ),
) )
storage_object.content_hash = storage_data["content_hash"] script.current_object_id = storage_data["storage_object_id"]
storage_object.size_bytes = storage_data["size_bytes"]
script.updated_at = datetime.now(UTC).replace(tzinfo=None) script.updated_at = datetime.now(UTC).replace(tzinfo=None)
if old_object_id != script.current_object_id:
try:
await request.app.state.storage_client.delete_object(old_object_id)
except Exception:
pass
return { return {
"request_id": context.request_id, "request_id": context.request_id,
"data": script_payload(script, storage_object), "data": script_payload(script, storage_data),
"meta": {}, "meta": {},
} }
@@ -738,18 +743,11 @@ async def publish_version(
"script working copy is not stored in object storage", "script working copy is not stored in object storage",
) )
def read_object_bytes() -> bytes: content = await asyncio.to_thread(
response = request.app.state.object_store.get_object( request.app.state.object_store.get_bytes,
Bucket=source_object.bucket_name, bucket_name=source_object.bucket_name,
Key=source_object.object_key, object_key=source_object.object_key,
) )
body = response["Body"]
try:
return body.read()
finally:
body.close()
content = await asyncio.to_thread(read_object_bytes)
content_hash = hashlib.sha256(content).hexdigest() content_hash = hashlib.sha256(content).hexdigest()
existing = await session.scalar( existing = await session.scalar(
select(Versions).where( select(Versions).where(
+1 -1
View File
@@ -366,7 +366,7 @@ async def complete_upload_record(
object_key_hash=upload.object_key_hash, object_key_hash=upload.object_key_hash,
storage_uri=f"s3://{upload.bucket_name}/{upload.object_key}", storage_uri=f"s3://{upload.bucket_name}/{upload.object_key}",
file_name=file_name, file_name=file_name,
file_extension=Path(file_name).suffix.lower() or None, file_extension=PurePosixPath(file_name).suffix.lower() or None,
mime_type=actual_content_type, mime_type=actual_content_type,
size_bytes=actual_size, size_bytes=actual_size,
content_hash=actual_hash, content_hash=actual_hash,
+8
View File
@@ -137,6 +137,14 @@ class RustFSObjectStore:
def head(self, *, bucket_name: str, object_key: str) -> dict[str, Any]: def head(self, *, bucket_name: str, object_key: str) -> dict[str, Any]:
return self.internal.head_object(Bucket=bucket_name, Key=object_key) return self.internal.head_object(Bucket=bucket_name, Key=object_key)
def get_bytes(self, *, bucket_name: str, object_key: str) -> bytes:
response = self.internal.get_object(Bucket=bucket_name, Key=object_key)
body: BinaryIO = response["Body"]
try:
return body.read()
finally:
body.close()
def sha256(self, *, bucket_name: str, object_key: str) -> str: def sha256(self, *, bucket_name: str, object_key: str) -> str:
response = self.internal.get_object(Bucket=bucket_name, Key=object_key) response = self.internal.get_object(Bucket=bucket_name, Key=object_key)
body: BinaryIO = response["Body"] body: BinaryIO = response["Body"]