Skip to content

Commit

Permalink
[#] #122 lens-v2 fetching and saving
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhongFuze committed Mar 21, 2024
1 parent 0dfd9b4 commit e11cfc5
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 32 deletions.
170 changes: 147 additions & 23 deletions src/upstream/lensv2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,12 @@ use crate::tigergraph::vertex::Identity;
use crate::upstream::{
DataFetcher, DataSource, DomainNameSystem, Fetcher, Platform, Target, TargetProcessedList,
};
use crate::util::{
make_client, make_http_client, naive_now, option_naive_datetime_from_utc_string, parse_body,
};
use crate::util::{make_http_client, naive_now, utc_to_naive};
use async_trait::async_trait;
use cynic::QueryFragment;
use cynic::{http::SurfExt, QueryBuilder};
use http::uri::InvalidUri;
use hyper::body;
use hyper::Method;
use hyper::{client::HttpConnector, Body, Client};
use serde::{Deserialize, Serialize};
use tracing::{debug, info, warn};
use hyper::{client::HttpConnector, Client};
use tracing::{trace, warn};
use uuid::Uuid;

mod schema {
cynic::use_schema!("src/upstream/lensv2/schema.graphql");
Expand All @@ -31,7 +25,11 @@ mod schema {
// Query by Handles
#[derive(cynic::QueryVariables, Debug, Default)]
pub struct ProfilesRequestVariables {
#[cynic(skip_serializing_if = "Option::is_none")]
pub handles: Option<Vec<Handle>>,
#[cynic(skip_serializing_if = "Option::is_none")]
#[cynic(rename = "ownedBy")]
pub owned_by: Option<Vec<EvmAddress>>,
}

#[derive(cynic::QueryFragment, Debug)]
Expand All @@ -41,7 +39,7 @@ pub struct ProfilesRequestVariables {
variables = "ProfilesRequestVariables"
)]
pub struct ProfileQueryByHandles {
#[arguments(request: { where: { handles: $handles}} )]
#[arguments(request: { where: { handles: $handles, ownedBy: $owned_by}} )]
pub profiles: PaginatedProfileResult,
}

Expand All @@ -51,7 +49,7 @@ pub struct PaginatedProfileResult {
pub items: Vec<Profile>,
}

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema_path = "src/upstream/lensv2/schema.graphql")]
pub struct Profile {
pub id: ProfileId,
Expand All @@ -62,20 +60,20 @@ pub struct Profile {
pub tx_hash: TxHash,
}

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema_path = "src/upstream/lensv2/schema.graphql")]
pub struct ProfileMetadata {
pub display_name: Option<String>,
}

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema_path = "src/upstream/lensv2/schema.graphql")]
pub struct NetworkAddress {
pub address: EvmAddress,
pub chain_id: ChainId,
}

#[derive(cynic::QueryFragment, Debug)]
#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(schema_path = "src/upstream/lensv2/schema.graphql")]
pub struct HandleInfo {
pub id: TokenId,
Expand All @@ -86,7 +84,7 @@ pub struct HandleInfo {
}

#[derive(cynic::Scalar, Debug, Clone)]
pub struct ChainId(pub String);
pub struct ChainId(pub u32);

#[derive(cynic::Scalar, Debug, Clone)]
pub struct DateTime(pub String);
Expand Down Expand Up @@ -129,12 +127,12 @@ impl Fetcher for LensV2 {

async fn fetch_by_lens_handle(target: &Target) -> Result<TargetProcessedList, Error> {
let target_var = target.identity()?;
let handle = target_var.trim_end_matches(".lens");
let full_handle = format!("lens/{}", handle);
let handle_name = target_var.trim_end_matches(".lens");
let full_handle = format!("lens/{}", handle_name);
let operation = ProfileQueryByHandles::build(ProfilesRequestVariables {
handles: Some(vec![Handle(full_handle)]),
handles: Some(vec![Handle(full_handle.clone())]),
owned_by: None,
});
println!("{}", operation.query);
let response = surf::post(C.upstream.lens_api.url.clone())
.run_graphql(operation)
.await;
Expand All @@ -146,10 +144,136 @@ async fn fetch_by_lens_handle(target: &Target) -> Result<TargetProcessedList, Er
);
return Ok(vec![]);
}
info!("Lens response {:?}", response);
Ok(vec![])
let cli = make_http_client();
let profiles = response
.unwrap()
.data
.map_or(vec![], |data| data.profiles.items);

let mut next_targets: Vec<Target> = Vec::new();
for profile in profiles.iter() {
let t = save_profile(&cli, profile).await?;
if let Some(t) = t {
next_targets.push(t);
}
}

Ok(next_targets)
}

