blob: 1b7156fdd39432fb87dc003f85f50830a848d62f [file]
/**
* 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.
*/
#pragma once
#include <pulsar/Authentication.h>
#include <pulsar/defines.h>
#include <pulsar/st/CheckpointConsumer.h>
#include <pulsar/st/Expected.h>
#include <pulsar/st/Future.h>
#include <pulsar/st/Policies.h>
#include <pulsar/st/Producer.h>
#include <pulsar/st/QueueConsumer.h>
#include <pulsar/st/Schema.h>
#include <pulsar/st/StreamConsumer.h>
#include <pulsar/st/Transaction.h>
#include <pulsar/st/detail/ClientCore.h>
#include <chrono>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
namespace pulsar::st {
class PulsarClientBuilder;
/**
* The heavyweight, thread-safe entry point of the scalable-topics SDK. It owns the
* connection pool, IO threads, and memory buffers. An application SHOULD create a
* single instance and keep it for the whole application lifetime, sharing it
* across all producers and consumers, and close it exactly once at shutdown
* (spec §3).
*
* A `PulsarClient` is a lightweight, copyable handle to that shared state, built
* only through `PulsarClient::builder()`.
*/
class PULSAR_PUBLIC PulsarClient {
public:
/** Copyable, movable handle; copies share the underlying client. */
PulsarClient(const PulsarClient&) = default;
PulsarClient& operator=(const PulsarClient&) = default;
PulsarClient(PulsarClient&&) = default;
PulsarClient& operator=(PulsarClient&&) = default;
/**
* Begin configuring a client.
*
* This is the only way to obtain a PulsarClient: the default constructor is
* private. Set at least PulsarClientBuilder::serviceUrl, then call
* PulsarClientBuilder::build.
*
* @return a fresh, unconfigured client builder
*/
static PulsarClientBuilder builder();
/**
* Start building a producer for values of type `T`.
*
* The schema governs serialization and broker-side compatibility: built-ins
* cover `Bytes` (the default), `std::string` and numeric primitives;
* structured types use `jsonSchema<T>()`, `avroSchema<T>()`,
* `protobufNativeSchema<T>()`, or a custom SerDe (see Schema.h and the
* dedicated schema headers).
*
* @tparam T the value type produced; defaults to `Bytes` (raw payload).
* @param schema the schema describing how `T` is encoded; defaults to the
* built-in schema for `T`.
* @return a ProducerBuilder to further configure and create the producer
*/
template <typename T = Bytes>
ProducerBuilder<T> newProducer(Schema<T> schema = {}) {
return ProducerBuilder<T>(core_, std::move(schema));
}
/**
* Start building a stream consumer: an ordered, broker-managed,
* cumulative-ack consumer (spec §7.1).
*
* @tparam T the value type consumed; defaults to `Bytes` (raw payload).
* @param schema the schema describing how `T` is decoded; defaults to the
* built-in schema for `T`.
* @return a StreamConsumerBuilder to further configure and create the consumer
*/
template <typename T = Bytes>
StreamConsumerBuilder<T> newStreamConsumer(Schema<T> schema = {}) {
return StreamConsumerBuilder<T>(core_, std::move(schema));
}
/**
* Start building a queue consumer: a parallel, broker-managed,
* individual-ack consumer (spec §7.2).
*
* @tparam T the value type consumed; defaults to `Bytes` (raw payload).
* @param schema the schema describing how `T` is decoded; defaults to the
* built-in schema for `T`.
* @return a QueueConsumerBuilder to further configure and create the consumer
*/
template <typename T = Bytes>
QueueConsumerBuilder<T> newQueueConsumer(Schema<T> schema = {}) {
return QueueConsumerBuilder<T>(core_, std::move(schema));
}
/**
* Start building a checkpoint consumer: an unmanaged consumer whose read
* position is held by the client rather than the broker (spec §7.3).
*
* @tparam T the value type consumed; defaults to `Bytes` (raw payload).
* @param schema the schema describing how `T` is decoded; defaults to the
* built-in schema for `T`.
* @return a CheckpointConsumerBuilder to further configure and create the consumer
*/
template <typename T = Bytes>
CheckpointConsumerBuilder<T> newCheckpointConsumer(Schema<T> schema = {}) {
return CheckpointConsumerBuilder<T>(core_, std::move(schema));
}
/**
* Open a new transaction synchronously (spec §9).
*
* Blocks until the transaction has been started by the broker. The
* transaction uses the default timeout configured via
* PulsarClientBuilder::transactionPolicy.
*
* @return the new Transaction, or an Error if it could not be started
*/
Expected<Transaction> newTransaction() { return core_.newTransactionAsync().get(); }
/**
* Open a new transaction asynchronously (spec §9).
*
* @return a Future that completes with the new Transaction, or an Error if it
* could not be started
*/
Future<Transaction> newTransactionAsync() { return core_.newTransactionAsync(); }
/**
* Close the client gracefully.
*
* Awaits all pending operations to complete, then releases every resource the
* client owns (connections, IO threads, buffers). Blocks until the shutdown
* finishes. Call this exactly once at application shutdown.
*
* @return an empty Expected on success, or an Error if the close failed
*/
Expected<void> close() { return core_.closeAsync().get(); }
/**
* Close the client gracefully, asynchronously.
*
* Like close() but returns immediately with a Future that completes once all
* pending operations have drained and resources have been released.
*
* @return a Future that completes empty on success, or with an Error if the
* close failed
*/
Future<void> closeAsync() { return core_.closeAsync(); }
/**
* Shut the client down immediately.
*
* Drops any pending operations without waiting for them and releases
* resources at once. Prefer close() for an orderly shutdown; use this only
* when a graceful close is not possible or not desired.
*/
void shutdown() { core_.shutdown(); }
/**
* Test whether this handle refers to a live client.
*
* @return true if the handle is backed by shared client state; false if it
* has been moved from
*/
explicit operator bool() const { return static_cast<bool>(core_); }
private:
friend class PulsarClientBuilder;
PulsarClient() = default;
explicit PulsarClient(detail::ClientCore core) : core_(std::move(core)) {}
detail::ClientCore core_;
};
/**
* Configures and builds a `PulsarClient`. `serviceUrl` is the only required
* setting; everything else has sensible defaults and is grouped into policy
* objects (spec Appendix A). With C++20 designated initializers:
*
* auto client = PulsarClient::builder()
* .serviceUrl("pulsar://localhost:6650")
* .connectionPolicy({.connectionsPerBroker = 4, .connectionTimeout = 10s})
* .build();
*/
class PULSAR_PUBLIC PulsarClientBuilder {
public:
/**
* REQUIRED — the Pulsar endpoint, e.g. `pulsar://localhost:6650`.
*
* This is the only required setting; build() fails if it is not set.
*
* @param url the broker or proxy service URL to connect to
* @return `*this`, for call chaining
*/
PulsarClientBuilder& serviceUrl(std::string url) {
serviceUrl_ = std::move(url);
return *this;
}
/**
* Set the authentication provider used when connecting to the broker.
*
* Optional. When unset, the client connects without authentication.
*
* @param auth the authentication provider to use
* @return `*this`, for call chaining
*/
PulsarClientBuilder& authentication(AuthenticationPtr auth) {
authentication_ = std::move(auth);
return *this;
}
/**
* Set connection-pool, lookup, and request-timeout tuning.
*
* Optional. Any field left unset within the policy falls back to the client
* default for that setting.
*
* @param policy the connection policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& connectionPolicy(ConnectionPolicy policy) {
connectionPolicy_ = std::move(policy);
return *this;
}
/**
* Set the reconnection backoff policy.
*
* Optional. Any field left unset within the policy falls back to the client
* default for that bound.
*
* @param policy the backoff policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& backoffPolicy(BackoffPolicy policy) {
backoffPolicy_ = std::move(policy);
return *this;
}
/**
* Set the transport security (TLS) policy.
*
* Optional. When unset, TLS is disabled and connections are plaintext.
*
* @param policy the TLS policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& tlsPolicy(TlsPolicy policy) {
tlsPolicy_ = std::move(policy);
return *this;
}
/**
* Set client-wide transaction settings (spec §9).
*
* Optional. Transactions are always available; this only tunes the default
* transaction timeout. When unset, the client applies its built-in default.
*
* @param policy the transaction policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& transactionPolicy(TransactionPolicy policy) {
transactionPolicy_ = std::move(policy);
return *this;
}
/**
* Set IO- and listener-thread pool sizing.
*
* Optional. Any field left unset within the policy falls back to the client
* default of a single thread. (The advertised `listenerName` for broker
* discovery now lives on `ConnectionPolicy`.)
*
* @param policy the thread policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& threadPolicy(ThreadPolicy policy) {
threadPolicy_ = std::move(policy);
return *this;
}
/**
* Set the client-wide memory budget for pending (in-flight) messages.
*
* Optional. When unset, the client applies its built-in default limit.
*
* @param policy the memory policy to apply
* @return `*this`, for call chaining
*/
PulsarClientBuilder& memoryPolicy(MemoryPolicy policy) {
memoryPolicy_ = std::move(policy);
return *this;
}
/**
* Build the client from the configured settings.
*
* @return the new PulsarClient on success, or an Error describing the
* configuration problem (for example, a missing or invalid
* serviceUrl())
*/
Expected<PulsarClient> build();
private:
std::string serviceUrl_;
AuthenticationPtr authentication_;
ConnectionPolicy connectionPolicy_;
ThreadPolicy threadPolicy_;
MemoryPolicy memoryPolicy_;
BackoffPolicy backoffPolicy_;
TlsPolicy tlsPolicy_;
TransactionPolicy transactionPolicy_;
};
inline PulsarClientBuilder PulsarClient::builder() { return PulsarClientBuilder{}; }
} // namespace pulsar::st