#[cfg(feature = "graphql")]
use async_graphql::{Context, Object, Result};
#[cfg(feature = "graphql")]
use std::sync::Arc;
#[cfg(feature = "graphql")]
use crate::client::InstagramClient;
#[cfg(feature = "graphql")]
use crate::types::{
profile::{ProfileInfo, AuthState},
thread::{Thread, User, InboxResult},
story::{StoryReel, Story},
message::{Message, ReactionEvent},
post::{FeedInstance, Post},
};
#[cfg(feature = "graphql")]
use crate::auth::login::{LoginResult, TwoFactorInfo, CheckpointError};
#[cfg(feature = "graphql")]
use crate::direct::thread::MessagesResult;
#[cfg(feature = "graphql")]
use crate::notify::inbox::NewsInbox;
#[cfg(feature = "graphql")]
#[derive(async_graphql::SimpleObject)]
pub struct ThreadSearchResult {
pub thread: Thread,
pub score: f64,
}
#[cfg(feature = "graphql")]
#[derive(Default)]
pub struct QinstagramQuery;
#[cfg(feature = "graphql")]
#[Object]
impl QinstagramQuery {
async fn current_user(&self, ctx: &Context<'_>) -> Result<ProfileInfo> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let user = client.get_current_user().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(user)
}
async fn direct_threads(&self, ctx: &Context<'_>) -> Result<Vec<Thread>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_threads(None).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result.threads)
}
async fn thread_by_username(&self, ctx: &Context<'_>, username: String) -> Result<Option<Thread>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.search_thread_by_username(&username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn reels_tray(&self, ctx: &Context<'_>) -> Result<Vec<StoryReel>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_reels_tray().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn news_inbox(&self, ctx: &Context<'_>) -> Result<String> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_news_inbox().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
serde_json::to_string(&result).map_err(|e| async_graphql::Error::new(e.to_string()))
}
async fn messages(&self, ctx: &Context<'_>, thread_id: String, cursor: Option<String>) -> Result<MessagesResult> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_messages(&thread_id, cursor.as_deref()).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn timeline_feed(&self, ctx: &Context<'_>) -> Result<FeedInstance> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_timeline_feed().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn stories_for_user(&self, ctx: &Context<'_>, user_id: String) -> Result<Vec<Story>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_stories_for_user(&user_id).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn search_users(&self, ctx: &Context<'_>, query: String) -> Result<Vec<User>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.search_users(&query).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn search_user_exact(&self, ctx: &Context<'_>, username: String) -> Result<Option<User>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.search_user_exact(&username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn search_threads_by_title(&self, ctx: &Context<'_>, query: String) -> Result<Vec<ThreadSearchResult>> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.search_threads_by_title(&query).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result.into_iter().map(|(thread, score)| ThreadSearchResult { thread, score }).collect())
}
async fn user_info_by_pk(&self, ctx: &Context<'_>, pk: String) -> Result<ProfileInfo> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_user_info(&pk).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn user_profile_by_username(&self, ctx: &Context<'_>, username: String) -> Result<ProfileInfo> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let result = client.get_user_profile(&username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
}
#[cfg(feature = "graphql")]
#[derive(Default)]
pub struct QinstagramMutation;
#[cfg(feature = "graphql")]
#[Object]
impl QinstagramMutation {
async fn send_message(&self, ctx: &Context<'_>, thread_id: String, text: String) -> Result<bool> {
let client = ctx.data::<Arc<InstagramClient>>()?;
client.send_message(&thread_id, &text).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn send_reaction(&self, ctx: &Context<'_>, thread_id: String, item_id: String, emoji: String) -> Result<bool> {
let client = ctx.data::<Arc<InstagramClient>>()?;
client.send_reaction(&thread_id, &item_id, &emoji).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn mark_item_seen(&self, ctx: &Context<'_>, thread_id: String, item_id: String) -> Result<bool> {
let client = ctx.data::<Arc<InstagramClient>>()?;
client.mark_item_as_seen(&thread_id, &item_id).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn unsend_message(&self, ctx: &Context<'_>, thread_id: String, item_id: String) -> Result<bool> {
let client = ctx.data::<Arc<InstagramClient>>()?;
client.unsend_message(&thread_id, &item_id).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn ensure_thread(&self, ctx: &Context<'_>, user_pks: Vec<String>) -> Result<Thread> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let slices: Vec<&str> = user_pks.iter().map(|s| s.as_str()).collect();
let result = client.ensure_thread(&slices).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn mark_thread_seen(&self, ctx: &Context<'_>, thread_id: String, item_id: String) -> Result<bool> {
let client = ctx.data::<Arc<InstagramClient>>()?;
client.mark_thread_as_seen(&thread_id, &item_id).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn send_photo(&self, ctx: &Context<'_>, thread_id: String, file_path_str: String) -> Result<String> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let p = std::path::Path::new(&file_path_str);
let result = client.send_photo(&thread_id, p).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn send_video(&self, ctx: &Context<'_>, thread_id: String, file_path_str: String) -> Result<String> {
let client = ctx.data::<Arc<InstagramClient>>()?;
let p = std::path::Path::new(&file_path_str);
let result = client.send_video(&thread_id, p).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(result)
}
async fn login(&self, ctx: &Context<'_>, username: String, password: String) -> Result<LoginResult> {
let mut local_client = crate::client::InstagramClient::builder().build().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
let res = local_client.login(&username, &password).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(res)
}
async fn two_factor_login(&self, ctx: &Context<'_>, code: String, identifier: String, username: String) -> Result<LoginResult> {
let mut local_client = crate::client::InstagramClient::builder().build().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
let res = local_client.two_factor_login(&code, &identifier, &username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(res)
}
async fn start_challenge(&self, ctx: &Context<'_>, url: String) -> Result<bool> {
let mut local_client = crate::client::InstagramClient::builder().build().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
local_client.start_challenge(&url).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn send_challenge_code(&self, ctx: &Context<'_>, url: String, code: String, username: String) -> Result<LoginResult> {
let mut local_client = crate::client::InstagramClient::builder().build().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
let res = local_client.send_challenge_code(&url, &code, &username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(res)
}
async fn switch_user(&self, ctx: &Context<'_>, username: String) -> Result<bool> {
crate::client::InstagramClient::switch_user(&username).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn logout(&self, ctx: &Context<'_>, username: Option<String>) -> Result<bool> {
crate::client::InstagramClient::logout(username.as_deref()).await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
async fn cleanup_sessions(&self, ctx: &Context<'_>) -> Result<bool> {
crate::client::InstagramClient::cleanup_sessions().await
.map_err(|e| async_graphql::Error::new(e.to_string()))?;
Ok(true)
}
}