kafrust 0.2.2

A pure Rust Kafka client with no librdkafka or C toolchain dependency.
Documentation
mod common;

use kafrust::{
    AclBinding, AclFilter, AclOperation, AclPatternType, AclPermissionType, AclResourceType,
    AdminClient, ClientConfig, Error,
};

#[tokio::main]
async fn main() -> kafrust::Result<()> {
    let bootstrap_servers = common::bootstrap_servers_from_env();
    let topic =
        std::env::var("KAFRUST_ACL_TOPIC").unwrap_or_else(|_| "kafrust-acl-smoke".to_owned());
    let principal =
        std::env::var("KAFRUST_ACL_PRINCIPAL").unwrap_or_else(|_| "User:ANONYMOUS".to_owned());
    let config = common::apply_security(
        ClientConfig::new(bootstrap_servers).client_id("kafrust-acl-example"),
    )?;
    let admin = AdminClient::new(config);
    let binding = AclBinding::new(
        AclResourceType::Topic,
        &topic,
        AclPatternType::Literal,
        &principal,
        "*",
        AclOperation::Read,
        AclPermissionType::Allow,
    );

    let created = admin.create_acls(std::slice::from_ref(&binding)).await?;
    if !created.is_success() {
        return Err(Error::Broker {
            code: created
                .results()
                .first()
                .map(|result| result.error_code())
                .unwrap_or(-1),
            context: format!("create ACL for topic {topic}"),
        });
    }
    println!("created ACL for {principal} on topic {topic}");

    let filter = AclFilter::any()
        .resource_type(AclResourceType::Topic)
        .resource_name(&topic)
        .pattern_type(AclPatternType::Literal)
        .principal(&principal)
        .host("*")
        .operation(AclOperation::Read)
        .permission_type(AclPermissionType::Allow);
    let described = admin.describe_acls(&filter).await?;
    if !described.is_success()
        || !described
            .bindings()
            .iter()
            .any(|candidate| candidate == &binding)
    {
        return Err(Error::Broker {
            code: described.error_code(),
            context: format!("describe ACL for topic {topic}"),
        });
    }
    println!("described ACL for {principal} on topic {topic}");

    let deleted = admin.delete_acls(&[filter]).await?;
    if !deleted.is_success() {
        return Err(Error::Broker {
            code: deleted
                .filter_results()
                .first()
                .map(|result| result.error_code())
                .unwrap_or(-1),
            context: format!("delete ACL for topic {topic}"),
        });
    }
    println!("deleted ACL for {principal} on topic {topic}");

    Ok(())
}