Skip to content

Commit 20174eb

Browse files
committed
WIP: Implement serve_web
Allows querying the database via http
1 parent 60cc657 commit 20174eb

8 files changed

Lines changed: 172 additions & 13 deletions

File tree

Cargo.lock

Lines changed: 57 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ opcua = {version="0.12.0", features = ["vendored-openssl"]}
5050
url = "2.5.2"
5151
uuid = {version = "1.10.0", features = ["fast-rng", "v4"]}
5252

53+
axum = "0.7.7"
54+
5355
[patch.crates-io]
5456
oxrdf = { git = 'https://github.com/magbak/oxigraph.git', rev = "b13df973ed2785de2ac41066ca4b62d88d3f5d40"}
5557
oxttl = { git = 'https://github.com/magbak/oxigraph.git', rev = "b13df973ed2785de2ac41066ca4b62d88d3f5d40"}

lib/chrontext/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ async-trait.workspace = true
3333
oxigraph.workspace = true
3434
filesize.workspace = true
3535
uuid.workspace = true
36+
axum.workspace = true
37+
tokio.workspace = true
38+
serde.workspace = true
3639

3740
[features]
3841
opcua = ["virtualization/opcua"]

lib/chrontext/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ pub mod rewriting;
1111
pub mod sparql_database;
1212
mod sparql_result_to_polars;
1313
pub mod splitter;
14+
pub mod web;

lib/chrontext/src/sparql_database.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod sparql_endpoint;
44
use crate::sparql_database::sparql_embedded_oxigraph::EmbeddedOxigraphError;
55
use crate::sparql_database::sparql_endpoint::SparqlEndpointQueryExecutionError;
66
use async_trait::async_trait;
7+
use oxigraph::sparql::QueryResults;
78
use sparesults::QuerySolution;
89
use spargebra::Query;
910
use thiserror::Error;

lib/chrontext/src/web.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use std::sync::Arc;
2+
3+
use axum::response::Html;
4+
use axum::Form;
5+
use axum::{self, Router};
6+
use axum::{extract::State, routing::get};
7+
8+
use oxigraph::sparql::{results::QueryResultsFormat, QueryResults, QuerySolutionIter};
9+
use oxrdf::Variable;
10+
use serde::Deserialize;
11+
12+
use crate::sparql_database::SparqlQueryable;
13+
14+
#[derive(Clone)]
15+
struct AppState {
16+
sparql_engine: Arc<(dyn SparqlQueryable)>,
17+
}
18+
19+
pub async fn launch_web(sparql_engine: Arc<(dyn SparqlQueryable)>, address: &str) {
20+
let state = AppState { sparql_engine };
21+
22+
let app: Router = Router::new()
23+
.route("/", get(|| async { "Hello, World!" }))
24+
.route("/query", get(get_query).post(post_query))
25+
.with_state(state);
26+
27+
let listener = tokio::net::TcpListener::bind(address).await.unwrap();
28+
axum::serve(listener, app).await.unwrap();
29+
}
30+
31+
async fn get_query() -> Html<&'static str> {
32+
Html(include_str!("web/sparql.html"))
33+
}
34+
35+
#[derive(Deserialize, Debug)]
36+
struct SparqlQuery {
37+
query: String,
38+
}
39+
40+
async fn post_query(State(state): State<AppState>, Form(form): Form<SparqlQuery>) -> String {
41+
let sparql_engine = state.sparql_engine;
42+
43+
let query = spargebra::Query::parse(&form.query, None).unwrap();
44+
45+
let query_result: QueryResults = match sparql_engine.execute(&query).await {
46+
Ok(v) => {
47+
let variables: Arc<[Variable]> = v.first().unwrap().variables().into();
48+
let iter = v
49+
.into_iter()
50+
.map(|qs| Ok(qs.values().iter().map(|t| t.clone()).collect()));
51+
let qsi = QuerySolutionIter::new(variables, iter);
52+
qsi.into()
53+
}
54+
Err(_) => todo!(),
55+
};
56+
57+
let mut results = Vec::new();
58+
query_result.write(&mut results, QueryResultsFormat::Json);
59+
60+
String::from_utf8_lossy(&results).into()
61+
}

lib/chrontext/src/web/sparql.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!--
2+
From https://github.com/oxigraph/oxigraph/blob/22d956823f6257b7840f2116858e1431393cdf84/cli/templates/query.html
3+
Licensed under Apache 2.0 or MIT
4+
Vincent Emonet
5+
Thomas Tanon
6+
-->
7+
<!DOCTYPE html>
8+
<html lang="en">
9+
<head>
10+
<meta charset="utf-8">
11+
<title>Chrontext - Query</title>
12+
<link href="https://unpkg.com/@zazuko/yasgui@4/build/yasgui.min.css" rel="stylesheet" type="text/css" />
13+
<script src="https://unpkg.com/@zazuko/yasgui@4/build/yasgui.min.js"></script>
14+
<link rel="icon" type="image/svg+xml" href="/logo.svg">
15+
</head>
16+
<body>
17+
<div id="yasgui"></div>
18+
<script>
19+
const url = new URL(window.location.href.endsWith('/') ? window.location.href.slice(0, -1) : window.location.href);
20+
new Yasgui(document.getElementById("yasgui"), {
21+
requestConfig: { endpoint: url.origin + "/query" }
22+
});
23+
</script>
24+
</body>

py_chrontext/src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ static GLOBAL: Jemalloc = Jemalloc;
3535
#[global_allocator]
3636
static GLOBAL: MiMalloc = MiMalloc;
3737

38+
use std::thread;
39+
3840
use crate::errors::PyChrontextError;
3941
use chrontext::engine::{Engine, EngineConfig};
4042
use chrontext::sparql_database::sparql_embedded_oxigraph::EmbeddedOxigraphConfig;
@@ -285,6 +287,27 @@ impl PyEngine {
285287
.unwrap()
286288
.block_on(flight_server.serve(address))
287289
.map_err(|x| PyChrontextError::FlightServerError(x))?;
290+
291+
Ok(())
292+
})
293+
}
294+
295+
pub fn serve_web(&mut self, address: &str, py: Python) -> PyResult<()> {
296+
let address = address.to_owned();
297+
py.allow_threads(move || {
298+
if self.engine.is_none() {
299+
self.init()?;
300+
}
301+
let sparql_database = self.engine.as_mut().unwrap().sparql_database.clone();
302+
thread::spawn(move || {
303+
let mut builder = Builder::new_multi_thread();
304+
builder.enable_all();
305+
builder
306+
.build()
307+
.unwrap()
308+
.block_on(chrontext::web::launch_web(sparql_database, &address));
309+
});
310+
288311
Ok(())
289312
})
290313
}

0 commit comments

Comments
 (0)