Найти в Дзене
Один Rust не п...Rust

Управление акциями маркетплейсов на Rust

Оглавление

Для чего нужна данная статья? :
Создать
маркетплейс на 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();

}