@gear-js/api
Version:
A JavaScript library that provides functionality to connect GEAR Component APIs.
143 lines (140 loc) • 5.72 kB
JavaScript
import { ReplaySubject } from 'rxjs';
import { SendMessageError, SendReplyError } from '../errors/message.errors.js';
import '@polkadot/util';
import '../utils/generate.js';
import { validateValue, validateGasLimit, validateMailboxItem } from '../utils/validate.js';
import { decodeAddress } from '../utils/address.js';
import '@polkadot/util-crypto';
import { encodePayload } from '../utils/create-payload.js';
import { getExtrinsic } from '../utils/getExtrinsic.js';
import { GearTransaction } from './Transaction.js';
class GearMessage extends GearTransaction {
/**
* ## Send Message
* @param message
* @param metaOrHexRegistry Metadata
* @param typeIndexOrTypeName type index in registry or type name
* @returns Submitable result
*/
send({ destination, value, gasLimit, payload, keepAlive }, metaOrHexRegistry, typeIndexOrTypeName) {
validateValue(value, this._api);
validateGasLimit(gasLimit, this._api);
const _payload = encodePayload(payload, metaOrHexRegistry, 'handle', typeIndexOrTypeName);
try {
const txArgs = [destination, _payload, gasLimit, value || 0, keepAlive || true];
this.extrinsic = getExtrinsic(this._api, 'gear', 'sendMessage', txArgs);
return this.extrinsic;
}
catch (error) {
throw new SendMessageError(error.message);
}
}
/**
* Sends reply message
* @param args Message parameters
* @param metaOrHexRegistry Metadata
* @param typeIndexOrTypeName type index in registry or type name
* @returns Submittable result
*/
async sendReply({ value, gasLimit, replyToId, payload, account, keepAlive }, metaOrHexRegistry, typeIndexOrTypeName) {
validateValue(value, this._api);
validateGasLimit(gasLimit, this._api);
if (account) {
await validateMailboxItem(account, replyToId, this._api);
}
const _payload = encodePayload(payload, metaOrHexRegistry, 'reply', typeIndexOrTypeName);
try {
const txArgs = [replyToId, _payload, gasLimit, value || 0, keepAlive || true];
this.extrinsic = getExtrinsic(this._api, 'gear', 'sendReply', txArgs);
return this.extrinsic;
}
catch (_) {
throw new SendReplyError();
}
}
/**
* ## Get event with reply message
* @param msgId - id of sent message
* @param txBlock - number or hash of block where the message was sent
* @returns UserMessageSent event
*/
async getReplyEvent(programId, msgId, txBlock) {
let unsub;
const replyEvent = new Promise((resolve) => {
unsub = this._api.gearEvents.subscribeToGearEvent('UserMessageSent', (event) => {
if (event.data.message.source.eq(programId) === false)
return;
if (msgId === null) {
resolve(event);
}
if (event.data.message.details.isSome && event.data.message.details.unwrap().to.toHex() === msgId) {
resolve(event);
}
}, txBlock);
});
(await unsub)();
return replyEvent;
}
/**
* @deprecated Use `getReplyEvent` instead
*/
listenToReplies(programId, bufferSize = 5) {
let unsub;
const subject = new ReplaySubject(bufferSize);
this._api.gearEvents
.subscribeToGearEvent('UserMessageSent', ({ data }) => {
if (data.message.source.eq(programId)) {
if (data.message.details.isSome) {
data.message.details.unwrap().to.toHex();
{
subject.next([data.message.details.unwrap().to.toHex(), data]);
}
}
}
})
.then((result) => {
unsub = result;
});
return (messageId) => {
return new Promise((resolve) => {
subject.subscribe({
next: ([id, data]) => {
if (id === messageId) {
subject.complete();
unsub();
resolve(data);
}
},
});
});
};
}
/**
* ## Send message to the program and get the reply.
* This method is immutable and doesn't send any extrinsic.
* @param params Message parameters
* @param meta (optional) Program metadata obtained using `ProgramMetadata.from` method.
* @param typeIndexOrTypeName (optional) Index of type in the registry. If not specified the type index from `meta.handle.input` will be used instead.
* @returns Reply info structure
*
* @example
* ```javascript
* const programId = '0x..';
* const origin = '0x...';
* const meta = ProgramMetadata.from('0x...');
* const result = await api.message.calculateReply({
* origin,
* destination: programId,
* payload: { myPayload: [] },
* value: 0
* }, meta);
*
* console.log(result.toJSON());
* console.log('reply payload:', meta.createType(meta.types.handle.output, result.payload).toJSON());
*/
async calculateReply({ payload, origin, destination, value, gasLimit, at }, meta, typeIndexOrTypeName) {
const _payload = encodePayload(payload, meta, 'handle', typeIndexOrTypeName);
return await this._api.rpc.gear.calculateReplyForHandle(decodeAddress(origin), destination, _payload, gasLimit || this._api.blockGasLimit.toBigInt(), value || 0, at || null);
}
}
export { GearMessage };