blob: 34576cf8365d25fa3fcb044982bc7a7594bdfc6f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
use napi::bindgen_prelude::BigInt;
use opendal::raw::{BytesRange, Timestamp};
use std::collections::HashMap;
#[napi(object)]
#[derive(Debug)]
pub struct StatOptions {
/**
* Sets version for this operation.
* Retrieves data of a specified version of the given path.
*/
pub version: Option<String>,
/**
* Sets if-match condition for this operation.
* If file exists and its etag doesn't match, an error will be returned.
*/
pub if_match: Option<String>,
/**
* Sets if-none-match condition for this operation.
* If file exists and its etag matches, an error will be returned.
*/
pub if_none_match: Option<String>,
/**
* Sets if-modified-since condition for this operation.
* If file exists and hasn't been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_modified_since: Option<String>,
/**
* Sets if-unmodified-since condition for this operation.
* If file exists and has been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_unmodified_since: Option<String>,
/**
* Specifies the content-type header for presigned operations.
* Only meaningful when used along with presign.
*/
pub override_content_type: Option<String>,
/**
* Specifies the cache-control header for presigned operations.
* Only meaningful when used along with presign.
*/
pub override_cache_control: Option<String>,
/**
* Specifies the content-disposition header for presigned operations.
* Only meaningful when used along with presign.
*/
pub override_content_disposition: Option<String>,
}
impl From<StatOptions> for opendal::options::StatOptions {
fn from(value: StatOptions) -> Self {
let if_modified_since = value
.if_modified_since
.and_then(|v| v.parse::<Timestamp>().ok());
let if_unmodified_since = value
.if_unmodified_since
.and_then(|v| v.parse::<Timestamp>().ok());
Self {
if_modified_since,
if_unmodified_since,
version: value.version,
if_match: value.if_match,
if_none_match: value.if_none_match,
override_content_type: value.override_content_type,
override_cache_control: value.override_cache_control,
override_content_disposition: value.override_content_disposition,
}
}
}
#[napi(object)]
#[derive(Default, Debug)]
pub struct ReadOptions {
/**
* Set `version` for this operation.
*
* This option can be used to retrieve the data of a specified version of the given path.
*/
pub version: Option<String>,
/**
* Set `concurrent` for the operation.
*
* OpenDAL by default to read file without concurrent. This is not efficient for cases when users
* read large chunks of data. By setting `concurrent`, opendal will reading files concurrently
* on support storage services.
*
* By setting `concurrent`, opendal will fetch chunks concurrently with
* the give chunk size.
*/
pub concurrent: Option<u32>,
/**
* Sets the chunk size for this operation.
*
* OpenDAL will use services' preferred chunk size by default. Users can set chunk based on their own needs.
*/
pub chunk: Option<u32>,
/**
* Controls the optimization strategy for range reads in [`Reader::fetch`].
*
* When performing range reads, if the gap between two requested ranges is smaller than
* the configured `gap` size, OpenDAL will merge these ranges into a single read request
* and discard the unrequested data in between. This helps reduce the number of API calls
* to remote storage services.
*
* This optimization is particularly useful when performing multiple small range reads
* that are close to each other, as it reduces the overhead of multiple network requests
* at the cost of transferring some additional data.
*/
pub gap: Option<BigInt>,
/**
* Sets the offset (starting position) for range read operations.
* The read will start from this position in the file.
*/
pub offset: Option<BigInt>,
/**
* Sets the size (length) for range read operations.
* The read will continue for this many bytes after the offset.
*/
pub size: Option<BigInt>,
/**
* Sets if-match condition for this operation.
* If file exists and its etag doesn't match, an error will be returned.
*/
pub if_match: Option<String>,
/**
* Sets if-none-match condition for this operation.
* If file exists and its etag matches, an error will be returned.
*/
pub if_none_match: Option<String>,
/**
* Sets if-modified-since condition for this operation.
* If file exists and hasn't been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_modified_since: Option<String>,
/**
* Sets if-unmodified-since condition for this operation.
* If file exists and has been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_unmodified_since: Option<String>,
/**
* Specify the `content-type` header that should be sent back by the operation.
*
* This option is only meaningful when used along with presign.
*/
pub content_type: Option<String>,
/**
* Specify the `cache-control` header that should be sent back by the operation.
*
* This option is only meaningful when used along with presign.
*/
pub cache_control: Option<String>,
/**
* Specify the `content-disposition` header that should be sent back by the operation.
*
* This option is only meaningful when used along with presign.
*/
pub content_disposition: Option<String>,
}
impl ReadOptions {
pub fn make_range(&self) -> BytesRange {
let offset = self.offset.clone().map(|offset| offset.get_u64().1);
let size = self.size.clone().map(|size| size.get_u64().1);
BytesRange::new(offset.unwrap_or_default(), size)
}
}
impl From<ReadOptions> for opendal::options::ReadOptions {
fn from(value: ReadOptions) -> Self {
let range = value.make_range();
let if_modified_since = value
.if_modified_since
.and_then(|v| v.parse::<Timestamp>().ok());
let if_unmodified_since = value
.if_unmodified_since
.and_then(|v| v.parse::<Timestamp>().ok());
Self {
version: value.version,
concurrent: value.concurrent.unwrap_or_default() as usize,
chunk: value.chunk.map(|chunk| chunk as usize),
gap: value.gap.map(|gap| gap.get_u64().1 as usize),
range,
if_match: value.if_match,
if_none_match: value.if_none_match,
if_modified_since,
if_unmodified_since,
override_content_type: value.content_type,
override_cache_control: value.cache_control,
override_content_disposition: value.content_disposition,
}
}
}
#[napi(object)]
#[derive(Default)]
pub struct ReaderOptions {
/**
* Set `version` for this operation.
*
* This option can be used to retrieve the data of a specified version of the given path.
*/
pub version: Option<String>,
/**
* Set `concurrent` for the operation.
*
* OpenDAL by default to read file without concurrent. This is not efficient for cases when users
* read large chunks of data. By setting `concurrent`, opendal will reading files concurrently
* on support storage services.
*
* By setting `concurrent`, opendal will fetch chunks concurrently with
* the give chunk size.
*/
pub concurrent: Option<u32>,
/**
* Sets the chunk size for this operation.
*
* OpenDAL will use services' preferred chunk size by default. Users can set chunk based on their own needs.
*/
pub chunk: Option<u32>,
/** Controls the number of prefetched bytes ranges that can be buffered in memory
* during concurrent reading.
*
* When performing concurrent reads with `Reader`, this option limits how many
* completed-but-not-yet-read chunks can be buffered. Once the number of buffered
* chunks reaches this limit, no new read tasks will be spawned until some of the
* buffered chunks are consumed.
*
* - Default value: 0 (no prefetching, strict back-pressure control)
* - Set to a higher value to allow more aggressive prefetching at the cost of memory
*
* This option helps prevent memory exhaustion when reading large files with high
* concurrency settings.
*/
pub prefetch: Option<u32>,
/**
* Controls the optimization strategy for range reads in [`Reader::fetch`].
*
* When performing range reads, if the gap between two requested ranges is smaller than
* the configured `gap` size, OpenDAL will merge these ranges into a single read request
* and discard the unrequested data in between. This helps reduce the number of API calls
* to remote storage services.
*
* This optimization is particularly useful when performing multiple small range reads
* that are close to each other, as it reduces the overhead of multiple network requests
* at the cost of transferring some additional data.
*/
pub gap: Option<BigInt>,
/**
* Sets if-match condition for this operation.
* If file exists and its etag doesn't match, an error will be returned.
*/
pub if_match: Option<String>,
/**
* Sets if-none-match condition for this operation.
* If file exists and its etag matches, an error will be returned.
*/
pub if_none_match: Option<String>,
/**
* Sets if-modified-since condition for this operation.
* If file exists and hasn't been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_modified_since: Option<String>,
/**
* Sets if-unmodified-since condition for this operation.
* If file exists and has been modified since the specified time, an error will be returned.
* ISO 8601 formatted date string
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
*/
pub if_unmodified_since: Option<String>,
}
impl From<ReaderOptions> for opendal::options::ReaderOptions {
fn from(value: ReaderOptions) -> Self {
let if_modified_since = value
.if_modified_since
.and_then(|v| v.parse::<Timestamp>().ok());
let if_unmodified_since = value
.if_unmodified_since
.and_then(|v| v.parse::<Timestamp>().ok());
Self {
version: value.version,
concurrent: value.concurrent.unwrap_or_default() as usize,
chunk: value.chunk.map(|chunk| chunk as usize),
gap: value.gap.map(|gap| gap.get_u64().1 as usize),
prefetch: value.prefetch.unwrap_or_default() as usize,
if_match: value.if_match,
if_none_match: value.if_none_match,
if_modified_since,
if_unmodified_since,
}
}
}
#[napi(object)]
#[derive(Debug, Default)]
pub struct ListOptions {
/**
* The limit passed to underlying service to specify the max results
* that could return per-request.
*
* Users could use this to control the memory usage of list operation.
*/
pub limit: Option<u32>,
/**
* The start_after passed to underlying service to specify the specified key
* to start listing from.
*/
pub start_after: Option<String>,
/**
* The recursive is used to control whether the list operation is recursive.
*
* - If `false`, list operation will only list the entries under the given path.
* - If `true`, list operation will list all entries that starts with given path.
*
* Default to `false`.
*/
pub recursive: Option<bool>,
/**
* The versions is used to control whether the object versions should be returned.
*
* - If `false`, list operation will not return with object versions
* - If `true`, list operation will return with object versions if object versioning is supported
* by the underlying service
*
* Default to `false`
*/
pub versions: Option<bool>,
/**
* The deleted is used to control whether the deleted objects should be returned.
*
* - If `false`, list operation will not return with deleted objects
* - If `true`, list operation will return with deleted objects if object versioning is supported
* by the underlying service
*
* Default to `false`
*/
pub deleted: Option<bool>,
}
impl From<ListOptions> for opendal::options::ListOptions {
fn from(value: ListOptions) -> Self {
Self {
limit: value.limit.map(|v| v as usize),
start_after: value.start_after,
recursive: value.recursive.unwrap_or_default(),
versions: value.versions.unwrap_or_default(),
deleted: value.deleted.unwrap_or_default(),
}
}
}
#[napi(object)]
#[derive(Default, Debug)]
pub struct WriteOptions {
/// Append bytes into a path.
///
/// ### Notes
///
/// - It always appends content to the end of the file.
/// - It will create file if the path does not exist.
pub append: Option<bool>,
/// Set the chunk of op.
///
/// If chunk is set, the data will be chunked by the underlying writer.
///
/// ## NOTE
///
/// A service could have their own minimum chunk size while perform write
/// operations like multipart uploads. So the chunk size may be larger than
/// the given buffer size.
pub chunk: Option<BigInt>,
/// Set the [Content-Type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) of op.
pub content_type: Option<String>,
/// Set the [Content-Disposition](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) of op.
pub content_disposition: Option<String>,
/// Set the [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) of op.
pub cache_control: Option<String>,
/// Set the [Content-Encoding] https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Encoding of op.
pub content_encoding: Option<String>,
/// Sets user metadata of op.
///
/// If chunk is set, the user metadata will be attached to the object during write.
///
/// ## NOTE
///
/// - Services may have limitations for user metadata, for example:
/// - Key length is typically limited (e.g., 1024 bytes)
/// - Value length is typically limited (e.g., 4096 bytes)
/// - Total metadata size might be limited
/// - Some characters might be forbidden in keys
pub user_metadata: Option<HashMap<String, String>>,
/// Sets if-match condition of op.
///
/// This operation provides conditional write functionality based on ETag matching,
/// helping prevent unintended overwrites in concurrent scenarios.
pub if_match: Option<String>,
/// Sets if-none-match condition of op.
///
/// This operation provides conditional write functionality based on ETag non-matching,
/// useful for preventing overwriting existing resources or ensuring unique writes.
pub if_none_match: Option<String>,
/// Sets if_not_exists condition of op.
///
/// This operation provides a way to ensure write operations only create new resources
/// without overwriting existing ones, useful for implementing "create if not exists" logic.
pub if_not_exists: Option<bool>,
/// Sets concurrent of op.
///
/// - By default, OpenDAL writes files sequentially
/// - When concurrent is set:
/// - Multiple write operations can execute in parallel
/// - Write operations return immediately without waiting if tasks space are available
/// - Close operation ensures all writes complete in order
/// - Memory usage increases with concurrency level
pub concurrent: Option<u32>,
}
impl From<WriteOptions> for opendal::options::WriteOptions {
fn from(value: WriteOptions) -> Self {
Self {
append: value.append.unwrap_or_default(),
chunk: value.chunk.map(|v| v.get_u64().1 as usize),
content_type: value.content_type,
content_disposition: value.content_disposition,
cache_control: value.cache_control,
content_encoding: value.content_encoding,
user_metadata: value.user_metadata,
if_match: value.if_match,
if_none_match: value.if_none_match,
if_not_exists: value.if_not_exists.unwrap_or_default(),
concurrent: value.concurrent.unwrap_or_default() as usize,
}
}
}
#[napi(object)]
#[derive(Default)]
pub struct DeleteOptions {
pub version: Option<String>,
/// Whether to delete recursively.
pub recursive: Option<bool>,
}
impl From<DeleteOptions> for opendal::options::DeleteOptions {
fn from(value: DeleteOptions) -> Self {
Self {
version: value.version,
recursive: value.recursive.unwrap_or_default(),
}
}
}