blob: 0795fc6e0206703343a0f40030f1062a6e9d74d1 [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.
use bytes::Bytes;
use futures_util::stream::StreamExt;
use iggy::prelude::*;
use iggy_common::wire_conversions::user_headers_to_wire;
// The compression and decompression utilities are shared between the producer and consumer compression examples.
// Hence, we import them here.
use iggy_examples::shared::codec::{Codec, NUM_MESSAGES, STREAM_NAME, TOPIC_NAME};
pub const CONSUMER_NAME: &str = "example-consumer";
#[tokio::main]
async fn main() -> Result<(), IggyError> {
// Setup a client to connect to the iggy-server via TCP.
let client = IggyClientBuilder::new().with_tcp().build()?;
client.connect().await?;
// Login using default credentials.
client
.login_user(DEFAULT_ROOT_USERNAME, DEFAULT_ROOT_PASSWORD)
.await?;
// Configure a consumer, to read the compressed messages that were previously written to the server (using ../producer/main.rs).
let mut consumer = client
.consumer(CONSUMER_NAME, STREAM_NAME, TOPIC_NAME, 0)?
.build();
consumer.init().await?;
// Prevent the consumer from indefinitely awaiting new messages.
// Since the producer wrote 1000 messages to the server, break if all of them were read (consumed_messages == NUM_MESSAGES).
let mut consumed_messages = 0;
while let Some(message) = consumer.next().await {
let mut received_message = message.expect("Message was not received from server.");
handle_payload_compression(&mut received_message)?;
consumed_messages += 1;
println!(
"Message payload was decompressed and reads: {:?}",
received_message.message.payload
);
if consumed_messages == NUM_MESSAGES {
return Ok(());
}
}
Ok(())
}
// A helper function to decompress a ReceivedMessage's payload.
fn handle_payload_compression(msg: &mut ReceivedMessage) -> Result<(), IggyError> {
// Check if the message payload is compressed by inspecting the user-header.
if let Ok(Some(algorithm)) = msg.message.get_user_header(&Codec::header_key()) {
// setup the codec with the compression algorithm defined in the user-header (value)
let codec = Codec::from_header_value(&algorithm);
// decompress the payload and update the payload length
let decompressed_payload = codec.decompress(&msg.message.payload);
msg.message.payload = Bytes::from(decompressed_payload);
msg.message.header.payload_length = msg.message.payload.len() as u32;
// remove the compression header since payload is now decompressed
if let Ok(Some(mut headers_map)) = msg.message.user_headers_map() {
headers_map.remove(&Codec::header_key());
if headers_map.is_empty() {
msg.message.header.user_headers_length = 0;
msg.message.user_headers = None;
} else {
let wire = user_headers_to_wire(&headers_map);
msg.message.header.user_headers_length = wire.as_bytes().len() as u32;
msg.message.user_headers = Some(wire.into_bytes());
};
}
}
Ok(())
}