Unofficial async Rust client for FunPay marketplace. Authenticate via golden_key, receive real-time events for chats and orders.
- Real-time polling for chats and orders
- Send messages to chats
- Edit offers (price, quantity, status)
- Configurable polling intervals, retry policies, and User-Agent
- Pluggable state storage (JSON file or in-memory)
- Async/await with Tokio
[dependencies]
funpay-client = "0.2"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }use funpay_client::{FunPayAccount, Event};
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let golden_key = std::env::var("FUNPAY_GOLDEN_KEY")?;
let mut account = FunPayAccount::new(golden_key);
account.init().await?;
println!("Logged in as: {:?}", account.username);
let mut rx = account.subscribe();
tokio::spawn(async move {
while let Ok(event) = rx.recv().await {
match event {
Event::NewMessage { message } => {
println!("New message in {}: {:?}", message.chat_id, message.text);
}
Event::NewOrder { order } => {
println!("New order: {} - {}", order.id, order.description);
}
Event::OrderStatusChanged { order } => {
println!("Order {} status: {:?}", order.id, order.status);
}
_ => {}
}
}
});
account.start_polling_loop().await?;
Ok(())
}Use FunPayConfig builder for custom settings:
use funpay_client::{FunPayAccount, FunPayConfig};
use std::time::Duration;
let config = FunPayConfig::builder()
.user_agent("MyBot/1.0")
.polling_interval(Duration::from_secs(2))
.error_retry_delay(Duration::from_secs(10))
.event_channel_capacity(1024)
.state_storage_path("./state.json")
.retry_policy(50, 5) // base_ms, max_retries
.build();
let account = FunPayAccount::with_config(golden_key, config);use funpay_client::{FunPayAccount, FunPayConfig};
// Simple proxy
let account = FunPayAccount::with_proxy(golden_key, "http://proxy:8080");
// Proxy with custom config
let config = FunPayConfig::builder()
.polling_interval(Duration::from_secs(3))
.build();
let account = FunPayAccount::with_proxy_and_config(golden_key, "http://user:pass@proxy:8080", config);| Event | Description |
|---|---|
InitialChat |
Chat loaded on startup |
ChatsListChanged |
Chat list updated |
LastChatMessageChanged |
New activity in chat |
NewMessage |
New message received |
InitialOrder |
Order loaded on startup |
OrdersListChanged |
Order counters changed |
NewOrder |
New order created |
OrderStatusChanged |
Order status changed |
let sender = account.create_sender()?;
sender.send_chat_message("users-123-456", "Hello!").await?;use funpay_client::models::OfferEditParams;
let sender = account.create_sender()?;
// Get current offer params
let params = sender.get_offer_params(offer_id, node_id).await?;
// Update offer price
let update = OfferEditParams {
price: Some("100.00".to_string()),
..Default::default()
};
sender.edit_offer(offer_id, node_id, update).await?;
// Get all my offers for a category
let offers = sender.get_my_offers(node_id).await?;Implement FunpayGateway trait for custom HTTP handling:
use funpay_client::{FunPayAccount, FunpayGateway};
use std::sync::Arc;
struct MyGateway { /* ... */ }
#[async_trait::async_trait]
impl FunpayGateway for MyGateway {
// implement required methods...
}
let gateway: Arc<dyn FunpayGateway> = Arc::new(MyGateway::new());
let account = FunPayAccount::with_gateway(gateway, golden_key);Implement StateStorage trait for custom persistence:
use funpay_client::StateStorage;
use async_trait::async_trait;
use std::collections::HashMap;
struct RedisStorage { /* ... */ }
#[async_trait]
impl StateStorage for RedisStorage {
async fn load(&self) -> anyhow::Result<HashMap<i64, i64>> {
// load from Redis
}
async fn save(&self, data: &HashMap<i64, i64>) -> anyhow::Result<()> {
// save to Redis
}
}| Parameter | Default |
|---|---|
base_url |
https://funpay.com |
user_agent |
Chrome 123 on Windows |
polling_interval |
1500ms |
error_retry_delay |
5s |
event_channel_capacity |
512 |
retry_base_ms |
20 |
max_retries |
3 |
redirect_limit |
10 |
- Rust 1.84+
- Tokio 1.x