new(all): Initial import.
This commit is contained in:
parent
cba43cefde
commit
7f384469a9
4 changed files with 41 additions and 119 deletions
|
@ -8,11 +8,9 @@ use axum::{
|
|||
response::IntoResponse,
|
||||
Json,
|
||||
};
|
||||
|
||||
use gb_core::{Result, Error, models::*};
|
||||
use gb_messaging::{MessageProcessor, models::MessageEnvelope};
|
||||
use std::sync::Arc;
|
||||
use chrono;
|
||||
use std::{sync::Arc, collections::HashMap};
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{instrument, error};
|
||||
use uuid::Uuid;
|
||||
|
@ -48,7 +46,7 @@ async fn handle_ws_connection(
|
|||
if let Ok(text) = msg.to_text() {
|
||||
if let Ok(envelope) = serde_json::from_str::<MessageEnvelope>(text) {
|
||||
let mut processor = state.message_processor.lock().await;
|
||||
if let Err(e) = processor.process_message(&envelope).await {
|
||||
if let Err(e) = processor.process_messages(vec![envelope]).await {
|
||||
error!("Failed to process message: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -57,19 +55,17 @@ async fn handle_ws_connection(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn websocket_handler(
|
||||
State(state): State<Arc<ApiState>>,
|
||||
ws: WebSocketUpgrade,
|
||||
) -> impl IntoResponse {
|
||||
ws.on_upgrade(|socket| async move {
|
||||
ws.on_upgrade(move |socket| async move {
|
||||
let _ = handle_ws_connection(socket, state).await;
|
||||
})
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn send_message(
|
||||
State(state): State<Arc<ApiState>>,
|
||||
Json(message): Json<Message>,
|
||||
|
@ -77,27 +73,25 @@ async fn send_message(
|
|||
let envelope = MessageEnvelope {
|
||||
id: Uuid::new_v4(),
|
||||
message,
|
||||
metadata: std::collections::HashMap::new(),
|
||||
metadata: HashMap::new(),
|
||||
};
|
||||
|
||||
let mut processor = state.message_processor.lock().await;
|
||||
processor.process_message(&envelope).await
|
||||
processor.process_messages(vec![envelope.clone()]).await
|
||||
.map_err(|e| Error::internal(format!("Failed to process message: {}", e)))?;
|
||||
|
||||
Ok(Json(MessageId(envelope.id)))
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn get_message(
|
||||
State(_state): State<Arc<ApiState>>,
|
||||
Path(id): Path<Uuid>,
|
||||
Path(_id): Path<Uuid>,
|
||||
) -> Result<Json<Message>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn create_room(
|
||||
State(_state): State<Arc<ApiState>>,
|
||||
Json(_config): Json<RoomConfig>,
|
||||
|
@ -105,44 +99,19 @@ async fn create_room(
|
|||
todo!()
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn get_room(
|
||||
State(_state): State<Arc<ApiState>>,
|
||||
Path(id): Path<Uuid>,
|
||||
Path(_id): Path<Uuid>,
|
||||
) -> Result<Json<Room>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[axum::debug_handler]
|
||||
#[instrument(skip(state))]
|
||||
#[instrument(skip_all)]
|
||||
async fn join_room(
|
||||
State(_state): State<Arc<ApiState>>,
|
||||
Path(id): Path<Uuid>,
|
||||
Json(user_id): Json<Uuid>,
|
||||
Path(_id): Path<Uuid>,
|
||||
Json(_user_id): Json<Uuid>,
|
||||
) -> Result<Json<Connection>> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use axum::http::StatusCode;
|
||||
use axum::body::Body;
|
||||
use tower::ServiceExt;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_health_check() {
|
||||
let app = create_router(MessageProcessor::new(100));
|
||||
let response = app
|
||||
.oneshot(
|
||||
axum::http::Request::builder()
|
||||
.uri("/health")
|
||||
.body(Body::empty())
|
||||
.unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
use axum::{
|
||||
http::Request,
|
||||
response::Response,
|
||||
http::{Request, Response},
|
||||
middleware::Next,
|
||||
body::Body,
|
||||
};
|
||||
use axum_extra::TypedHeader;
|
||||
use axum_extra::headers::{Authorization, authorization::Bearer};
|
||||
use gb_core::User;
|
||||
use jsonwebtoken::{decode, DecodingKey, Validation};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::AuthError;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct Claims {
|
||||
|
@ -14,10 +16,10 @@ struct Claims {
|
|||
exp: i64,
|
||||
}
|
||||
|
||||
pub async fn auth_middleware<B>(
|
||||
pub async fn auth_middleware(
|
||||
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
|
||||
request: Request<B>,
|
||||
next: Next<B>,
|
||||
request: Request<Body>,
|
||||
next: Next,
|
||||
) -> Result<Response, AuthError> {
|
||||
let token = auth.token();
|
||||
let key = DecodingKey::from_secret(b"secret");
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
use std::time::Duration;
|
||||
use chromiumoxide::browser::{Browser, BrowserConfig};
|
||||
use chromiumoxide::cdp::browser_protocol;
|
||||
use chromiumoxide::element::Element;
|
||||
use chromiumoxide::page::Page;
|
||||
use futures_util::StreamExt;
|
||||
use gb_core::{Error, Result};
|
||||
use tracing::instrument;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Element {
|
||||
inner: chromiumoxide::element::Element,
|
||||
}
|
||||
|
||||
pub struct WebAutomation {
|
||||
browser: Browser,
|
||||
}
|
||||
|
@ -18,10 +12,14 @@ pub struct WebAutomation {
|
|||
impl WebAutomation {
|
||||
#[instrument]
|
||||
pub async fn new() -> Result<Self> {
|
||||
let (browser, mut handler) = Browser::launch(BrowserConfig::default())
|
||||
let config = BrowserConfig::builder()
|
||||
.build()
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
|
||||
let (browser, mut handler) = Browser::launch(config)
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
|
||||
|
||||
tokio::spawn(async move {
|
||||
while let Some(h) = handler.next().await {
|
||||
if let Err(e) = h {
|
||||
|
@ -35,36 +33,34 @@ impl WebAutomation {
|
|||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn new_page(&self) -> Result<Page> {
|
||||
let params = browser_protocol::page::CreateTarget::new();
|
||||
let page = self.browser.new_page(params)
|
||||
let params = chromiumoxide::cdp::browser_protocol::target::CreateTarget::new()
|
||||
.url("about:blank");
|
||||
|
||||
self.browser.new_page(params)
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(page)
|
||||
.map_err(|e| Error::internal(e.to_string()))
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn navigate(&self, page: &Page, url: &str) -> Result<()> {
|
||||
page.goto(url)
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(())
|
||||
.map_err(|e| Error::internal(e.to_string()))
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_element(&self, page: &Page, selector: &str) -> Result<Element> {
|
||||
let element = page.find_element(selector)
|
||||
page.find_element(selector)
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(Element { inner: element })
|
||||
.map_err(|e| Error::internal(e.to_string()))
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn screenshot(&self, page: &Page, _path: &str) -> Result<Vec<u8>> {
|
||||
let screenshot_params = browser_protocol::page::CaptureScreenshot::new();
|
||||
let data = page.screenshot(screenshot_params)
|
||||
let params = chromiumoxide::cdp::browser_protocol::page::CaptureScreenshot::new();
|
||||
page.screenshot(params)
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(data)
|
||||
.map_err(|e| Error::internal(e.to_string()))
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
|
@ -74,49 +70,4 @@ impl WebAutomation {
|
|||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn wait_for_network_idle(&self, page: &Page) -> Result<()> {
|
||||
page.evaluate("() => new Promise(resolve => setTimeout(resolve, 1000))")
|
||||
.await
|
||||
.map_err(|e| Error::internal(e.to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rstest::*;
|
||||
|
||||
#[fixture]
|
||||
async fn automation() -> WebAutomation {
|
||||
WebAutomation::new().await.unwrap()
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_navigation(automation: WebAutomation) -> Result<()> {
|
||||
let page = automation.new_page().await?;
|
||||
automation.navigate(&page, "https://example.com").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_element_interaction(automation: WebAutomation) -> Result<()> {
|
||||
let page = automation.new_page().await?;
|
||||
automation.navigate(&page, "https://example.com").await?;
|
||||
let element = automation.get_element(&page, "h1").await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[rstest]
|
||||
#[tokio::test]
|
||||
async fn test_screenshot(automation: WebAutomation) -> Result<()> {
|
||||
let page = automation.new_page().await?;
|
||||
automation.navigate(&page, "https://example.com").await?;
|
||||
let screenshot = automation.screenshot(&page, "test.png").await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -130,7 +130,7 @@ impl ImageProcessor {
|
|||
let mut api = Tesseract::new(None, Some("eng"))
|
||||
.map_err(|e| Error::internal(format!("Failed to initialize Tesseract: {}", e)))?;
|
||||
|
||||
api.set_image(temp_file.path())
|
||||
api.set_image(temp_file.path().to_str().unwrap())
|
||||
.map_err(|e| Error::internal(format!("Failed to set image: {}", e)))?;
|
||||
|
||||
api.recognize()
|
||||
|
|
Loading…
Add table
Reference in a new issue