blob: 9a7ec5229af83b9e2d5869e7d29c47d9b6b57524 [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.
//
// TCP/TLS Consumer Example
//
// Demonstrates consuming messages over a TLS-encrypted TCP connection
// using custom certificates from core/certs/.
//
// Prerequisites:
// Start the Iggy server with TLS enabled:
// IGGY_TCP_TLS_ENABLED=true \
// IGGY_TCP_TLS_CERT_FILE=core/certs/iggy_cert.pem \
// IGGY_TCP_TLS_KEY_FILE=core/certs/iggy_key.pem \
// cargo r --bin iggy-server
//
// Run this example (from examples/node/):
// DEBUG=iggy:* npx tsx src/tcp-tls/consumer.ts
import { readFileSync } from 'node:fs';
import { Client, PollingStrategy, Consumer } from 'apache-iggy';
import { log, PARTITION_ID, STREAM_ID, TOPIC_ID } from '../utils';
const BATCHES_LIMIT = 5;
const MESSAGES_PER_BATCH = 10;
async function consumeMessages(
client: Client,
streamId: number | string,
topicId: number | string,
partitionId: number,
) {
const interval = 500;
log(
'Messages will be consumed from stream: %s, topic: %s, partition: %d with interval %d ms.',
streamId,
topicId,
partitionId,
interval,
);
let offset = 0;
let consumedBatches = 0;
while (consumedBatches < BATCHES_LIMIT) {
try {
log('Polling for messages...');
const polledMessages = await client.message.poll({
streamId,
topicId,
consumer: Consumer.Single,
partitionId,
pollingStrategy: PollingStrategy.Offset(BigInt(offset)),
count: MESSAGES_PER_BATCH,
autocommit: false,
});
if (!polledMessages || polledMessages.messages.length === 0) {
log('No messages found.');
consumedBatches++;
await new Promise(resolve => setTimeout(resolve, interval));
continue;
}
offset += polledMessages.messages.length;
for (const message of polledMessages.messages) {
const payload = message.payload.toString('utf8');
const { offset: msgOffset, timestamp } = message.headers;
log('Received message: %s (offset: %d, timestamp: %d)', payload, msgOffset, timestamp);
}
consumedBatches++;
log('Consumed %d message(s) in batch %d.', polledMessages.messages.length, consumedBatches);
await new Promise(resolve => setTimeout(resolve, interval));
} catch (error) {
log('Error consuming messages: %o', error);
throw error;
}
}
log('Consumed %d batches of messages, exiting.', consumedBatches);
}
async function main() {
// Configure the client with TLS transport.
// transport: 'TLS' activates TLS on the TCP connection
// ca: readFileSync(...) provides the CA certificate to verify the server cert
// host: 'localhost' must match the server certificate CN/SAN
const client = new Client({
transport: 'TLS',
options: {
port: 8090,
host: 'localhost',
ca: readFileSync('../../core/certs/iggy_ca_cert.pem'),
},
credentials: { username: 'iggy', password: 'iggy' },
});
try {
log('TLS consumer has started, selected transport: TLS');
log('Connecting to Iggy server over TLS...');
await consumeMessages(client, STREAM_ID, TOPIC_ID, PARTITION_ID);
} catch (error) {
log('Error in main: %o', error);
process.exitCode = 1;
} finally {
await client.destroy();
log('Disconnected from server.');
}
}
process.on('unhandledRejection', (reason, promise) => {
log('Unhandled Rejection at: %o, reason: %o', promise, reason);
process.exitCode = 1;
});
main();