From b1935f36542ed805209c1ce684aa12fc1de8af7a Mon Sep 17 00:00:00 2001 From: Thoralf-M Date: Tue, 25 May 2021 18:20:40 +0200 Subject: [PATCH 1/5] nodejs add getMessageId --- .changes/getMessageId.md | 5 +++++ bindings/nodejs/README.md | 10 ++++++++++ bindings/nodejs/examples/10_mqtt.js | 11 ++++++++++- bindings/nodejs/lib/index.d.ts | 1 + bindings/nodejs/native/src/classes/client/mod.rs | 16 ++++++++++++++-- 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 .changes/getMessageId.md diff --git a/.changes/getMessageId.md b/.changes/getMessageId.md new file mode 100644 index 000000000..659baf4bf --- /dev/null +++ b/.changes/getMessageId.md @@ -0,0 +1,5 @@ +--- +"nodejs-binding": minor +--- + +Added getMessageId function. diff --git a/bindings/nodejs/README.md b/bindings/nodejs/README.md index 31c09285e..7850ad992 100644 --- a/bindings/nodejs/README.md +++ b/bindings/nodejs/README.md @@ -323,6 +323,16 @@ Checks if a given address is valid. **Returns** A boolean. +#### getMessageId(message: string): boolean + +Returns the message id from a message. + +| Param | Type | Description | +| ------- | ------------------- | -------------- | +| message | string | The message id | + +**Returns** the message id. + #### retry(messageId: string): Promise Retries (promotes or reattaches) the message associated with the given id. diff --git a/bindings/nodejs/examples/10_mqtt.js b/bindings/nodejs/examples/10_mqtt.js index cb0290e09..ce67cf9f3 100644 --- a/bindings/nodejs/examples/10_mqtt.js +++ b/bindings/nodejs/examples/10_mqtt.js @@ -8,9 +8,18 @@ async function run() { .node('https://api.hornet-0.testnet.chrysalis2.com') .build(); - client.subscriber().topics(['milestones/confirmed', 'messages']).subscribe((err, data) => { + client.subscriber().topics(['messages']).subscribe((err, data) => { + console.log(client.getMessageId(data.payload)); console.log(data); }) + + const message = await client.message() + .index('IOTA.RS BINDING - NODE.JS') + .data('some utf based data') + .submit(); + console.log(message.message); + console.log(client.getMessageId(JSON.stringify(message.message))); + console.log(message); } run() diff --git a/bindings/nodejs/lib/index.d.ts b/bindings/nodejs/lib/index.d.ts index 62edc6841..f7f813c8d 100644 --- a/bindings/nodejs/lib/index.d.ts +++ b/bindings/nodejs/lib/index.d.ts @@ -116,6 +116,7 @@ export declare class Client { bech32ToHex(address: string): string hexToBech32(address: string, bech32_hrp?: string): Promise isAddressValid(address: string): boolean + getMessageId(message: string): string getMilestone(index: number): Promise getMilestoneUtxoChanges(index: number): Promise getReceipts(): Promise diff --git a/bindings/nodejs/native/src/classes/client/mod.rs b/bindings/nodejs/native/src/classes/client/mod.rs index c152de113..d6cab27cc 100644 --- a/bindings/nodejs/native/src/classes/client/mod.rs +++ b/bindings/nodejs/native/src/classes/client/mod.rs @@ -3,13 +3,14 @@ #![allow(clippy::unnecessary_wraps)] use iota_client::{ - bee_message::prelude::{Address, MessageId, TransactionId, UtxoInput}, + bee_message::prelude::{Address, Message, MessageId, TransactionId, UtxoInput}, + bee_rest_api::types::dtos::MessageDto as BeeMessageDto, AddressOutputsOptions, Client, OutputType, Seed, }; use neon::prelude::*; use serde::Deserialize; -use std::str::FromStr; +use std::{convert::TryFrom, str::FromStr}; mod builder; pub use builder::*; @@ -665,5 +666,16 @@ declare_types! { let is_valid = Client::is_address_valid(address.as_str()); Ok(cx.boolean(is_valid).upcast()) } + + method getMessageId(mut cx) { + let message_string = cx.argument::(0)?.value(); + // Try BeeMessageDto and if it fails Message + let message = match serde_json::from_str::(&message_string){ + Ok(message_dto) => Message::try_from(&message_dto).expect("invalid message"), + Err(_) => serde_json::from_str::(&message_string).expect("invalid message"), + }; + let message_id = message.id().0.to_string(); + Ok(cx.string(message_id).upcast()) + } } } From d70d69252c6cb27947bc8740a239a4dc361f3fad Mon Sep 17 00:00:00 2001 From: Thoralf-M Date: Tue, 25 May 2021 18:23:32 +0200 Subject: [PATCH 2/5] update example --- bindings/nodejs/examples/10_mqtt.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/bindings/nodejs/examples/10_mqtt.js b/bindings/nodejs/examples/10_mqtt.js index ce67cf9f3..091d29783 100644 --- a/bindings/nodejs/examples/10_mqtt.js +++ b/bindings/nodejs/examples/10_mqtt.js @@ -8,18 +8,10 @@ async function run() { .node('https://api.hornet-0.testnet.chrysalis2.com') .build(); - client.subscriber().topics(['messages']).subscribe((err, data) => { - console.log(client.getMessageId(data.payload)); + client.subscriber().topics(['milestones/confirmed', 'messages']).subscribe((err, data) => { console.log(data); + // To get the message id `client.getMessageId(data.payload)` can be used }) - - const message = await client.message() - .index('IOTA.RS BINDING - NODE.JS') - .data('some utf based data') - .submit(); - console.log(message.message); - console.log(client.getMessageId(JSON.stringify(message.message))); - console.log(message); } run() From 57867e2c2161f21e43b4462ea99f8ee4ac4d8e48 Mon Sep 17 00:00:00 2001 From: bingyanglin Date: Wed, 26 May 2021 19:15:55 +0800 Subject: [PATCH 3/5] Add python binding method and example --- bindings/python/README.md | 66 +++++++++++-------- bindings/python/examples/10_mqtt.py | 62 +++++++++++++++++ .../native/src/client/high_level_api.rs | 22 ++++++- 3 files changed, 120 insertions(+), 30 deletions(-) create mode 100644 bindings/python/examples/10_mqtt.py diff --git a/bindings/python/README.md b/bindings/python/README.md index 5e0de16c4..ab99fe9c7 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -183,24 +183,24 @@ Also for all the optional values, the default values are the same as the ones in Creates a new instance of the Client. -| Param | Type | Default | Description | -| ------------------------------------ | -------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [network] | str | undefined | The network | -| [node] | str | undefined | A node URL | -| [primary_node_jwt_name_password] | list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | -| [primary_pow_node_jwt_name_password] | list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | -| [nodes_name_password] | list[]list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | -| [node_sync_interval] | int | undefined | The interval for the node syncing process | -| [node_sync_disabled] | bool | undefined | Disables the node syncing process. Every node will be considered healthy and ready to use | -| [node_pool_urls] | str | undefined | An array of node pool URLs | -| [quorum] | bool | false | Bool to define if quorum should be used | -| [quorum_size] | int | 3 | An int that defines how many nodes should be used for quorum | -| [quorum_threshold] | int | 66 | Define the % of nodes that need to return the same response to accept it | -| [request_timeout] | int | undefined | Sets the default HTTP request timeout | -| [api_timeout] | dict | undefined | The API to set the request timeout. Key: 'GetHealth', 'GetInfo', 'GetPeers', 'GetTips', 'PostMessage', 'GetOutput', 'GetMilestone' Value: timeout in milliseconds | -| [local_pow] | bool | undefined | Flag determining if PoW should be done locally or remotely | -| [tips_interval] | int | undefined | Time between requests for new tips during PoW | -| [mqtt_broker_options] | [BrokerOptions](#brokeroptions) | undefined | Sets the options for the MQTT connection with the node | +| Param | Type | Default | Description | +| ------------------------------------ | -------------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [network] | str | undefined | The network | +| [node] | str | undefined | A node URL | +| [primary_node_jwt_name_password] | list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | +| [primary_pow_node_jwt_name_password] | list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | +| [nodes_name_password] | list[]list[str] | undefined | An array of array with node URLs and optional JWT and basic auth name and password (length 1 is only the url, length 2 is url with JWT, length 3 is url with basic auth name and password and length 4 is url with JWT and basic auth name and password) | +| [node_sync_interval] | int | undefined | The interval for the node syncing process | +| [node_sync_disabled] | bool | undefined | Disables the node syncing process. Every node will be considered healthy and ready to use | +| [node_pool_urls] | str | undefined | An array of node pool URLs | +| [quorum] | bool | false | Bool to define if quorum should be used | +| [quorum_size] | int | 3 | An int that defines how many nodes should be used for quorum | +| [quorum_threshold] | int | 66 | Define the % of nodes that need to return the same response to accept it | +| [request_timeout] | int | undefined | Sets the default HTTP request timeout | +| [api_timeout] | dict | undefined | The API to set the request timeout. Key: 'GetHealth', 'GetInfo', 'GetPeers', 'GetTips', 'PostMessage', 'GetOutput', 'GetMilestone' Value: timeout in milliseconds | +| [local_pow] | bool | undefined | Flag determining if PoW should be done locally or remotely | +| [tips_interval] | int | undefined | Time between requests for new tips during PoW | +| [mqtt_broker_options] | [BrokerOptions](#brokeroptions) | undefined | Sets the options for the MQTT connection with the node | **Returns** The constructed [Client](#client). @@ -328,8 +328,8 @@ Get the treasury amount. Get the included message of a transaction. -| Param | Type | Description | -| ----- | ------------------- | -------------------------- | +| Param | Type | Description | +| ------- | ------------------- | ------------------------- | | [index] | string | The id of the transaction | **Returns** the new [Message](#message). @@ -397,6 +397,16 @@ Gets the children of the given message. **Returns** the list of children strings. +#### get_message_id(payload_str): str + +Get the message id from the payload string. + +| Param | Type | Default | Description | +| ----------- | ---------------- | ---------------------- | ---------------------------------------------- | +| payload_str | str | undefined | The payload string from the mqtt message event | + +**Returns** the list of children strings. + #### get_message_index(index): list[str] Gets the list of message indices from the message_id. @@ -487,9 +497,9 @@ Returns the seed hex encoded. Returns a parsed hex String from bech32. -| Param | Type | Default | Description | -| ------- | ------------------- | ---------------------- | ------------------------- | -| bech32 | string | undefined | The address Bech32 string | +| Param | Type | Default | Description | +| ------ | ------------------- | ---------------------- | ------------------------- | +| bech32 | string | undefined | The address Bech32 string | **Returns** A String @@ -497,10 +507,10 @@ Returns a parsed hex String from bech32. Returns a parsed bech32 String from hex. -| Param | Type | Default | Description | -| ----------- | ------------------- | ---------------------- | ------------------------- | -| bech32 | string | undefined | The address Bech32 string | -| bech32_hrp | string | undefined | The Bech32 hrp string | +| Param | Type | Default | Description | +| ---------- | ------------------- | ---------------------- | ------------------------- | +| bech32 | string | undefined | The address Bech32 string | +| bech32_hrp | string | undefined | The Bech32 hrp string | **Returns** A String @@ -541,7 +551,7 @@ Retries (promotes or reattaches) the message associated with the given id. Function to consolidate all funds from a range of addresses to the address with the lowest index in that range | Param | Type | Description | -| --------------- | ------------------- | -------------------------------------------------------------------- | +| --------------- | ------------------- | --------------------------------------------------------------------- | | [seed] | string | The seed | | [account_index] | int | The account index. | | [start_index] | int | The lowest address index, funds will be consolidated to this address. | diff --git a/bindings/python/examples/10_mqtt.py b/bindings/python/examples/10_mqtt.py new file mode 100644 index 000000000..95e95ae18 --- /dev/null +++ b/bindings/python/examples/10_mqtt.py @@ -0,0 +1,62 @@ +import iota_client +import json +import os +import queue +import time + +# The node mqtt url +node_url = 'https://chrysalis-nodes.iota.org/' + +# The queue to store received events +q = queue.Queue() + +# The MQTT broker options +broker_options = { + 'automatic_disconnect': True, + 'timeout': 30, + 'use_ws': True, + 'port': 443, + 'max_reconnection_attempts': 5, +} + +client = iota_client.Client( + nodes_name_password=[[node_url]], mqtt_broker_options=broker_options) + +# The queue to store received events +q = queue.Queue() + +# The MQTT broker options +broker_options = { + 'automatic_disconnect': True, + 'timeout': 5, + 'use_ws': True, + 'port': 443, + 'max_reconnection_attempts': 5, +} + + +def worker(topics): + """The worker to process the queued events. + """ + received_events = 0 + while received_events < 10: + item = q.get(True) + event = json.loads(item) + print(f'Received Event: {event}') + message_id = client.get_message_id(str(event['payload'])) + print(f'Received message_id: {message_id}') + received_events += 1 + q.task_done() + + +def on_mqtt_event(event): + """Put the received event to queue. + """ + q.put(event) + + +if __name__ == '__main__': + client.subscribe_topics(['messages'], on_mqtt_event) + worker(['messages']) + client.disconnect() + q.queue.clear() diff --git a/bindings/python/native/src/client/high_level_api.rs b/bindings/python/native/src/client/high_level_api.rs index 09c05341f..5253cd376 100644 --- a/bindings/python/native/src/client/high_level_api.rs +++ b/bindings/python/native/src/client/high_level_api.rs @@ -7,13 +7,15 @@ use crate::client::{ }; use iota_client::{ bee_message::prelude::{ - MessageId as RustMessageId, TransactionId as RustTransactionId, UtxoInput as RustUtxoInput, + Message as RustMessage, MessageId as RustMessageId, TransactionId as RustTransactionId, + UtxoInput as RustUtxoInput, }, + bee_rest_api::types::dtos::MessageDto as BeeMessageDto, Client as RustClient, Seed as RustSeed, }; use pyo3::{exceptions, prelude::*}; use std::{ - convert::{Into, TryInto}, + convert::{Into, TryFrom, TryInto}, str::FromStr, }; @@ -163,6 +165,22 @@ impl Client { })?; Ok(children.iter().map(|child| hex::encode(child.as_ref())).collect()) } + /// Get the message id from the payload string. + /// + /// Args: + /// payload_str (str): The identifier of message. + /// + /// Returns: + /// children ([str]): The returned list of children string. + fn get_message_id(&self, payload_str: &str) -> Result { + // Try BeeMessageDto and if it fails Message + let message = match serde_json::from_str::(&payload_str) { + Ok(message_dto) => RustMessage::try_from(&message_dto).expect("invalid message"), + Err(_) => serde_json::from_str::(&payload_str).expect("invalid message"), + }; + let message_id = message.id().0.to_string(); + Ok(message_id) + } /// Get the list of message indices from the message_id. /// /// Args: From 541ea5b6cf8ce63e129de241d8ff8562a4c1e4ed Mon Sep 17 00:00:00 2001 From: bingyanglin Date: Wed, 26 May 2021 19:24:56 +0800 Subject: [PATCH 4/5] Fix typos --- bindings/python/README.md | 2 +- bindings/python/native/src/client/high_level_api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/README.md b/bindings/python/README.md index ab99fe9c7..a941ad19c 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -405,7 +405,7 @@ Get the message id from the payload string. | ----------- | ---------------- | ---------------------- | ---------------------------------------------- | | payload_str | str | undefined | The payload string from the mqtt message event | -**Returns** the list of children strings. +**Returns** the message_id string. #### get_message_index(index): list[str] diff --git a/bindings/python/native/src/client/high_level_api.rs b/bindings/python/native/src/client/high_level_api.rs index 5253cd376..d3ad2425e 100644 --- a/bindings/python/native/src/client/high_level_api.rs +++ b/bindings/python/native/src/client/high_level_api.rs @@ -171,7 +171,7 @@ impl Client { /// payload_str (str): The identifier of message. /// /// Returns: - /// children ([str]): The returned list of children string. + /// message_id (str): The message id in string. fn get_message_id(&self, payload_str: &str) -> Result { // Try BeeMessageDto and if it fails Message let message = match serde_json::from_str::(&payload_str) { From 6e1f97abf7b3bdae3475a4f75d107e5ed144b3a2 Mon Sep 17 00:00:00 2001 From: bingyanglin Date: Wed, 26 May 2021 19:26:43 +0800 Subject: [PATCH 5/5] Modify description --- bindings/python/README.md | 2 +- bindings/python/native/src/client/high_level_api.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/README.md b/bindings/python/README.md index a941ad19c..7c82e97dc 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -405,7 +405,7 @@ Get the message id from the payload string. | ----------- | ---------------- | ---------------------- | ---------------------------------------------- | | payload_str | str | undefined | The payload string from the mqtt message event | -**Returns** the message_id string. +**Returns** The identifier of message. #### get_message_index(index): list[str] diff --git a/bindings/python/native/src/client/high_level_api.rs b/bindings/python/native/src/client/high_level_api.rs index d3ad2425e..ae7f6b31c 100644 --- a/bindings/python/native/src/client/high_level_api.rs +++ b/bindings/python/native/src/client/high_level_api.rs @@ -171,7 +171,7 @@ impl Client { /// payload_str (str): The identifier of message. /// /// Returns: - /// message_id (str): The message id in string. + /// message_id (str): The identifier of message. fn get_message_id(&self, payload_str: &str) -> Result { // Try BeeMessageDto and if it fails Message let message = match serde_json::from_str::(&payload_str) {