fix(all): Organizing APIs and docs.
This commit is contained in:
parent
3798976340
commit
eadbed756f
11 changed files with 361 additions and 220 deletions
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
23
.idea/general-bots.iml
generated
Normal file
23
.idea/general-bots.iml
generated
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-api/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-auth/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-auth/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-automation/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-core/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-image/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-media/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-messaging/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-migrations/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-monitoring/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-storage/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-testing/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/gb-testing/tests" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/general-bots.iml" filepath="$PROJECT_DIR$/.idea/general-bots.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
76
README.md
76
README.md
|
@ -211,6 +211,82 @@ Licensed under terms specified in workspace configuration.
|
|||
- Global expansion
|
||||
- Enterprise features
|
||||
|
||||
|
||||
|
||||
# Infrastructure Compliance Checklist - ISO 27001, HIPAA, LGPD
|
||||
|
||||
| ✓ | Requirement | Component | Standard | Implementation Steps |
|
||||
|---|-------------|-----------|-----------|---------------------|
|
||||
| ⬜ | TLS 1.3 Configuration | Nginx | All | Configure modern SSL parameters and ciphers in `/etc/nginx/conf.d/ssl.conf` |
|
||||
| ⬜ | Access Logging | Nginx | All | Enable detailed access logs with privacy fields in `/etc/nginx/nginx.conf` |
|
||||
| ⬜ | Rate Limiting | Nginx | ISO 27001 | Implement rate limiting rules in location blocks |
|
||||
| ⬜ | WAF Rules | Nginx | HIPAA | Install and configure ModSecurity with OWASP rules |
|
||||
| ⬜ | Reverse Proxy Security | Nginx | All | Configure security headers (X-Frame-Options, HSTS, CSP) |
|
||||
| ⬜ | MFA Implementation | Zitadel | All | Enable and enforce MFA for all administrative accounts |
|
||||
| ⬜ | RBAC Configuration | Zitadel | All | Set up role-based access control with least privilege |
|
||||
| ⬜ | Password Policy | Zitadel | All | Configure strong password requirements (length, complexity, history) |
|
||||
| ⬜ | OAuth2/OIDC Setup | Zitadel | ISO 27001 | Configure secure OAuth flows and token policies |
|
||||
| ⬜ | Audit Logging | Zitadel | All | Enable comprehensive audit logging for user activities |
|
||||
| ⬜ | Encryption at Rest | Garage (S3) | All | Configure encrypted storage with key management |
|
||||
| ⬜ | Bucket Policies | Garage (S3) | All | Implement strict bucket access policies |
|
||||
| ⬜ | Object Versioning | Garage (S3) | HIPAA | Enable versioning for data recovery capability |
|
||||
| ⬜ | Access Logging | Garage (S3) | All | Enable detailed access logging for object operations |
|
||||
| ⬜ | Lifecycle Rules | Garage (S3) | LGPD | Configure data retention and deletion policies |
|
||||
| ⬜ | DKIM/SPF/DMARC | Stalwart | All | Configure email authentication mechanisms |
|
||||
| ⬜ | Mail Encryption | Stalwart | All | Enable TLS for mail transport |
|
||||
| ⬜ | Content Filtering | Stalwart | All | Implement content scanning and filtering rules |
|
||||
| ⬜ | Mail Archiving | Stalwart | HIPAA | Configure compliant email archiving |
|
||||
| ⬜ | Sieve Filtering | Stalwart | All | Implement security-focused mail filtering rules |
|
||||
| ⬜ | System Hardening | Ubuntu | All | Apply CIS Ubuntu Linux benchmarks |
|
||||
| ⬜ | System Updates | Ubuntu | All | Configure unattended-upgrades for security patches |
|
||||
| ⬜ | Audit Daemon | Ubuntu | All | Configure auditd for system event logging |
|
||||
| ⬜ | Firewall Rules | Ubuntu | All | Configure UFW with restrictive rules |
|
||||
| ⬜ | Disk Encryption | Ubuntu | All | Implement LUKS encryption for system disks |
|
||||
| ⬜ | SELinux/AppArmor | Ubuntu | All | Enable and configure mandatory access control |
|
||||
| ⬜ | Monitoring Setup | All | All | Install and configure Prometheus + Grafana |
|
||||
| ⬜ | Log Aggregation | All | All | Implement centralized logging (e.g., ELK Stack) |
|
||||
| ⬜ | Backup System | All | All | Configure automated backup system with encryption |
|
||||
| ⬜ | Network Isolation | All | All | Implement proper network segmentation |
|
||||
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
1. **Security Policies**
|
||||
- Information Security Policy
|
||||
- Access Control Policy
|
||||
- Password Policy
|
||||
- Data Protection Policy
|
||||
- Incident Response Plan
|
||||
|
||||
2. **Procedures**
|
||||
- Backup and Recovery Procedures
|
||||
- Change Management Procedures
|
||||
- Access Review Procedures
|
||||
- Security Incident Procedures
|
||||
- Data Breach Response Procedures
|
||||
|
||||
3. **Technical Documentation**
|
||||
- Network Architecture Diagrams
|
||||
- System Configuration Documentation
|
||||
- Security Controls Documentation
|
||||
- Encryption Standards Documentation
|
||||
- Logging and Monitoring Documentation
|
||||
|
||||
4. **Compliance Records**
|
||||
- Risk Assessment Reports
|
||||
- Audit Logs
|
||||
- Training Records
|
||||
- Incident Reports
|
||||
- Access Review Records
|
||||
|
||||
## Regular Maintenance Tasks
|
||||
|
||||
- Weekly security updates
|
||||
- Monthly access reviews
|
||||
- Quarterly compliance audits
|
||||
- Annual penetration testing
|
||||
- Bi-annual disaster recovery testing
|
||||
|
||||
---
|
||||
|
||||
Built with ❤️ from Brazil, using Rust for maximum performance and reliability.
|
||||
|
|
|
@ -42,8 +42,8 @@ mod tests {
|
|||
kind: "test".to_string(),
|
||||
content: "integration test".to_string(),
|
||||
metadata: serde_json::Value::Object(serde_json::Map::new()),
|
||||
created_at: chrono::Utc::now(),
|
||||
shard_key: 0,
|
||||
created_at: Some(chrono::Utc::now()),
|
||||
shard_key: Some(0),
|
||||
};
|
||||
|
||||
let response = app
|
||||
|
|
|
@ -24,15 +24,238 @@ pub fn create_router(message_processor: MessageProcessor) -> Router {
|
|||
let state = Arc::new(ApiState {
|
||||
message_processor: Mutex::new(message_processor),
|
||||
});
|
||||
|
||||
Router::new()
|
||||
.route("/health", get(|| async { "OK" }))
|
||||
.route("/messages", post(send_message))
|
||||
.route("/messages/:id", get(get_message))
|
||||
.route("/rooms", post(create_room))
|
||||
.route("/rooms/:id", get(get_room))
|
||||
.route("/rooms/:id/join", post(join_room))
|
||||
.route("/ws", get(websocket_handler))
|
||||
// File & Document Management
|
||||
.route("/files/upload", post(upload_file))
|
||||
.route("/files/download", post(download))
|
||||
.route("/files/copy", post(copy_file))
|
||||
.route("/files/move", post(move_file))
|
||||
.route("/files/delete", post(delete_file))
|
||||
.route("/files/getContents", post(get_file_contents))
|
||||
.route("/files/save", post(save_file))
|
||||
.route("/files/createFolder", post(create_folder))
|
||||
.route("/files/shareFolder", post(share_folder))
|
||||
.route("/files/dirFolder", post(dir_folder))
|
||||
.route("/files/list", post(get_files))
|
||||
.route("/files/search", post(search_files))
|
||||
.route("/files/recent", post(get_recent_files))
|
||||
.route("/files/favorite", post(toggle_favorite))
|
||||
.route("/files/versions", post(get_file_versions))
|
||||
.route("/files/restore", post(restore_file_version))
|
||||
.route("/files/permissions", post(set_file_permissions))
|
||||
.route("/files/quota", get(get_storage_quota))
|
||||
.route("/files/shared", get(get_shared_files))
|
||||
.route("/files/sync/status", get(get_sync_status))
|
||||
.route("/files/sync/start", post(start_sync))
|
||||
.route("/files/sync/stop", post(stop_sync))
|
||||
|
||||
// Document Processing
|
||||
.route("/docs/merge", post(merge_documents))
|
||||
.route("/docs/convert", post(convert_document))
|
||||
.route("/docs/fill", post(fill_document))
|
||||
.route("/docs/export", post(export_document))
|
||||
.route("/docs/import", post(import_document))
|
||||
|
||||
// Groups & Organizations
|
||||
.route("/groups/create", post(create_group))
|
||||
.route("/groups/update", put(update_group))
|
||||
.route("/groups/delete", delete(delete_group))
|
||||
.route("/groups/list", get(get_groups))
|
||||
.route("/groups/search", post(search_groups))
|
||||
.route("/groups/members", get(get_group_members))
|
||||
.route("/groups/members/add", post(add_group_member))
|
||||
.route("/groups/members/remove", post(remove_group_member))
|
||||
.route("/groups/permissions", post(set_group_permissions))
|
||||
.route("/groups/settings", post(update_group_settings))
|
||||
.route("/groups/analytics", get(get_group_analytics))
|
||||
.route("/groups/join/request", post(request_group_join))
|
||||
.route("/groups/join/approve", post(approve_join_request))
|
||||
.route("/groups/join/reject", post(reject_join_request))
|
||||
.route("/groups/invites/send", post(send_group_invite))
|
||||
.route("/groups/invites/list", get(list_group_invites))
|
||||
|
||||
// Teams & Projects
|
||||
.route("/teams/create", post(create_team))
|
||||
.route("/teams/update", put(update_team))
|
||||
.route("/teams/delete", delete(delete_team))
|
||||
.route("/teams/list", get(get_teams))
|
||||
.route("/teams/search", post(search_teams))
|
||||
.route("/teams/members", get(get_team_members))
|
||||
.route("/teams/members/add", post(add_team_member))
|
||||
.route("/teams/members/remove", post(remove_team_member))
|
||||
.route("/teams/roles", post(set_team_roles))
|
||||
.route("/teams/permissions", post(set_team_permissions))
|
||||
.route("/teams/settings", post(update_team_settings))
|
||||
.route("/teams/analytics", get(get_team_analytics))
|
||||
.route("/teams/projects/create", post(create_project))
|
||||
.route("/teams/projects/list", get(get_projects))
|
||||
.route("/teams/projects/update", put(update_project))
|
||||
.route("/teams/projects/delete", delete(delete_project))
|
||||
.route("/teams/reports/generate", post(generate_team_report))
|
||||
.route("/teams/activity", get(get_team_activity))
|
||||
|
||||
// Conversations & Real-time Communication
|
||||
.route("/conversations/create", post(create_conversation))
|
||||
.route("/conversations/join", post(join_conversation))
|
||||
.route("/conversations/leave", post(leave_conversation))
|
||||
.route("/conversations/members", get(get_conversation_members))
|
||||
.route("/conversations/messages", get(get_messages))
|
||||
.route("/conversations/messages/send", post(send_message))
|
||||
.route("/conversations/messages/edit", put(edit_message))
|
||||
.route("/conversations/messages/delete", delete(delete_message))
|
||||
.route("/conversations/messages/react", post(react_to_message))
|
||||
.route("/conversations/messages/pin", post(pin_message))
|
||||
.route("/conversations/messages/search", post(search_messages))
|
||||
.route("/conversations/calls/start", post(start_call))
|
||||
.route("/conversations/calls/join", post(join_call))
|
||||
.route("/conversations/calls/leave", post(leave_call))
|
||||
.route("/conversations/calls/mute", post(mute_participant))
|
||||
.route("/conversations/calls/unmute", post(unmute_participant))
|
||||
.route("/conversations/screen/share", post(share_screen))
|
||||
.route("/conversations/screen/stop", post(stop_screen_share))
|
||||
.route("/conversations/recording/start", post(start_recording))
|
||||
.route("/conversations/recording/stop", post(stop_recording))
|
||||
.route("/conversations/whiteboard/create", post(create_whiteboard))
|
||||
.route("/conversations/whiteboard/collaborate", post(collaborate_whiteboard))
|
||||
|
||||
// Communication Services
|
||||
.route("/comm/email/send", post(send_email))
|
||||
.route("/comm/email/template", post(send_template_email))
|
||||
.route("/comm/email/schedule", post(schedule_email))
|
||||
.route("/comm/email/cancel", post(cancel_scheduled_email))
|
||||
.route("/comm/sms/send", post(send_sms))
|
||||
.route("/comm/sms/bulk", post(send_bulk_sms))
|
||||
.route("/comm/notifications/send", post(send_notification))
|
||||
.route("/comm/notifications/preferences", post(set_notification_preferences))
|
||||
.route("/comm/broadcast/send", post(send_broadcast))
|
||||
.route("/comm/contacts/import", post(import_contacts))
|
||||
.route("/comm/contacts/export", post(export_contacts))
|
||||
.route("/comm/contacts/sync", post(sync_contacts))
|
||||
.route("/comm/contacts/groups", post(manage_contact_groups))
|
||||
|
||||
// User Management & Authentication
|
||||
.route("/users/create", post(create_user))
|
||||
.route("/users/update", put(update_user))
|
||||
.route("/users/delete", delete(delete_user))
|
||||
.route("/users/list", get(get_users))
|
||||
.route("/users/search", post(search_users))
|
||||
.route("/users/profile", get(get_user_profile))
|
||||
.route("/users/profile/update", put(update_profile))
|
||||
.route("/users/settings", post(update_user_settings))
|
||||
.route("/users/permissions", post(set_user_permissions))
|
||||
.route("/users/roles", post(manage_user_roles))
|
||||
.route("/users/status", post(update_user_status))
|
||||
.route("/users/presence", get(get_user_presence))
|
||||
.route("/users/activity", get(get_user_activity))
|
||||
.route("/users/security/2fa/enable", post(enable_2fa))
|
||||
.route("/users/security/2fa/disable", post(disable_2fa))
|
||||
.route("/users/security/devices", get(get_registered_devices))
|
||||
.route("/users/security/sessions", get(get_active_sessions))
|
||||
.route("/users/notifications/settings", post(update_notification_settings))
|
||||
|
||||
// Calendar & Task Management
|
||||
.route("/calendar/events/create", post(create_event))
|
||||
.route("/calendar/events/update", put(update_event))
|
||||
.route("/calendar/events/delete", delete(delete_event))
|
||||
.route("/calendar/events/list", get(get_calendar_events))
|
||||
.route("/calendar/events/search", post(search_events))
|
||||
.route("/calendar/availability/check", post(check_availability))
|
||||
.route("/calendar/schedule/meeting", post(schedule_meeting))
|
||||
.route("/calendar/reminders/set", post(set_reminder))
|
||||
.route("/tasks/create", post(create_task))
|
||||
.route("/tasks/update", put(update_task))
|
||||
.route("/tasks/delete", delete(delete_task))
|
||||
.route("/tasks/list", get(get_tasks))
|
||||
.route("/tasks/assign", post(assign_task))
|
||||
.route("/tasks/status/update", put(update_task_status))
|
||||
.route("/tasks/priority/set", post(set_task_priority))
|
||||
.route("/tasks/dependencies/set", post(set_task_dependencies))
|
||||
|
||||
// Storage & Data Management
|
||||
.route("/storage/save", post(save_to_storage))
|
||||
.route("/storage/batch", post(save_batch_to_storage))
|
||||
.route("/storage/json", post(save_json_to_storage))
|
||||
.route("/storage/delete", delete(delete_from_storage))
|
||||
.route("/storage/quota/check", get(check_storage_quota))
|
||||
.route("/storage/cleanup", post(cleanup_storage))
|
||||
.route("/storage/backup/create", post(create_backup))
|
||||
.route("/storage/backup/restore", post(restore_backup))
|
||||
.route("/storage/archive", post(archive_data))
|
||||
.route("/storage/metrics", get(get_storage_metrics))
|
||||
|
||||
// Automation & Workflows
|
||||
.route("/automation/workflow/create", post(create_workflow))
|
||||
.route("/automation/workflow/update", put(update_workflow))
|
||||
.route("/automation/workflow/delete", delete(delete_workflow))
|
||||
.route("/automation/workflow/execute", post(execute_workflow))
|
||||
.route("/automation/workflow/status", get(get_workflow_status))
|
||||
.route("/automation/triggers/create", post(create_trigger))
|
||||
.route("/automation/triggers/list", get(list_triggers))
|
||||
.route("/automation/schedule/create", post(create_schedule))
|
||||
.route("/automation/schedule/update", put(update_schedule))
|
||||
.route("/automation/actions/create", post(create_action))
|
||||
.route("/automation/actions/execute", post(execute_action))
|
||||
.route("/automation/rules/create", post(create_rule))
|
||||
.route("/automation/rules/evaluate", post(evaluate_rules))
|
||||
|
||||
// Analytics & Reporting
|
||||
.route("/analytics/dashboard", get(get_dashboard_data))
|
||||
.route("/analytics/reports/generate", post(generate_report))
|
||||
.route("/analytics/reports/schedule", post(schedule_report))
|
||||
.route("/analytics/metrics/collect", post(collect_metrics))
|
||||
.route("/analytics/insights/generate", post(generate_insights))
|
||||
.route("/analytics/trends/analyze", post(analyze_trends))
|
||||
.route("/analytics/export", post(export_analytics))
|
||||
|
||||
// System & Administration
|
||||
.route("/admin/system/status", get(get_system_status))
|
||||
.route("/admin/system/metrics", get(get_system_metrics))
|
||||
.route("/admin/logs/view", get(view_logs))
|
||||
.route("/admin/logs/export", post(export_logs))
|
||||
.route("/admin/config/update", post(update_config))
|
||||
.route("/admin/maintenance/schedule", post(schedule_maintenance))
|
||||
.route("/admin/backup/create", post(create_system_backup))
|
||||
.route("/admin/backup/restore", post(restore_system_backup))
|
||||
.route("/admin/users/manage", post(manage_system_users))
|
||||
.route("/admin/roles/manage", post(manage_system_roles))
|
||||
.route("/admin/quotas/manage", post(manage_quotas))
|
||||
.route("/admin/licenses/manage", post(manage_licenses))
|
||||
|
||||
// Integration & External Services
|
||||
.route("/integrations/list", get(list_integrations))
|
||||
.route("/integrations/install", post(install_integration))
|
||||
.route("/integrations/configure", post(configure_integration))
|
||||
.route("/integrations/uninstall", post(uninstall_integration))
|
||||
.route("/integrations/status", get(get_integration_status))
|
||||
.route("/integrations/sync", post(sync_integration_data))
|
||||
.route("/integrations/webhook/create", post(create_webhook))
|
||||
.route("/integrations/webhook/manage", post(manage_webhooks))
|
||||
|
||||
// AI & Machine Learning
|
||||
.route("/ai/analyze/text", post(analyze_text))
|
||||
.route("/ai/analyze/image", post(analyze_image))
|
||||
.route("/ai/generate/text", post(generate_text))
|
||||
.route("/ai/generate/image", post(generate_image))
|
||||
.route("/ai/translate", post(translate_content))
|
||||
.route("/ai/summarize", post(summarize_content))
|
||||
.route("/ai/recommend", post(get_recommendations))
|
||||
.route("/ai/train/model", post(train_custom_model))
|
||||
.route("/ai/predict", post(make_prediction))
|
||||
|
||||
// Security & Compliance
|
||||
.route("/security/audit/logs", get(get_audit_logs))
|
||||
.route("/security/compliance/check", post(check_compliance))
|
||||
.route("/security/threats/scan", post(scan_for_threats))
|
||||
.route("/security/access/review", post(review_access))
|
||||
.route("/security/encryption/manage", post(manage_encryption))
|
||||
.route("/security/certificates/manage", post(manage_certificates))
|
||||
|
||||
// Health & Monitoring
|
||||
.route("/health", get(health_check))
|
||||
.route("/health/detailed", get(detailed_health_check))
|
||||
.route("/monitoring/status", get(get_monitoring_status))
|
||||
.route("/monitoring/alerts", get(get_active_alerts))
|
||||
.route("/monitoring/metrics", get(get_monitoring_metrics))
|
||||
.with_state(state)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
mod kafka;
|
||||
mod rabbitmq;
|
||||
mod redis_pubsub;
|
||||
mod websocket;
|
||||
mod processor;
|
||||
pub mod models;
|
||||
|
||||
pub use kafka::Kafka;
|
||||
pub use rabbitmq::RabbitMQ;
|
||||
pub use redis_pubsub::RedisPubSub;
|
||||
pub use websocket::WebSocketClient;
|
||||
pub use processor::MessageProcessor;
|
||||
|
@ -38,10 +36,6 @@ mod tests {
|
|||
let redis_client = Client::open("redis://localhost")
|
||||
.expect("Failed to create Redis client");
|
||||
let redis = RedisPubSub::new(Arc::new(redis_client));
|
||||
let rabbitmq = RabbitMQ::new("amqp://localhost:5672")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut websocket = WebSocketClient::connect("ws://localhost:8080")
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -59,10 +53,6 @@ mod tests {
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
rabbitmq.publish("", "test.key", &test_message)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
websocket.send_message(&serde_json::to_string(&test_message).unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -83,8 +73,8 @@ mod tests {
|
|||
kind: "test".to_string(),
|
||||
content: "test content".to_string(),
|
||||
metadata: serde_json::Value::Object(serde_json::Map::new()),
|
||||
created_at: chrono::Utc::now(),
|
||||
shard_key: 0,
|
||||
created_at: Some(chrono::Utc::now()),
|
||||
shard_key: Some(0),
|
||||
};
|
||||
|
||||
let envelope = MessageEnvelope {
|
||||
|
|
|
@ -7,7 +7,7 @@ use tracing::instrument;
|
|||
use crate::MessageEnvelope;
|
||||
use tokio::sync::broadcast; // Add this import
|
||||
use std::sync::Arc;
|
||||
use tracing::{error, info}; // Add error and info macros here
|
||||
use tracing::{error}; // Add error and info macros here
|
||||
|
||||
|
||||
pub struct MessageProcessor {
|
||||
|
@ -109,8 +109,8 @@ mod tests {
|
|||
kind: "test".to_string(),
|
||||
content: "test content".to_string(),
|
||||
metadata: serde_json::Value::Object(serde_json::Map::new()),
|
||||
created_at: chrono::Utc::now(),
|
||||
shard_key: 0,
|
||||
created_at: Some(chrono::Utc::now()),
|
||||
shard_key: Some(0),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
use gb_core::{Result, Error};
|
||||
use lapin::{
|
||||
options::*,
|
||||
types::FieldTable,
|
||||
Connection, ConnectionProperties,
|
||||
Channel,
|
||||
BasicProperties,
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{instrument, error};
|
||||
use futures::StreamExt;
|
||||
|
||||
pub struct RabbitMQ {
|
||||
connection: Arc<Connection>,
|
||||
channel: Arc<Mutex<Channel>>,
|
||||
}
|
||||
|
||||
impl Clone for RabbitMQ {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
connection: self.connection.clone(),
|
||||
channel: self.channel.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RabbitMQ {
|
||||
pub async fn new(url: &str) -> Result<Self> {
|
||||
let connection = Connection::connect(
|
||||
url,
|
||||
ConnectionProperties::default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::internal(format!("RabbitMQ connection error: {}", e)))?;
|
||||
|
||||
let channel = connection.create_channel()
|
||||
.await
|
||||
.map_err(|e| Error::internal(format!("RabbitMQ channel error: {}", e)))?;
|
||||
|
||||
Ok(Self {
|
||||
connection: Arc::new(connection),
|
||||
channel: Arc::new(Mutex::new(channel)),
|
||||
})
|
||||
}
|
||||
|
||||
#[instrument(skip(self, message))]
|
||||
pub async fn publish<T: Serialize>(
|
||||
&self,
|
||||
exchange: &str,
|
||||
routing_key: &str,
|
||||
message: &T,
|
||||
) -> Result<()> {
|
||||
let payload = serde_json::to_string(message)
|
||||
.map_err(|e| Error::internal(format!("Serialization error: {}", e)))?;
|
||||
|
||||
let channel = self.channel.lock().await;
|
||||
|
||||
channel.basic_publish(
|
||||
exchange,
|
||||
routing_key,
|
||||
BasicPublishOptions::default(),
|
||||
payload.as_bytes(),
|
||||
BasicProperties::default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::internal(format!("RabbitMQ publish error: {}", e)))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self, handler))]
|
||||
pub async fn subscribe<T, F, Fut>(
|
||||
&self,
|
||||
queue: &str,
|
||||
handler: F,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
F: Fn(T) -> Fut,
|
||||
Fut: std::future::Future<Output = Result<()>>,
|
||||
{
|
||||
let channel = self.channel.lock().await;
|
||||
|
||||
channel.queue_declare(
|
||||
queue,
|
||||
QueueDeclareOptions::default(),
|
||||
FieldTable::default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::internal(format!("RabbitMQ queue declare error: {}", e)))?;
|
||||
|
||||
let mut consumer = channel.basic_consume(
|
||||
queue,
|
||||
"consumer",
|
||||
BasicConsumeOptions::default(),
|
||||
FieldTable::default(),
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::internal(format!("RabbitMQ consume error: {}", e)))?;
|
||||
|
||||
while let Some(delivery) = consumer.next().await {
|
||||
match delivery {
|
||||
Ok(delivery) => {
|
||||
if let Ok(payload) = String::from_utf8(delivery.data.clone()) {
|
||||
match serde_json::from_str::<T>(&payload) {
|
||||
Ok(value) => {
|
||||
if let Err(e) = handler(value).await {
|
||||
error!("Handler error: {}", e);
|
||||
}
|
||||
}
|
||||
Err(e) => error!("Deserialization error: {}", e),
|
||||
}
|
||||
}
|
||||
delivery.ack(BasicAckOptions::default())
|
||||
.await
|
||||
.map_err(|e| error!("Ack error: {}", e)).ok();
|
||||
}
|
||||
Err(e) => error!("Consumer error: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rstest::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
|
||||
struct TestMessage {
|
||||
id: Uuid,
|
||||
content: String,
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
async fn rabbitmq() -> RabbitMQ {
|
||||
RabbitMQ::new("amqp://localhost:5672")
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[fixture]
|
||||
fn test_message() -> TestMessage {
|
||||
TestMessage {
|
||||
id: Uuid::new_v4(),
|
||||
content: "test message".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_publish_subscribe(
|
||||
#[future] rabbitmq: RabbitMQ,
|
||||
test_message: TestMessage,
|
||||
) {
|
||||
let queue = "test_queue";
|
||||
let routing_key = "test_routing_key";
|
||||
|
||||
let rabbitmq = rabbitmq.await;
|
||||
let rabbitmq_clone = rabbitmq.clone();
|
||||
let test_message_clone = test_message.clone();
|
||||
|
||||
let handle = tokio::spawn(async move {
|
||||
let test_message_ref = test_message_clone.clone();
|
||||
let handler = move |msg: TestMessage| {
|
||||
let expected_msg = test_message_ref.clone();
|
||||
async move {
|
||||
assert_eq!(msg, expected_msg);
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
rabbitmq_clone.subscribe(queue, handler).await.unwrap();
|
||||
});
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
rabbitmq.publish("", routing_key, &test_message)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
|
||||
handle.abort();
|
||||
}
|
||||
}
|
0
lib.rs
Normal file
0
lib.rs
Normal file
Loading…
Add table
Reference in a new issue