/* * Copyright (C) 2025-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.1 */ #pragma once #include #include #include #include #include #include #include #include "utils/rjson.hh" #include "utils/chunked_vector.hh" #include "utils/seekable_source.hh" namespace seastar { class abort_source; } namespace utils::gcp { struct google_credentials; } namespace utils::gcp::storage { /** * List info on a named object in a bucket */ struct object_info { std::string name; std::string content_type; uint64_t size; uint64_t generation; std::chrono::system_clock::time_point modified; // TODO: what info do we need? }; class client; struct bucket_paging { private: uint32_t max_results; std::string token; bool done; friend class client; public: bucket_paging(uint64_t max = 1000) : max_results(max) , done(false) {} bucket_paging(const bucket_paging&) = delete; bucket_paging(bucket_paging&&) = default; }; /** * Minimal GCP object storage client */ class client { class impl; class object_data_sink; class object_data_source; shared_ptr _impl; public: static const std::string DEFAULT_ENDPOINT; client(client&&); /** * @endpoint - typically https://storage.googleapis.com. * @credentials - google credentials for accessing the bucket(s). Can be nullopt, but only really useful for mockup testing. * @certs - TLS certs (truststore). Optional TLS parameters for connecting to endpoint. Normally not required (default is * using system trust iff endpoint is a https url) */ client(std::string_view endpoint, std::optional credentials, shared_ptr certs={}); /** * Same as above, but with an additional memory limiting semaphore which will be shared across all up/download source/sinks to * limit buffer memory usage. */ client(std::string_view endpoint, std::optional credentials, seastar::semaphore& memory_limit, shared_ptr certs={}); ~client(); /** * Creates a named bucket in project and region, using storage_class */ future<> create_bucket(std::string_view project, std::string_view bucket, std::string_view region = {}, std::string_view storage_class = {}); /** * Creates a named bucket in project, using provided metadata json * See https://cloud.google.com/storage/docs/creating-buckets */ future<> create_bucket(std::string_view project, rjson::value meta); /** * Deletes a bucket. Note: bucket must be empty. */ future<> delete_bucket(std::string_view bucket); /** * List objects in bucket. Optionally applies the @prefix as filter */ future> list_objects(std::string_view bucket, std::string_view prefix = {}); /** * List objects in bucket. Optionally applies the @prefix as filter. Uses page size and offset as defined by * the bucket_pager */ future> list_objects(std::string_view bucket, std::string_view prefix, bucket_paging&); /** * Deletes a named object from bucket */ future<> delete_object(std::string_view bucket, std::string_view object_name); /** * Renames a named object in bucket */ future<> rename_object(std::string_view bucket, std::string_view object_name, std::string_view new_name); /** * Moves a named object from one bucket to a different one using new name */ future<> rename_object(std::string_view bucket, std::string_view object_name, std::string_view new_bucket, std::string_view new_name); /** * Copies a named object to @new_name */ future<> copy_object(std::string_view bucket, std::string_view object_name, std::string_view to_name); /** * Copies a named object to @new_bucket and @new_name */ future<> copy_object(std::string_view bucket, std::string_view object_name, std::string_view new_bucket, std::string_view to_name); /** * Merges sub-objects into a new destination. Actual file will be composed in order of subobject in `source_object`. * @return info of the created, merged object. */ future merge_objects(std::string_view bucket, std::string_view dest_object_name, const std::vector& source_objects, rjson::value metadata = {}, seastar::abort_source* = nullptr); /** * Creates a data_sink for uploading data to a given name in bucket. * * @name - name of object to create/overwrite * @metadata - optional metadata to set in the created object. * * Note: this will overwrite any existing object of the same name. */ seastar::data_sink create_upload_sink(std::string_view bucket, std::string_view object_name, rjson::value metadata = {}, seastar::abort_source* = nullptr) const; /** * Creates a data_source for reading from a named object. */ seekable_data_source create_download_source(std::string_view bucket, std::string_view object_name, seastar::abort_source* = nullptr) const; /** * Checks if an object exists. */ future object_exists(std::string_view bucket, std::string_view object_name, seastar::abort_source* as = nullptr) const; /** * Destroys resources. Must be called before releasing object */ future<> close(); }; class storage_error : public std::runtime_error { int _status; public: storage_error(const std::string&); storage_error(int status, const std::string&); // TODO: make http::status_type non-nested type, and forward declarable int status() const { return _status; } }; class permission_error : public storage_error { public: using mybase = storage_error; using mybase::mybase; }; class failed_operation : public storage_error { public: using mybase = storage_error; using mybase::mybase; }; class failed_upload_error : public failed_operation { public: using mybase = failed_operation; using mybase::mybase; }; }