async fn fetch_by_wallet(target: &Target) -> Result<TargetProcessedList, Error> {
todo!()
let target_var = target.identity()?;
let owned_by_evm = target_var.to_lowercase();
let operation = ProfileQueryByHandles::build(ProfilesRequestVariables {
handles: None,
owned_by: Some(vec![EvmAddress(owned_by_evm.clone())]),
});
let response = surf::post(C.upstream.lens_api.url.clone())
.run_graphql(operation)
.await;

if response.is_err() {
warn!(
"LensV2 target {} | Failed to fetch: {}",
target,
response.unwrap_err(),
);
return Ok(vec![]);
}
let cli = make_http_client();
let profiles = response
.unwrap()
.data
.map_or(vec![], |data| data.profiles.items);
let mut next_targets: Vec<Target> = Vec::new();
for profile in profiles.iter() {
let t = save_profile(&cli, profile).await?;
if let Some(t) = t {
next_targets.push(t);
}
}

Ok(next_targets)
}

async fn save_profile(
client: &Client<HttpConnector>,
profile: &Profile,
) -> Result<Option<Target>, Error> {
if profile.handle.clone().is_none() {
return Ok(None);
}
let handle_info = profile.handle.clone().unwrap();
let owner = profile.owned_by.address.0.to_ascii_lowercase();
let lens_handle = format!("{}.{}", handle_info.local_name, handle_info.namespace);
let lens_display_name = profile
.metadata
.clone()
.map_or(None, |metadata| metadata.display_name);
let created_at = utc_to_naive(profile.created_at.clone().0)?;

let addr: Identity = Identity {
uuid: Some(Uuid::new_v4()),
platform: Platform::Ethereum,
identity: owner.clone(),
uid: None,
created_at: None,
display_name: None,
added_at: naive_now(),
avatar_url: None,
profile_url: None,
updated_at: naive_now(),
expired_at: None,
reverse: Some(false),
};

let lens: Identity = Identity {
uuid: Some(Uuid::new_v4()),
platform: Platform::Lens,
identity: lens_handle.clone(),
uid: Some(profile.id.clone().0.to_string()),
created_at: Some(created_at),
display_name: lens_display_name,
added_at: naive_now(),
avatar_url: None,
profile_url: Some("https://hey.xyz/u/".to_owned() + &handle_info.local_name),
updated_at: naive_now(),
expired_at: None,
reverse: Some(true),
};

let hold: Hold = Hold {
uuid: Uuid::new_v4(),
source: DataSource::Lens,
transaction: Some(profile.tx_hash.clone().0),
id: profile.id.clone().0.to_string(),
created_at: Some(created_at),
updated_at: naive_now(),
fetcher: DataFetcher::RelationService,
expired_at: None,
};

let resolve: Resolve = Resolve {
uuid: Uuid::new_v4(),
source: DataSource::Lens,
system: DomainNameSystem::Lens,
name: lens_handle.clone(),
fetcher: DataFetcher::RelationService,
updated_at: naive_now(),
};

// field `is_default` has been canceled in lens-v2-api
let reverse: Resolve = Resolve {
uuid: Uuid::new_v4(),
source: DataSource::Lens,
system: DomainNameSystem::Lens,
name: lens_handle.clone(),
fetcher: DataFetcher::RelationService,
updated_at: naive_now(),
};
trace!("LensV2 Ethereum({}) handle: {}", owner, lens_handle);
create_identity_to_identity_hold_record(client, &addr, &lens, &hold).await?;
create_identity_domain_resolve_record(client, &lens, &addr, &resolve).await?;
create_identity_domain_reverse_resolve_record(client, &addr, &lens, &reverse).await?;
Ok(Some(Target::Identity(Platform::Ethereum, owner.clone())))
}
33 changes: 24 additions & 9 deletions src/upstream/lensv2/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,34 @@ mod tests {
util::make_http_client,
};

#[tokio::test]
async fn test_fetch_by_wallet() -> Result<(), Error> {
let target = Target::Identity(
Platform::Ethereum,
String::from("0x934B510D4C9103E6a87AEf13b816fb080286D649"),
);
let _ = LensV2::fetch(&target).await?;
let client = make_http_client();
let found = Identity::find_by_platform_identity(&client, &Platform::Lens, "sujiyan.lens")
.await?
.expect("Record not found");
print!("found: {:?}", found);
Ok(())
}

#[tokio::test]
async fn test_fetch_by_lens_handle() -> Result<(), Error> {
let target = Target::Identity(Platform::Lens, String::from("sujiyan.lens"));
let _ = LensV2::fetch(&target).await?;
// let client = make_http_client();
// let found = Identity::find_by_platform_identity(
// &client,
// &Platform::Ethereum,
// "0x0fefed77bb715e96f1c35c1a4e0d349563d6f6c0",
// )
// .await?
// .expect("Record not found");
// print!("found: {:?}", found);
let client = make_http_client();
let found = Identity::find_by_platform_identity(
&client,
&Platform::Ethereum,
&String::from("0x934B510D4C9103E6a87AEf13b816fb080286D649").to_lowercase(),
)
.await?
.expect("Record not found");
print!("found: {:?}", found);
Ok(())
}
}

0 comments on commit e11cfc5

Please sign in to comment.