cloudpub_sdk/lib.rs
1//! # CloudPub Rust SDK
2//!
3//! CloudPub Rust SDK предоставляет простой интерфейс для взаимодействия с
4//! платформой CloudPub. CloudPub обеспечивает безопасное туннелирование и публикацию сервисов,
5//! позволяя безопасно открывать локальные сервисы в интернет.
6//!
7//! ## Возможности
8//!
9//! - **Публикация сервисов**: Открытие локальных сервисов (HTTP, HTTPS, TCP, UDP, WebSocket, RTSP) в интернет
10//! - **Безопасное туннелирование**: Все соединения шифруются и аутентифицируются
11//! - **Несколько протоколов**: Поддержка различных протоколов, включая HTTP/HTTPS, TCP/UDP, WebSocket и RTSP
12//! - **Аутентификация**: Встроенная поддержка аутентификации на основе токенов и учетных данных
13//! - **Управление сервисами**: Запуск, остановка, список и управление опубликованными сервисами
14//! - **Событийно-ориентированная архитектура**: Поддержка async/await с управлением состоянием на основе событий
15//!
16//! ## Быстрый старт
17//!
18//! Добавьте SDK в ваш `Cargo.toml`:
19//!
20//! ```toml
21//! [dependencies]
22//! cloudpub-sdk = "2.4.2"
23//! cloudpub-common = "2.4.2" # Требуется для типов протокола
24//! ```
25//!
26//! ## Базовое использование
27//!
28//! ### Простая публикация сервиса
29//!
30//! ```no_run
31//! use cloudpub_sdk::Connection;
32//! use cloudpub_common::protocol::{Protocol, Auth, Endpoint};
33//!
34//! #[tokio::main]
35//! async fn main() -> anyhow::Result<()> {
36//! // Создание соединения с учетными данными
37//! let mut conn = Connection::builder()
38//! .credentials("user@example.com", "password")
39//! .build()
40//! .await?;
41//!
42//! // Публикация локального веб-сервиса
43//! let endpoint = conn.publish(
44//! Protocol::Http,
45//! "localhost:3000".to_string(),
46//! Some("My Web App".to_string()),
47//! Some(Auth::None),
48//! None, // acl
49//! None, // headers
50//! None, // rules
51//! ).await?;
52//!
53//! println!("Service published at: {}", endpoint.as_url());
54//!
55//! // Ожидание сигнала Ctrl+C для остановки
56//! tokio::signal::ctrl_c().await?;
57//!
58//! // Очистка
59//! conn.unpublish(endpoint.guid).await?;
60//! Ok(())
61//! }
62//! ```
63//!
64//! ### Расширенная публикация сервиса с ACL, заголовками и правилами фильтрации
65//!
66//! ```no_run
67//! use cloudpub_sdk::Connection;
68//! use cloudpub_common::protocol::{
69//! Protocol, Auth, Endpoint, Acl, Header, FilterRule,
70//! Role, FilterAction
71//! };
72//!
73//! #[tokio::main]
74//! async fn main() -> anyhow::Result<()> {
75//! let mut conn = Connection::builder()
76//! .credentials("admin@example.com", "password")
77//! .build()
78//! .await?;
79//!
80//! // Настройка списка контроля доступа
81//! let acl = vec![
82//! Acl { user: "admin@example.com".to_string(), role: Role::Admin as i32 },
83//! Acl { user: "user@example.com".to_string(), role: Role::Reader as i32 },
84//! Acl { user: "writer@example.com".to_string(), role: Role::Writer as i32 },
85//! ];
86//!
87//! // Добавление пользовательских HTTP заголовков
88//! let headers = vec![
89//! Header { name: "X-API-Version".to_string(), value: "2.0".to_string() },
90//! Header { name: "Access-Control-Allow-Origin".to_string(), value: "*".to_string() },
91//! Header { name: "X-Custom-Header".to_string(), value: "CloudPub".to_string() },
92//! ];
93//!
94//! // Определение правил фильтрации для обработки запросов
95//! let rules = vec![
96//! FilterRule {
97//! order: 0,
98//! action_type: FilterAction::FilterAllow as i32,
99//! action_value: None,
100//! data: "http.path starts_with \"/api/\" and http.headers[\"X-API-Key\"] contains \"valid\"".to_string(),
101//! },
102//! FilterRule {
103//! order: 1,
104//! action_type: FilterAction::FilterDeny as i32,
105//! action_value: None,
106//! data: "http.path matches \"^/admin.*\" and not (ip.src >= 192.168.1.0 and ip.src <= 192.168.1.255)".to_string(),
107//! },
108//! FilterRule {
109//! order: 2,
110//! action_type: FilterAction::FilterRedirect as i32,
111//! action_value: Some("https://api.example.com/v2/".to_string()), // URL перенаправления
112//! data: "http.path starts_with \"/api/v1/\"".to_string(),
113//! },
114//! ];
115//!
116//! // Публикация сервиса со всеми расширенными возможностями
117//! let endpoint = conn.publish(
118//! Protocol::Https,
119//! "localhost:8443".to_string(),
120//! Some("Secured API Server".to_string()),
121//! Some(Auth::Basic),
122//! Some(acl),
123//! Some(headers),
124//! Some(rules),
125//! ).await?;
126//!
127//! println!("Advanced service published at: {}", endpoint.as_url());
128//!
129//! Ok(())
130//! }
131//! ```
132//!
133//! ### Расширенная конфигурация
134//!
135//! ```no_run
136//! # async fn example() -> anyhow::Result<()> {
137//! use cloudpub_sdk::Connection;
138//! use std::time::Duration;
139//!
140//! // Создание соединения с расширенной конфигурацией
141//! let conn = Connection::builder()
142//! .config_path("/custom/path/config.toml") // Пользовательский файл конфигурации
143//! .log_level("debug") // Включить отладочное логирование
144//! .verbose(true) // Вывод логов в консоль
145//! .timeout(Duration::from_secs(60)) // Установить таймаут операции
146//! .token("existing-auth-token") // Использовать существующий токен
147//! .build()
148//! .await?;
149//! # Ok(())
150//! # }
151//! ```
152//!
153//! ## Расширенные возможности
154//!
155//! ### Списки контроля доступа (ACL)
156//!
157//! Контроль доступа к вашим сервисам на основе ролей пользователей:
158//!
159//! ```no_run
160//! # use cloudpub_common::protocol::{Acl, Role};
161//! let acl = vec![
162//! Acl {
163//! user: "admin@example.com".to_string(),
164//! role: Role::Admin as i32 // Полный доступ
165//! },
166//! Acl {
167//! user: "reader@example.com".to_string(),
168//! role: Role::Reader as i32 // Доступ только на чтение
169//! },
170//! Acl {
171//! user: "writer@example.com".to_string(),
172//! role: Role::Writer as i32 // Доступ на чтение-запись
173//! },
174//! Acl {
175//! user: "guest@example.com".to_string(),
176//! role: Role::Nobody as i32 // Нет доступа
177//! },
178//! ];
179//! ```
180//!
181//! ### Пользовательские HTTP заголовки
182//!
183//! Добавление пользовательских заголовков в HTTP/HTTPS ответы:
184//!
185//! ```no_run
186//! # use cloudpub_common::protocol::Header;
187//! let headers = vec![
188//! Header {
189//! name: "X-API-Version".to_string(),
190//! value: "2.0".to_string()
191//! },
192//! Header {
193//! name: "Access-Control-Allow-Origin".to_string(),
194//! value: "*".to_string()
195//! },
196//! Header {
197//! name: "Cache-Control".to_string(),
198//! value: "no-cache, no-store, must-revalidate".to_string()
199//! },
200//! ];
201//! ```
202//!
203//! ### Правила фильтрации
204//!
205//! Определение правил для управления маршрутизацией запросов и доступом на основе различных параметров соединения.
206//! Правила обрабатываются по порядку (по полю `order`), и первое подходящее правило применяется.
207//!
208//! ```no_run
209//! # use cloudpub_common::protocol::{FilterRule, FilterAction};
210//! let rules = vec![
211//! // Разрешить доступ к API только из локальной сети
212//! FilterRule {
213//! order: 0,
214//! action_type: FilterAction::FilterAllow as i32,
215//! action_value: None,
216//! data: "ip.src >= 192.168.1.0 and ip.src <= 192.168.1.255 and http.path starts_with \"/api/\"".to_string(),
217//! },
218//!
219//! // Блокировать доступ к админ-панели снаружи
220//! FilterRule {
221//! order: 1,
222//! action_type: FilterAction::FilterDeny as i32,
223//! action_value: None,
224//! data: "http.path matches \"^/admin.*\"".to_string(),
225//! },
226//!
227//! // Перенаправление старых API эндпоинтов на новую версию
228//! // action_value содержит URL перенаправления для FilterRedirect
229//! FilterRule {
230//! order: 2,
231//! action_type: FilterAction::FilterRedirect as i32,
232//! action_value: Some("https://api.example.com/v2/".to_string()), // Redirect URL
233//! data: "http.path starts_with \"/api/v1/\"".to_string(),
234//! },
235//!
236//! // Блокировать запросы из определенных стран
237//! FilterRule {
238//! order: 3,
239//! action_type: FilterAction::FilterDeny as i32,
240//! action_value: None,
241//! data: "geo.country != \"Россия\"".to_string(),
242//! },
243//!
244//! // Разрешить только аутентифицированные API запросы
245//! FilterRule {
246//! order: 4,
247//! action_type: FilterAction::FilterAllow as i32,
248//! action_value: None,
249//! data: "http.path starts_with \"/api/\" and http.headers[\"Authorization\"] contains \"Bearer\"".to_string(),
250//! },
251//! ];
252//! ```
253//!
254//! **Доступные переменные для фильтр выражений:**
255//! - `ip.src`, `ip.dst` - IP адреса источника и назначения
256//! - `port.src`, `port.dst` - Порты источника и назначения
257//! - `protocol` - Протокол соединения ("tcp", "udp", "http")
258//! - `http.host`, `http.path`, `http.method` - HTTP-специфичные поля
259//! - `http.headers["Header-Name"]` - Доступ к HTTP заголовкам
260//! - `geo.country`, `geo.region`, `geo.city`, `geo.code` - Данные геолокации
261//!
262//! **Операторы:**
263//! - Сравнение: `==`, `!=`, `>`, `<`, `>=`, `<=`
264//! - Строковые: `matches` (regex), `contains`, `starts_with`, `ends_with`
265//! - Логические: `and`, `or`, `not`
266//!
267//! ## Типы сервисов
268//!
269//! CloudPub поддерживает несколько протоколов сервисов:
270//!
271//! ### HTTP/HTTPS сервисы
272//!
273//! ```no_run
274//! # async fn http_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
275//! use cloudpub_common::protocol::{Protocol, Auth, Endpoint};
276//!
277//! // Публикация HTTP сервиса с базовой аутентификацией
278//! let http_endpoint = conn.publish(
279//! Protocol::Http,
280//! "localhost:8080".to_string(),
281//! Some("API Server".to_string()),
282//! Some(Auth::Basic), // Требовать пароль для доступа
283//! None, // acl
284//! None, // headers
285//! None, // rules
286//! ).await?;
287//!
288//! // Публикация HTTPS сервиса
289//! let https_endpoint = conn.publish(
290//! Protocol::Https,
291//! "localhost:8443".to_string(),
292//! Some("Secure API".to_string()),
293//! Some(Auth::Basic), // Требовать токен для доступа
294//! None, // acl
295//! None, // headers
296//! None, // rules
297//! ).await?;
298//! # Ok(())
299//! # }
300//! ```
301//!
302//! ### TCP/UDP сервисы
303//!
304//! ```no_run
305//! # async fn tcp_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
306//! use cloudpub_common::protocol::{Protocol, Auth};
307//!
308//! // Публикация TCP сервиса (например, SSH)
309//! let tcp_endpoint = conn.publish(
310//! Protocol::Tcp,
311//! "localhost:22".to_string(),
312//! Some("SSH Server".to_string()),
313//! Some(Auth::None),
314//! None, // acl
315//! None, // headers
316//! None, // rules
317//! ).await?;
318//!
319//! // Публикация UDP сервиса (например, DNS)
320//! let udp_endpoint = conn.publish(
321//! Protocol::Udp,
322//! "localhost:53".to_string(),
323//! Some("DNS Server".to_string()),
324//! Some(Auth::None),
325//! None, // acl
326//! None, // headers
327//! None, // rules
328//! ).await?;
329//! # Ok(())
330//! # }
331//! ```
332//!
333//! ### WebSocket сервисы
334//!
335//! ```no_run
336//! # async fn ws_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
337//! use cloudpub_common::protocol::{Protocol, Auth};
338//!
339//! // Публикация TCP сервиса
340//! let tcp_endpoint = conn.publish(
341//! Protocol::Tcp,
342//! "localhost:8080".to_string(),
343//! Some("TCP Server".to_string()),
344//! Some(Auth::None),
345//! None, // acl
346//! None, // headers
347//! None, // rules
348//! ).await?;
349//!
350//! // Публикация UDP сервиса
351//! let udp_endpoint = conn.publish(
352//! Protocol::Udp,
353//! "localhost:8443".to_string(),
354//! Some("UDP Server".to_string()),
355//! Some(Auth::Basic),
356//! None, // acl
357//! None, // headers
358//! None, // rules
359//! ).await?;
360//! # Ok(())
361//! # }
362//! ```
363//!
364//! ### RTSP стриминговые сервисы
365//!
366//! ```no_run
367//! # async fn rtsp_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
368//! use cloudpub_common::protocol::{Protocol, Auth};
369//!
370//! // Публикация RTSP потока с учетными данными в URL
371//! // Формат: rtsp://username:password@host:port/path
372//! let rtsp_endpoint = conn.publish(
373//! Protocol::Rtsp,
374//! "rtsp://camera:secret123@192.168.1.100:554/live/stream1".to_string(),
375//! Some("Security Camera".to_string()),
376//! Some(Auth::Basic), // Аутентификация доступа в CloudPub
377//! None, // acl
378//! None, // headers
379//! None, // rules
380//! ).await?;
381//!
382//! // RTSP без учетных данных (публичный поток)
383//! let public_rtsp = conn.publish(
384//! Protocol::Rtsp,
385//! "rtsp://localhost:554/public".to_string(),
386//! Some("Public Stream".to_string()),
387//! Some(Auth::None),
388//! None, // acl
389//! None, // headers
390//! None, // rules
391//! ).await?;
392//! # Ok(())
393//! # }
394//! ```
395//!
396//! ## Управление сервисами
397//!
398//! ### Список сервисов
399//!
400//! ```no_run
401//! # async fn list_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
402//! use cloudpub_common::protocol::Endpoint;
403//! // Получить все зарегистрированные сервисы
404//! let services = conn.ls().await?;
405//!
406//! for service in services {
407//! let name = service.client.as_ref()
408//! .and_then(|c| c.description.clone())
409//! .unwrap_or_else(|| "Без имени".to_string());
410//! println!("Service: {}", name);
411//! println!(" GUID: {}", service.guid);
412//! println!(" URL: {}", service.as_url());
413//! println!(" Status: {}", service.status.unwrap_or_else(|| "Unknown".to_string()));
414//! println!(" Protocol: {:?}", service.remote_proto);
415//! }
416//! # Ok(())
417//! # }
418//! ```
419//!
420//! ### Запуск и остановка сервисов
421//!
422//! ```no_run
423//! # async fn control_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
424//! // Временно остановить сервис
425//! conn.stop("service-guid-123".to_string()).await?;
426//!
427//! // Перезапустить сервис
428//! conn.start("service-guid-123".to_string()).await?;
429//!
430//! // Постоянно удалить сервис
431//! conn.unpublish("service-guid-123".to_string()).await?;
432//!
433//! // Удалить все сервисы
434//! conn.clean().await?;
435//! # Ok(())
436//! # }
437//! ```
438//!
439//! ## Управление конфигурацией
440//!
441//! ### Чтение и запись опций
442//!
443//! ```no_run
444//! # fn config_example(conn: &cloudpub_sdk::Connection) -> anyhow::Result<()> {
445//! // Установка значений конфигурации
446//! conn.set("server", "api.cloudpub.com")?;
447//! conn.set("port", "443")?;
448//! conn.set("ssl", "true")?;
449//!
450//! // Получение значений конфигурации
451//! let server = conn.get("server")?;
452//! println!("Server: {}", server);
453//!
454//! // Получение всех опций конфигурации
455//! let options = conn.options();
456//! for (key, value) in options {
457//! println!("{}: {}", key, value);
458//! }
459//! # Ok(())
460//! # }
461//! ```
462//!
463//! ### Управление аутентификацией
464//!
465//! ```no_run
466//! # async fn auth_example() -> anyhow::Result<()> {
467//! use cloudpub_sdk::Connection;
468//!
469//! // Аутентификация с учетными данными
470//! let mut conn = Connection::builder()
471//! .credentials("user@example.com", "password")
472//! .build()
473//! .await?;
474//!
475//! // Позже, выход для очистки токена
476//! conn.logout()?;
477//!
478//! // Повторная аутентификация с сохраненным токеном
479//! let conn = Connection::builder()
480//! .token("saved-auth-token")
481//! .build()
482//! .await?;
483//! # Ok(())
484//! # }
485//! ```
486//!
487//! ## Вспомогательные функции
488//!
489//! ### Проверка состояния сервера
490//!
491//! ```no_run
492//! # async fn ping_example(conn: &mut cloudpub_sdk::Connection) -> anyhow::Result<()> {
493//! // Измерение задержки сервера (возвращает микросекунды)
494//! let latency_us = conn.ping().await?;
495//! let latency_ms = latency_us as f64 / 1000.0;
496//! println!("Server latency: {}μs ({:.2}ms)", latency_us, latency_ms);
497//!
498//! if latency_ms > 100.0 {
499//! println!("Warning: High latency detected!");
500//! }
501//! # Ok(())
502//! # }
503//! ```
504//!
505//! ### Управление кэшем
506//!
507//! ```no_run
508//! # fn cache_example(conn: &cloudpub_sdk::Connection) -> anyhow::Result<()> {
509//! // Очистка локального кэша
510//! conn.purge()?;
511//! println!("Cache cleared");
512//! # Ok(())
513//! # }
514//! ```
515//!
516//! ## Обработка ошибок
517//!
518//! Все методы SDK возвращают `Result<T>` для правильной обработки ошибок:
519//!
520//! ```no_run
521//! # async fn error_example() -> anyhow::Result<()> {
522//! use cloudpub_sdk::Connection;
523//!
524//! match Connection::builder()
525//! .credentials("user@example.com", "wrong-password")
526//! .build()
527//! .await
528//! {
529//! Ok(conn) => {
530//! println!("Connected successfully");
531//! },
532//! Err(e) => {
533//! eprintln!("Connection failed: {}", e);
534//! // Обработка специфичных типов ошибок
535//! if e.to_string().contains("authentication") {
536//! eprintln!("Authentication failed. Please check your credentials.");
537//! }
538//! }
539//! }
540//! # Ok(())
541//! # }
542//! ```
543//!
544//! ## Полный пример
545//!
546//! Вот полный пример, демонстрирующий полный жизненный цикл с расширенными возможностями:
547//!
548//! ```no_run
549//! use cloudpub_sdk::Connection;
550//! use cloudpub_common::protocol::{
551//! Protocol, Auth, Endpoint, Acl, Header, FilterRule,
552//! Role, FilterAction
553//! };
554//! use std::time::Duration;
555//! use tokio::time::sleep;
556//!
557//! #[tokio::main]
558//! async fn main() -> anyhow::Result<()> {
559//! // Инициализация соединения с конфигурацией
560//! println!("Connecting to CloudPub...");
561//! let mut conn = Connection::builder()
562//! .credentials("admin@example.com", "secure-password")
563//! .log_level("info")
564//! .verbose(true)
565//! .timeout_secs(30)
566//! .build()
567//! .await?;
568//!
569//! println!("Connected successfully!");
570//!
571//! // Публикация нескольких сервисов
572//! println!("\nPublishing services...");
573//!
574//! // Простой веб-сервис без расширенных возможностей
575//! let web_service = conn.publish(
576//! Protocol::Http,
577//! "localhost:3000".to_string(),
578//! Some("Web Application".to_string()),
579//! Some(Auth::None),
580//! None, // Нет ACL ограничений
581//! None, // Нет пользовательских заголовков
582//! None, // Нет правил фильтрации
583//! ).await?;
584//! println!("✓ Web app: {}", web_service.as_url());
585//!
586//! // API сервер с ACL и пользовательскими заголовками
587//! let api_acl = vec![
588//! Acl { user: "api_admin@example.com".to_string(), role: Role::Admin as i32 },
589//! Acl { user: "api_user@example.com".to_string(), role: Role::Reader as i32 },
590//! ];
591//! let api_headers = vec![
592//! Header { name: "X-API-Version".to_string(), value: "2.0".to_string() },
593//! Header { name: "Access-Control-Allow-Origin".to_string(), value: "*".to_string() },
594//! ];
595//! let api_service = conn.publish(
596//! Protocol::Https,
597//! "localhost:8443".to_string(),
598//! Some("API Server".to_string()),
599//! Some(Auth::Basic),
600//! Some(api_acl),
601//! Some(api_headers),
602//! None, // Нет правил фильтрации
603//! ).await?;
604//! println!("✓ API server: {}", api_service.as_url());
605//!
606//! // SSH сервис с правилами фильтрации для безопасности
607//! let ssh_rules = vec![
608//! FilterRule {
609//! order: 0,
610//! action_type: FilterAction::FilterAllow as i32,
611//! action_value: None,
612//! data: "ip.src == 192.168.1.10 or ip.src == 10.0.0.5".to_string(), // Разрешить только определенные IP
613//! },
614//! FilterRule {
615//! order: 1,
616//! action_type: FilterAction::FilterDeny as i32,
617//! action_value: None,
618//! data: "ip.src matches \".*\"".to_string(), // Заблокировать все остальные IP
619//! },
620//! ];
621//! let ssh_service = conn.publish(
622//! Protocol::Tcp,
623//! "localhost:22".to_string(),
624//! Some("SSH Access".to_string()),
625//! Some(Auth::Basic),
626//! None, // Нет ACL
627//! None, // Нет заголовков (TCP не использует HTTP заголовки)
628//! Some(ssh_rules),
629//! ).await?;
630//! println!("✓ SSH: {}", ssh_service.as_url());
631//!
632//! // Проверка состояния сервера
633//! println!("\nChecking server health...");
634//! let latency_us = conn.ping().await?;
635//! println!("Server latency: {}μs ({:.2}ms)", latency_us, latency_us as f64 / 1000.0);
636//!
637//! // Список всех сервисов
638//! println!("\nActive services:");
639//! let services = conn.ls().await?;
640//! for (i, service) in services.iter().enumerate() {
641//! let name = service.client.as_ref()
642//! .and_then(|c| c.description.clone())
643//! .unwrap_or_else(|| "Без имени".to_string());
644//! println!("{}. {} - {}",
645//! i + 1,
646//! name,
647//! service.as_url()
648//! );
649//! }
650//!
651//! // Работать некоторое время
652//! println!("\nServices are running. Press Ctrl+C to stop...");
653//! tokio::select! {
654//! _ = tokio::signal::ctrl_c() => {
655//! println!("\nShutting down...");
656//! }
657//! _ = sleep(Duration::from_secs(3600)) => {
658//! println!("\nTimeout reached");
659//! }
660//! }
661//!
662//! // Очистка
663//! println!("Очистка сервисов...");
664//! for service in services {
665//! conn.unpublish(service.guid).await?;
666//! let name = service.client.as_ref()
667//! .and_then(|c| c.description.clone())
668//! .unwrap_or_else(|| "Без имени".to_string());
669//! println!("✓ Removed: {}", name);
670//! }
671//!
672//! println!("All services stopped. Goodbye!");
673//! Ok(())
674//! }
675//! ```
676//! ## Потокобезопасность
677//!
678//! Структура `Connection` использует внутреннюю синхронизацию и может безопасно использоваться
679//! между потоками через `Arc<Mutex<Connection>>` при необходимости.
680//!
681//! ## Лицензия
682//!
683//! Этот SDK лицензирован под лицензией Apache 2.0.
684
685pub use cloudpub_client::config::ClientOpts;
686
687mod builder;
688mod connection;
689
690pub use builder::ConnectionBuilder;
691pub use connection::{CheckSignalFn, Connection, ConnectionEvent};