Files
solana-streamer/crates/pumpfun/src/instruction/logs_subscribe.rs
T

104 lines
3.2 KiB
Rust
Raw Normal View History

2025-01-02 13:59:17 +08:00
use anchor_client::solana_client::{
nonblocking::pubsub_client::PubsubClient,
rpc_config::{RpcTransactionLogsConfig, RpcTransactionLogsFilter}
};
2025-01-03 17:01:07 +08:00
use anchor_client::solana_sdk::{commitment_config::CommitmentConfig, pubkey::Pubkey};
2025-01-02 13:59:17 +08:00
use std::sync::Arc;
use tokio::sync::mpsc;
use tokio::task::JoinHandle;
2025-01-03 00:38:45 +08:00
use futures::StreamExt;
2025-01-03 11:14:39 +08:00
use crate::{constants, instruction::{
logs_data::DexInstruction, logs_events::DexEvent, logs_filters::LogFilter
}};
2025-01-02 13:59:17 +08:00
2025-01-03 00:38:45 +08:00
/// Subscription handle containing task and unsubscribe logic
2025-01-02 13:59:17 +08:00
pub struct SubscriptionHandle {
pub task: JoinHandle<()>,
pub unsub_fn: Box<dyn Fn() + Send>,
}
2025-01-02 19:44:38 +08:00
impl SubscriptionHandle {
pub async fn shutdown(self) {
(self.unsub_fn)();
self.task.abort();
}
}
2025-01-02 13:59:17 +08:00
pub async fn create_pubsub_client(ws_url: &str) -> PubsubClient {
PubsubClient::new(ws_url).await.unwrap()
}
/// 启动订阅
2025-01-03 00:38:45 +08:00
pub async fn tokens_subscription<F>(
2025-01-02 13:59:17 +08:00
ws_url: &str,
commitment: CommitmentConfig,
2025-01-03 00:38:45 +08:00
callback: F,
2025-01-03 17:06:19 +08:00
bot_wallet: Option<Pubkey>,
2025-01-02 13:59:17 +08:00
) -> Result<SubscriptionHandle, Box<dyn std::error::Error>>
where
2025-01-03 00:38:45 +08:00
F: Fn(DexEvent) + Send + Sync + 'static,
2025-01-02 13:59:17 +08:00
{
2025-01-03 11:14:39 +08:00
let program_address = constants::accounts::PUMPFUN.to_string();
let logs_filter = RpcTransactionLogsFilter::Mentions(vec![program_address]);
2025-01-02 19:44:38 +08:00
2025-01-02 13:59:17 +08:00
let logs_config = RpcTransactionLogsConfig {
commitment: Some(commitment),
};
2025-01-03 00:38:45 +08:00
// Create PubsubClient
2025-01-02 19:44:38 +08:00
let sub_client = Arc::new(PubsubClient::new(ws_url).await.unwrap());
2025-01-02 13:59:17 +08:00
let sub_client_clone = Arc::clone(&sub_client);
2025-01-03 00:38:45 +08:00
// Create channel for unsubscribe
let (unsub_tx, _) = mpsc::channel(1);
2025-01-02 13:59:17 +08:00
2025-01-03 00:38:45 +08:00
// Start subscription task
2025-01-02 13:59:17 +08:00
let task = tokio::spawn(async move {
2025-01-03 00:38:45 +08:00
let (mut stream, _) = sub_client_clone.logs_subscribe(logs_filter, logs_config).await.unwrap();
2025-01-02 19:44:38 +08:00
2025-01-02 13:59:17 +08:00
loop {
2025-01-02 19:44:38 +08:00
let msg = stream.next().await;
match msg {
Some(msg) => {
if let Some(_err) = msg.value.err {
continue;
2025-01-02 13:59:17 +08:00
}
2025-01-03 00:38:45 +08:00
2025-01-03 17:06:19 +08:00
let instructions = LogFilter::parse_instruction(&msg.value.logs, bot_wallet).unwrap();
2025-01-03 00:38:45 +08:00
for instruction in instructions {
match instruction {
DexInstruction::CreateToken(token_info) => {
callback(DexEvent::NewToken(token_info));
}
2025-01-03 17:06:19 +08:00
DexInstruction::UserTrade(trade_info) => {
callback(DexEvent::NewUserTrade(trade_info));
2025-01-03 00:38:45 +08:00
}
2025-01-03 17:01:07 +08:00
DexInstruction::BotTrade(trade_info) => {
callback(DexEvent::NewBotTrade(trade_info));
}
2025-01-03 00:38:45 +08:00
_ => {}
}
}
2025-01-02 13:59:17 +08:00
}
2025-01-02 19:44:38 +08:00
None => {
println!("Token subscription stream ended");
}
}
2025-01-02 13:59:17 +08:00
}
});
2025-01-03 00:38:45 +08:00
// Return subscription handle and unsubscribe logic
2025-01-02 13:59:17 +08:00
Ok(SubscriptionHandle {
task,
unsub_fn: Box::new(move || {
2025-01-03 00:38:45 +08:00
let _ = unsub_tx.try_send(());
2025-01-02 13:59:17 +08:00
}),
})
}
pub async fn stop_subscription(handle: SubscriptionHandle) {
2025-01-08 16:33:43 +08:00
handle.shutdown().await;
2025-01-02 13:59:17 +08:00
}