From 0f40319b59f3a60d0cd91155a1d9899c632e6c98 Mon Sep 17 00:00:00 2001 From: Andrei <92177534+andrei-21@users.noreply.github.com> Date: Fri, 23 Feb 2024 18:10:06 +0000 Subject: [PATCH] Add pigeon (#94) --- Cargo.toml | 3 +- graphql/schemas/operations.graphql | 7 ++ graphql/schemas/schema_wallet_read.graphql | 117 +++++++++++++++++++++ graphql/src/lib.rs | 4 +- graphql/src/schema.rs | 8 ++ pigeon/Cargo.toml | 14 +++ pigeon/src/lib.rs | 20 ++++ pigeon/tests/integration_tests.rs | 56 ++++++++++ 8 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 pigeon/Cargo.toml create mode 100644 pigeon/src/lib.rs create mode 100644 pigeon/tests/integration_tests.rs diff --git a/Cargo.toml b/Cargo.toml index 9ce618d..e2e43c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,9 @@ members = [ "crow", "graphql", "honey-badger", - "squirrel", "parrot", + "pigeon", + "squirrel", ] resolver = "2" diff --git a/graphql/schemas/operations.graphql b/graphql/schemas/operations.graphql index 4af7211..303063e 100644 --- a/graphql/schemas/operations.graphql +++ b/graphql/schemas/operations.graphql @@ -157,3 +157,10 @@ mutation ReportPaymentTelemetry($telemetryId: String!, $events: PaymentTelemetry payFailed } } + +mutation AssignLightningAddress { + assign_lightning_address { + address + assignedAt + } +} diff --git a/graphql/schemas/schema_wallet_read.graphql b/graphql/schemas/schema_wallet_read.graphql index 60e8059..4d81fdf 100644 --- a/graphql/schemas/schema_wallet_read.graphql +++ b/graphql/schemas/schema_wallet_read.graphql @@ -1,3 +1,6 @@ +# Updated at 2024-02-23_11:14:36 +# Hasura Role: WALLET_READ + schema { query: query_root mutation: mutation_root @@ -65,6 +68,11 @@ type GetTermsConditionsStatusResponse { version: Int! } +type LightningAddressResponse { + address: String! + assignedAt: DateTime! +} + type MigrationBalanceResponse { balanceAmountSat: BigInteger! } @@ -584,6 +592,59 @@ enum cursor_ordering { DESC } +""" +columns and relationships of "lightning_address" +""" +type lightning_address { + address: String! + assignedAt: timestamptz! +} + +""" +Boolean expression to filter rows from the table "lightning_address". All fields are combined with a logical 'AND'. +""" +input lightning_address_bool_exp { + _and: [lightning_address_bool_exp!] + _not: lightning_address_bool_exp + _or: [lightning_address_bool_exp!] + address: String_comparison_exp + assignedAt: timestamptz_comparison_exp +} + +"""Ordering options when selecting data from "lightning_address".""" +input lightning_address_order_by { + address: order_by + assignedAt: order_by +} + +""" +select columns of table "lightning_address" +""" +enum lightning_address_select_column { + """column name""" + address + + """column name""" + assignedAt +} + +""" +Streaming cursor of the table "lightning_address" +""" +input lightning_address_stream_cursor_input { + """Stream column input with initial value""" + initial_value: lightning_address_stream_cursor_value_input! + + """cursor ordering""" + ordering: cursor_ordering +} + +"""Initial value of the column from where the streaming should start""" +input lightning_address_stream_cursor_value_input { + address: String + assignedAt: timestamptz +} + """mutation root""" type mutation_root { """ @@ -612,6 +673,7 @@ type mutation_root { ): accepted_terms_conditions accept_terms_conditions(args: ServiceProviderInputInput): AcceptTermsResponse accept_wallet_acl_by_pk(pk_columns: AcceptWalletPkRequestInput!): WalletAcl + assign_lightning_address: LightningAddressResponse create_backup(encryptedBackup: String!, schemaName: String!, schemaVersion: String!): CreateBackupResponse hide_topup(id: String!): String @@ -762,6 +824,27 @@ type query_root { currencyCode: String! ): currency get_terms_conditions_status(args: GetTermsConditionsStatusInputInput): GetTermsConditionsStatusResponse + + """ + fetch data from the table: "lightning_address" + """ + lightning_address( + """distinct select on columns""" + distinct_on: [lightning_address_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [lightning_address_order_by!] + + """filter the rows returned""" + where: lightning_address_bool_exp + ): [lightning_address!]! + lightning_address_service_version: String migration_balance(nodePubKey: String): MigrationBalanceResponse notification_service_version: String payment_service_version: String @@ -966,6 +1049,40 @@ type subscription_root { where: currency_bool_exp ): [currency!]! + """ + fetch data from the table: "lightning_address" + """ + lightning_address( + """distinct select on columns""" + distinct_on: [lightning_address_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [lightning_address_order_by!] + + """filter the rows returned""" + where: lightning_address_bool_exp + ): [lightning_address!]! + + """ + fetch data from the table in a streaming manner: "lightning_address" + """ + lightning_address_stream( + """maximum number of rows returned in a single batch""" + batch_size: Int! + + """cursor to stream the results returned by the query""" + cursor: [lightning_address_stream_cursor_input]! + + """filter the rows returned""" + where: lightning_address_bool_exp + ): [lightning_address!]! + """ fetch data from the table: "token" """ diff --git a/graphql/src/lib.rs b/graphql/src/lib.rs index 1c86b21..41e2580 100644 --- a/graphql/src/lib.rs +++ b/graphql/src/lib.rs @@ -59,7 +59,7 @@ pub fn build_async_client(access_token: Option<&str>) -> Result pub fn post_blocking( client: &Client, - backend_url: &String, + backend_url: &str, variables: Query::Variables, ) -> Result { let response = match post_graphql_blocking::(client, backend_url, variables) { @@ -83,7 +83,7 @@ pub fn post_blocking( pub async fn post( client: &reqwest::Client, - backend_url: &String, + backend_url: &str, variables: Query::Variables, ) -> Result { let response = match post_graphql::(client, backend_url, variables).await { diff --git a/graphql/src/schema.rs b/graphql/src/schema.rs index 88b7472..577c451 100644 --- a/graphql/src/schema.rs +++ b/graphql/src/schema.rs @@ -173,3 +173,11 @@ pub struct RecoverBackup; response_derives = "Debug" )] pub struct ReportPaymentTelemetry; + +#[derive(GraphQLQuery)] +#[graphql( + schema_path = "schemas/schema_wallet_read.graphql", + query_path = "schemas/operations.graphql", + response_derives = "Debug" +)] +pub struct AssignLightningAddress; diff --git a/pigeon/Cargo.toml b/pigeon/Cargo.toml new file mode 100644 index 0000000..03659cc --- /dev/null +++ b/pigeon/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "pigeon" +version = "0.1.0" +edition = "2021" + +[dependencies] +graphql = { path = "../graphql" } +honey-badger = { path = "../honey-badger" } + +[dev-dependencies] +bitcoin = { version = "0.30.1" } +ctor = "0.2.0" +simplelog = { version ="0.12.0", features = ["test"] } +tokio = { version = "1.32.0" } diff --git a/pigeon/src/lib.rs b/pigeon/src/lib.rs new file mode 100644 index 0000000..ef3642a --- /dev/null +++ b/pigeon/src/lib.rs @@ -0,0 +1,20 @@ +use graphql::perro::OptionToError; +use graphql::schema::{assign_lightning_address, AssignLightningAddress}; +use graphql::{build_async_client, post}; +use honey_badger::asynchronous::Auth; + +pub async fn assign_lightning_address(backend_url: &str, auth: &Auth) -> graphql::Result { + let token = auth.query_token().await?; + let client = build_async_client(Some(&token))?; + let data = post::( + &client, + backend_url, + assign_lightning_address::Variables {}, + ) + .await?; + let address = data + .assign_lightning_address + .ok_or_permanent_failure("Unexpected backend response: empty")? + .address; + Ok(address) +} diff --git a/pigeon/tests/integration_tests.rs b/pigeon/tests/integration_tests.rs new file mode 100644 index 0000000..3602839 --- /dev/null +++ b/pigeon/tests/integration_tests.rs @@ -0,0 +1,56 @@ +use bitcoin::Network; +use honey_badger::asynchronous::Auth; +use honey_badger::secrets::{derive_keys, generate_keypair, generate_mnemonic}; +use honey_badger::AuthLevel; +use pigeon::assign_lightning_address; +use simplelog::TestLogger; +use std::env; +use std::sync::Once; + +static INIT_LOGGER_ONCE: Once = Once::new(); + +#[cfg(test)] +#[ctor::ctor] +fn init() { + INIT_LOGGER_ONCE.call_once(|| { + TestLogger::init(simplelog::LevelFilter::Info, simplelog::Config::default()).unwrap(); + }); +} + +#[tokio::test] +async fn test_assigning_lightning_address() { + let (backend_url, auth) = build_client(); + let address = assign_lightning_address(&backend_url, &auth).await.unwrap(); + println!("Assigned address is: {address}"); + assert!(!address.is_empty()); + let address_from_another_call = assign_lightning_address(&backend_url, &auth).await.unwrap(); + assert_eq!(address, address_from_another_call); + + let (backend_url, another_auth) = build_client(); + let address_for_another_user = assign_lightning_address(&backend_url, &another_auth) + .await + .unwrap(); + assert_ne!(address, address_for_another_user); +} + +fn build_client() -> (String, Auth) { + println!("Generating keys ..."); + let mnemonic = generate_mnemonic(); + println!("mnemonic: {mnemonic:?}"); + let wallet_keys = derive_keys(Network::Testnet, mnemonic).wallet_keypair; + let auth_keys = generate_keypair(); + + let auth = Auth::new( + get_backend_url(), + AuthLevel::Pseudonymous, + wallet_keys, + auth_keys, + ) + .unwrap(); + + (get_backend_url(), auth) +} + +fn get_backend_url() -> String { + env::var("GRAPHQL_API_URL").expect("GRAPHQL_API_URL environment variable is not set") +}