syntax = "proto3"; package chatto.api.v1; import "buf/validate/validate.proto"; import "chatto/api/v1/attachments.proto"; import "google/protobuf/timestamp.proto"; // Upload lifecycle state for a room-scoped attachment upload. enum AssetUploadStatus { // The upload status was not specified. ASSET_UPLOAD_STATUS_UNSPECIFIED = 0; // The upload accepts more chunks. ASSET_UPLOAD_STATUS_OPEN = 1; // The upload has been completed and produced an attachment asset. ASSET_UPLOAD_STATUS_COMPLETED = 2; // The upload was cancelled or expired. ASSET_UPLOAD_STATUS_CANCELLED = 3; } // Current server-side state for one room-scoped attachment upload. message AssetUpload { // Upload session ID. string upload_id = 1; // Room the resulting attachment asset will belong to. string room_id = 2; // Current upload status. AssetUploadStatus status = 3; // Number of bytes committed so far. int64 committed_offset = 4; // Total declared file size in bytes. int64 size = 5; // Maximum accepted chunk size in bytes. int32 max_chunk_size = 6; // SHA-256 digest of the complete file, lowercase hexadecimal. string sha256 = 7; // Upload expiry. Clients should create a new upload after this time. google.protobuf.Timestamp expires_at = 8; // Asset ID after completion. string asset_id = 9; } // Request to start a room-scoped attachment upload. message CreateUploadRequest { reserved 6, 7; reserved "thread_root_event_id", "also_send_to_channel"; // Required room ID. string room_id = 1 [(buf.validate.field).string.min_len = 1]; // Original filename supplied by the client. string filename = 2 [(buf.validate.field).string.min_len = 1]; // MIME content type. Empty values are treated as application/octet-stream. string content_type = 3; // Required total file size in bytes. int64 size = 4 [(buf.validate.field).int64.gte = 0]; // Required SHA-256 digest of the complete file, lowercase hexadecimal. string sha256 = 5 [(buf.validate.field).string = { pattern: "^[a-f0-9]{64}$" }]; } // Response after creating an upload. message CreateUploadResponse { // Created upload session. AssetUpload upload = 1; } // Request to append one chunk to an upload. message UploadChunkRequest { // Required upload session ID. string upload_id = 1 [(buf.validate.field).string.min_len = 1]; // Byte offset where this chunk starts. int64 offset = 2 [(buf.validate.field).int64.gte = 0]; // Chunk bytes. The server enforces a per-RPC size limit. bytes content = 3 [(buf.validate.field).bytes.min_len = 1]; // SHA-256 digest of this chunk, lowercase hexadecimal. string chunk_sha256 = 4 [(buf.validate.field).string = { pattern: "^[a-f0-9]{64}$" }]; } // Response after committing an upload chunk. message UploadChunkResponse { // Updated upload session. AssetUpload upload = 1; } // Request to fetch upload state. message GetUploadRequest { // Required upload session ID. string upload_id = 1 [(buf.validate.field).string.min_len = 1]; } // Response containing upload state. message GetUploadResponse { // Current upload session. AssetUpload upload = 1; } // Request to complete an upload and create its attachment asset. message CompleteUploadRequest { // Required upload session ID. string upload_id = 1 [(buf.validate.field).string.min_len = 1]; } // Response after an upload completes. message CompleteUploadResponse { // Completed upload session. AssetUpload upload = 1; // Attachment asset produced by this upload. Asset asset = 2; } // Request to cancel an upload. message CancelUploadRequest { // Required upload session ID. string upload_id = 1 [(buf.validate.field).string.min_len = 1]; } // Response after cancelling an upload. message CancelUploadResponse { // Updated upload session. AssetUpload upload = 1; } // Creates room-scoped attachment assets through chunked ConnectRPC uploads. service AssetUploadService { // Starts a room-scoped attachment upload for the authenticated user. rpc CreateUpload(CreateUploadRequest) returns (CreateUploadResponse); // Appends one chunk at the upload's current committed offset. rpc UploadChunk(UploadChunkRequest) returns (UploadChunkResponse); // Reads current upload state for retry or resume. rpc GetUpload(GetUploadRequest) returns (GetUploadResponse); // Verifies the completed upload and creates the attachment asset. rpc CompleteUpload(CompleteUploadRequest) returns (CompleteUploadResponse); // Cancels an incomplete upload and releases temporary storage. rpc CancelUpload(CancelUploadRequest) returns (CancelUploadResponse); }