Для чего нужна данная статья? :
Создать маркетплейс на Rust с поддержкой ML, используя:
- Axum для API.
- PostgreSQL + SQLx для хранения товаров, заказов, пользователей.
- Redis для кеширования.
- Tonic (gRPC) для общения с ML-сервисами.
- PyO3 + TensorFlow/PyTorch для машинного обучения.
- RabbitMQ/Kafka для событий.
- WebSockets для реального времени.
- OAuth2 (Keycloak) для авторизации.
- Actix Web + WebRTC для потокового видео товаров.
Зачем Вам это уметь? :
Использовать обращение к API маркетплейсов, добавлять и удалять акции для продуктов:
1. Через смарт-контракты на блокчейне
Если маркетплейс работает в Web3, можно использовать Solana (Anchor), Ethereum (Rust для WASM-смарт-контрактов) или Substrate:
- Solana + Anchor → смарт-контракт управляет скидками, кешбэком, бонусами.
- Ethereum (Ink!) → реализация через WASM-контракты.
- Substrate → создание кастомного блокчейна для управления акциями.
✅ Плюсы: прозрачность, безопасность, децентрализация.
❌ Минусы: сложность разработки, необходимость комиссий за транзакции.
2. Через микросервис с API на Axum / Actix
Можно создать отдельный сервис для управления акциями и предоставлять REST/gRPC API:
- Rust + Axum/Actix для API.
- PostgreSQL + Diesel/SQLx для хранения акций.
- Redis для кеширования активных акций.
- RabbitMQ/Kafka для асинхронных событий (например, запуск/остановка акции).
✅ Плюсы: высокая производительность, гибкость, простота масштабирования.
❌ Минусы: сложнее интегрировать в монолитные системы.
3. Через no-code платформу на Rust (Bevy/Egui + WebView)
Можно сделать графический интерфейс для управления акциями маркетплейса:
- Egui + WebView → легковесный UI для управления акциями.
- SQLite/PostgreSQL → локальная или серверная БД.
- Rust + Tauri → десктопное приложение для управления акциями.
✅ Плюсы: простота разработки, кроссплатформенность.
❌ Минусы: не масштабируется для больших нагрузок.
4. Через SaaS-платформу на Rust
Создать облачный сервис управления акциями, где маркетплейсы могут настраивать скидки через API или UI.
- API: Axum, Actix, gRPC.
- Auth: Keycloak/OpenID (OAuth2).
- Storage: PostgreSQL + Redis.
- Billing: Stripe/PayPal SDK на Rust.
- ML-модуль: автоматическая генерация акций на основе данных (Rust + PyO3).
✅ Плюсы: готовый сервис для нескольких маркетплейсов.
❌ Минусы: сложность разработки, поддержка пользователей.
5. Встроенный механизм в маркетплейс (монолит на Rust)
Если маркетплейс полностью написан на Rust, акции можно встроить в основную систему:
- Использовать бизнес-логику в Rocket/Axum/Actix.
- PostgreSQL для хранения правил акций.
- Кеширование в Redis для быстрого доступа.
- Cron/Scheduler (tokio, quartz) для управления временем начала и конца акций.
✅ Плюсы: простота интеграции в существующий код.
❌ Минусы: сложность поддержки при росте системы.
Создадим менеджер акций:
use std::collections::HashMap;
// Структура для хранения информации о продукте
struct Product {
id: u32,
name: String,
price: f64,
discount: Option<f64>, // Скидка, None если скидки нет
}
// Менеджер акций, управляющий продуктами и их акциями
struct DiscountManager {
products: HashMap<u32, Product>,
}
impl DiscountManager {
// Создание нового менеджера акций
fn new() -> DiscountManager {
DiscountManager {
products: HashMap::new(),
}
}
// Добавление продукта
fn add_product(&mut self, id: u32, name: String, price: f64) {
let product = Product {
id,
name,
price,
discount: None,
};
self.products.insert(id, product);
}
// Установка скидки для продукта
fn set_discount(&mut self, id: u32, discount: f64) {
if let Some(product) = self.products.get_mut(&id) {
product.discount = Some(discount);
}
}
// Удаление скидки с продукта
fn remove_discount(&mut self, id: u32) {
if let Some(product) = self.products.get_mut(&id) {
product.discount = None;
}
}
// Вывод информации о продукте
fn print_product_info(&self, id: u32) {
if let Some(product) = self.products.get(&id) {
println!("Product ID: {}", product.id);
println!("Name: {}", product.name);
println!("Price: ${}", product.price);
match product.discount {
Some(discount) => println!("Discount: {}%", discount),
None => println!("No discount"),
}
} else {
println!("Product not found");
}
}
}
fn main() {
let mut manager = DiscountManager::new();
manager.add_product(1, "Rust Programming Book".to_string(), 50.0);
manager.set_discount(1, 10.0); // Установка скидки 10%
manager.print_product_info(1);
manager.remove_discount(1); // Удаление скидки
manager.print_product_info(1);
}
Используем API eBay для управления акциями и продуктами:
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1", features = ["full"] }
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::error::Error;
// Структура для десериализации ответа
#[derive(Debug, Serialize, Deserialize)]
struct ProductResponse {
// Определите поля в соответствии с форматом ответа API
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = Client::new();
let access_token = "your_access_token_here"; // Замените на ваш фактический токен
let product_id = "product_id_here"; // ID продукта, для которого нужна информация
let url = format!("https://api.ebay.com/some_endpoint/{}", product_id);
let response = client
.get(url)
.bearer_auth(access_token)
.send()
.await?
.json::<ProductResponse>()
.await?;
println!("{:?}", response);
Ok(())
}
Маркетплейс на Rust с поддержкой ML
marketplace/
├── api/ # Axum API (основной сервис)
├── ml_service/ # Python ML с PyO3/gRPC
├── streaming/ # Actix Web + WebRTC
├── protos/ # .proto файлы для gRPC
└── docker-compose.yml # Оркестрация сервисов
Основные зависимости (api/Cargo.toml)
[dependencies]
axum = "0.7"
sqlx = { version = "0.7", features = ["postgres", "runtime-tokio"] }
redis = "0.23"
tonic = "0.11"
prost = "0.12"
keycloak = "0.5"
tokio = { version = "1.0", features = ["full"] }
tower-http = { version = "0.5", features = ["cors"] }
lapin = { version = "3", features = ["tokio"] }
Пример API с Axum (api/src/main.rs)
use axum::{routing::get, Router, Extension};
use sqlx::postgres::PgPoolOptions;
struct AppState {
db_pool: sqlx::PgPool,
redis: redis::Client,
}
#[tokio::main]
async fn main() {
let db_pool = PgPoolOptions::new()
.connect("postgres://user:pass@localhost/marketplace")
.await
.unwrap();
let redis = redis::Client::open("redis://127.0.0.1/").unwrap();
let app = Router::new()
.route("/products", get(get_products))
.layer(Extension(AppState { db_pool, redis }));
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
.serve(app.into_make_service())
.await
.unwrap();
}
async fn get_products(Extension(state): Extension<AppState>) -> String {
// Проверка кэша Redis
let cached: Option<String> = state.redis.get_connection().unwrap()
.get("products")
.await
.unwrap_or(None);
if let Some(cached) = cached {
return cached;
}
// Запрос к PostgreSQL
let products = sqlx::query!("SELECT * FROM products")
.fetch_all(&state.db_pool)
.await
.unwrap();
// Кэширование
state.redis.get_connection().unwrap()
.set_ex("products", &products, 60)
.await
.unwrap();
format!("{:?}", products)
}
gRPC интеграция с Tonic (protos/recommendations.proto)
syntax = "proto3";
service Recommender {
rpc GetRecommendations (ProductRequest) returns (Recommendations);
}
message ProductRequest {
string product_id = 1;
}
message Recommendations {
repeated string product_ids = 1;
}
ML Service на Python (ml_service/main.py)
import grpc
from concurrent import futures
import recommendations_pb2_grpc
class Recommender(recommendations_pb2_grpc.RecommenderServicer):
def GetRecommendations(self, request, context):
# PyTorch/TensorFlow логика
return recommendations_pb2.Recommendations(product_ids=["123", "456"])
server = grpc.server(futures.ThreadPoolExecutor())
recommendations_pb2_grpc.add_RecommenderServicer_to_server(Recommender(), server)
server.add_insecure_port("[::]:50051")
server.start()
server.wait_for_termination()
WebSocket с Axum (api/src/websockets.rs)
use axum::extract::ws::{WebSocket, WebSocketUpgrade};
async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
ws.on_upgrade(|mut socket| async move {
while let Some(Ok(msg)) = socket.recv().await {
socket.send(msg).await.unwrap();
}
})
}
Docker-compose конфигурация
version: '3'
services:
api:
build: ./api
ports:
- "3000:3000"
depends_on:
- postgres
- redis
- keycloak
ml_service:
image: python:3.9
command: python -u main.py
volumes:
- ./ml_service:/app
ports:
- "50051:50051"
postgres:
image: postgres:14
environment:
POSTGRES_PASSWORD: password
redis:
image: redis:7
keycloak:
image: quay.io/keycloak/keycloak:22.0
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
Интеграция OAuth2
use axum::middleware::from_extractor;
use keycloak::Keycloak;
async fn protected_route(user: AuthenticatedUser) -> String {
format!("Hello {}", user.id)
}
let app = Router::new()
.route("/protected", get(protected_route))
.layer(from_extractor::<Keycloak>());
WebRTC с Actix (streaming/src/main.rs)
use actix_web::{web, App, HttpResponse, HttpServer};
async fn offer_negotiation(offer: web::Json<Offer>) -> HttpResponse {
// Сигнальная логика WebRTC
HttpResponse::Ok().json(Answer { sdp: "..." })
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/offer", post(offer_negotiation)))
.bind("0.0.0.0:4000")?
.run()
.await
}
Асинхронные события с RabbitMQ
use lapin::{options::*, Connection, ConnectionProperties};
async fn publish_order_event(order: Order) {
let conn = Connection::connect("amqp://guest:guest@localhost:5672", ConnectionProperties)
.await
.unwrap();
let channel = conn.create_channel().await.unwrap();
channel
.basic_publish(
"orders",
"",
BasicPublishOptions::default(),
serde_json::to_vec(&order).unwrap(),
BasicProperties::default(),
)
.await
.unwrap();
}