UNPKG

@hashgraph/hedera-cli

Version:

CLI tool to manage and setup developer environments for Hedera Hashgraph.

248 lines (226 loc) 7.59 kB
import stateUtils from '../../utils/state'; import telemetryUtils from '../../utils/telemetry'; import { Logger } from '../../utils/logger'; import stateController from '../../state/stateController'; import dynamicVariablesUtils from '../../utils/dynamicVariables'; import { TopicMessageSubmitTransaction, PrivateKey } from '@hashgraph/sdk'; import api from '../../api'; import type { Command, Filter } from '../../../types'; const logger = Logger.getInstance(); interface SubmitMessageOptions { message: string; topicId: string; args: string[]; } interface FindMessageOptions { sequenceNumber: string; sequenceNumberGt: string; sequenceNumberGte: string; sequenceNumberLt: string; sequenceNumberLte: string; sequenceNumberEq: string; sequenceNumberNe: string; topicId: string; } /** * Format the filters based on the options provided. * @param filters The filters to populate. * @param options The options provided. */ function formatFilters(filters: Filter[], options: FindMessageOptions) { if (options.sequenceNumberGt) { filters.push({ field: 'sequencenumber', operation: 'gt', value: Number(options.sequenceNumberGt), }); } if (options.sequenceNumberLt) { filters.push({ field: 'sequencenumber', operation: 'lt', value: Number(options.sequenceNumberLt), }); } if (options.sequenceNumberGte) { filters.push({ field: 'sequencenumber', operation: 'gte', value: Number(options.sequenceNumberGte), }); } if (options.sequenceNumberLte) { filters.push({ field: 'sequencenumber', operation: 'lte', value: Number(options.sequenceNumberLte), }); } if (options.sequenceNumberEq) { filters.push({ field: 'sequencenumber', operation: 'eq', value: Number(options.sequenceNumberEq), }); } if (options.sequenceNumberNe) { filters.push({ field: 'sequencenumber', operation: 'ne', value: Number(options.sequenceNumberNe), }); } } export default (program: any) => { const message = program.command('message'); message .command('submit') .hook('preAction', async (thisCommand: Command) => { const command = [ thisCommand.parent.action().name(), ...thisCommand.parent.args, ]; if (stateUtils.isTelemetryEnabled()) { await telemetryUtils.recordCommand(command.join(' ')); } }) .description('Submit a message to a topic') .requiredOption('-m, --message <message>', 'Submit a message to the topic') .requiredOption('-t, --topic-id <topicId>', 'The topic ID') .option( '--args <args>', 'Store arguments for scripts', (value: string, previous: string) => previous ? previous.concat(value) : [value], [], ) .action(async (options: SubmitMessageOptions) => { options = dynamicVariablesUtils.replaceOptions(options); // allow dynamic vars for topic-id logger.verbose(`Submitting message to topic: ${options.topicId}`); const client = stateUtils.getHederaClient(); let sequenceNumber; try { const submitMessageTx = await new TopicMessageSubmitTransaction({ topicId: options.topicId, message: options.message, }).freezeWith(client); // Signing if submit key is set (if it exists in the state - otherwise skip this step) const topics = stateController.get('topics'); if (topics[options.topicId] && topics[options.topicId].submitKey) { const submitKey = PrivateKey.fromStringDer( topics[options.topicId].submitKey, ); submitMessageTx.sign(submitKey); } const topicMessageTxResponse = await submitMessageTx.execute(client); const receipt = await topicMessageTxResponse.getReceipt(client); sequenceNumber = receipt.topicSequenceNumber; } catch (error) { logger.error('Error sending message to topic', error as object); client.close(); process.exit(1); } logger.log(`Message submitted with sequence number: ${sequenceNumber}`); client.close(); dynamicVariablesUtils.storeArgs( options.args, dynamicVariablesUtils.commandActions.topic.messageSubmit.action, { sequenceNumber: sequenceNumber.toString() }, ); }); message .command('find') .hook('preAction', async (thisCommand: Command) => { const command = [ thisCommand.parent.action().name(), ...thisCommand.parent.args, ]; if (stateUtils.isTelemetryEnabled()) { await telemetryUtils.recordCommand(command.join(' ')); } }) .description('Find a message by sequence number') .option('-s, --sequence-number <sequenceNumber>', 'The sequence number') .option('-t, --topic-id <topicId>', 'The topic ID') .option( '--sequence-number-gt <sequenceNumberGt>', 'The sequence number greater than', ) .option( '--sequence-number-lt <sequenceNumberLt>', 'The sequence number less than', ) .option( '--sequence-number-gte <sequenceNumberGte>', 'The sequence number greater than or equal to', ) .option( '--sequence-number-lte <sequenceNumberLte>', 'The sequence number less than or equal to', ) .option( '--sequence-number-eq <sequenceNumberEq>', 'The sequence number equal to', ) .option( '--sequence-number-ne <sequenceNumberNe>', 'The sequence number not equal to', ) .action(async (options: FindMessageOptions) => { options = dynamicVariablesUtils.replaceOptions(options); // allow dynamic vars for topic-id and sequence-number logger.verbose(`Finding message for topic: ${options.topicId}`); // Define the keys of options we are interested in const sequenceNumberOptions: string[] = [ 'sequenceNumberGt', 'sequenceNumberLt', 'sequenceNumberGte', 'sequenceNumberLte', 'sequenceNumberEq', 'sequenceNumberNe', ]; // Check if any of the sequence number options is set const isAnyOptionSet = sequenceNumberOptions.some( (option: string) => options[option as keyof FindMessageOptions], ); if (!isAnyOptionSet && !options.sequenceNumber) { logger.error( 'Please provide a sequence number or a sequence number filter', ); return; } if (!isAnyOptionSet) { // If no sequence number options are set, proceed with the original logic const response = await api.topic.findMessage( options.topicId, Number(options.sequenceNumber), ); logger.log( `Message found: "${Buffer.from( response.data.message, 'base64', ).toString('ascii')}"`, ); return; } // Assuming options can include multiple filters let filters: Filter[] = []; // Populate this based on the options provided formatFilters(filters, options); // Call the new API function const response = await api.topic.findMessagesWithFilters( options.topicId, filters, ); if (response.data.messages.length === 0) { logger.log('No messages found'); return; } response.data.messages.forEach((el) => { logger.log( `Message ${el.sequence_number}: "${Buffer.from( el.message, 'base64', ).toString('ascii')}"`, ); }); }); };