2026-06-08 19:33:49 -04:00
|
|
|
mod app;
|
2026-08-05 11:21:25 -04:00
|
|
|
mod args;
|
2026-08-08 23:50:04 -04:00
|
|
|
mod error;
|
|
|
|
|
mod navigator;
|
|
|
|
|
mod rdf;
|
|
|
|
|
mod theme;
|
|
|
|
|
mod widget;
|
2026-08-20 20:43:18 -04:00
|
|
|
mod tasks;
|
2026-06-08 19:33:49 -04:00
|
|
|
|
2026-08-13 09:44:46 -04:00
|
|
|
use std::collections::HashMap;
|
2026-08-08 23:50:04 -04:00
|
|
|
use crate::app::Publisher;
|
|
|
|
|
use crate::args::{AppArgs, Command};
|
2026-08-05 11:21:25 -04:00
|
|
|
use clap::Parser;
|
2026-08-12 14:11:47 -04:00
|
|
|
use gl_search::{Schema, SearchIndex};
|
2026-08-05 11:21:25 -04:00
|
|
|
use iced::futures::StreamExt;
|
|
|
|
|
use ldp::middleware::BasicAuthMiddleware;
|
2026-08-13 09:44:46 -04:00
|
|
|
use ldp::reqwest::Client;
|
2026-08-05 11:21:25 -04:00
|
|
|
use ldp::reqwest_middleware::ClientBuilder;
|
|
|
|
|
use ldp::traverse::Traverse;
|
2026-08-13 22:44:37 -04:00
|
|
|
use oxigraph::io::{RdfFormat, RdfParser, RdfSerializer};
|
|
|
|
|
use oxigraph::model::{Dataset, Graph, Triple, TripleRef};
|
2026-08-16 15:50:10 -04:00
|
|
|
use tracing::{debug_span, error, field, Instrument};
|
2026-08-08 23:50:04 -04:00
|
|
|
use tracing_subscriber::fmt::format::FmtSpan;
|
2026-06-08 19:33:49 -04:00
|
|
|
use tracing_subscriber::layer::SubscriberExt;
|
|
|
|
|
use tracing_subscriber::util::SubscriberInitExt;
|
|
|
|
|
use tracing_subscriber::{EnvFilter, fmt};
|
2026-08-13 09:44:46 -04:00
|
|
|
use url::Url;
|
2026-08-16 15:50:10 -04:00
|
|
|
use gl_graph::indexer::Indexer;
|
|
|
|
|
use gl_graph::{language, CurieHelper};
|
2026-08-12 14:11:47 -04:00
|
|
|
use gl_inference::proto::ontology_client::OntologyClient;
|
|
|
|
|
use gl_inference::proto::OntologyQueryRequest;
|
2026-06-08 19:33:49 -04:00
|
|
|
|
|
|
|
|
fn main() -> color_eyre::Result<()> {
|
|
|
|
|
let appender = tracing_appender::rolling::never("/tmp", "publisher-log");
|
|
|
|
|
tracing_subscriber::registry()
|
2026-08-08 23:50:04 -04:00
|
|
|
.with(
|
|
|
|
|
fmt::layer()
|
|
|
|
|
.with_span_events(FmtSpan::CLOSE)
|
|
|
|
|
.with_writer(appender),
|
|
|
|
|
)
|
2026-06-08 19:33:49 -04:00
|
|
|
.with(EnvFilter::from_default_env())
|
|
|
|
|
.init();
|
|
|
|
|
color_eyre::install()?;
|
|
|
|
|
|
2026-08-05 11:21:25 -04:00
|
|
|
let args = AppArgs::parse();
|
|
|
|
|
match args.command {
|
2026-08-07 18:16:03 -04:00
|
|
|
Some(Command::Query(args)) => {
|
2026-08-20 20:43:18 -04:00
|
|
|
let raw_query = if let Some(query) = &args.query_path {
|
|
|
|
|
Some(String::from_utf8(std::fs::read(query)?)?)
|
|
|
|
|
} else { None };
|
2026-08-07 18:16:03 -04:00
|
|
|
|
2026-08-12 14:11:47 -04:00
|
|
|
let graph = if let Some(dataset_path) = &args.dataset_path {
|
|
|
|
|
Some(String::from_utf8(std::fs::read(dataset_path)?)?)
|
|
|
|
|
} else { None };
|
|
|
|
|
|
2026-08-13 09:44:46 -04:00
|
|
|
let mut request = OntologyQueryRequest::default();
|
2026-08-20 20:43:18 -04:00
|
|
|
request.sparql_query = raw_query;
|
2026-08-13 09:44:46 -04:00
|
|
|
request.turtle = graph;
|
|
|
|
|
request.prefixes = HashMap::from_iter(gl_graph::PREFIXES.iter().map(|(name, iri)| (name.clone(), iri.clone())));
|
|
|
|
|
request.base = args.base.clone();
|
2026-08-20 20:43:18 -04:00
|
|
|
request.inferences_only = args.inferences_only;
|
2026-08-13 09:44:46 -04:00
|
|
|
|
2026-08-12 14:11:47 -04:00
|
|
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
|
|
|
|
.enable_all()
|
|
|
|
|
.name("inference-client")
|
|
|
|
|
.build()?;
|
|
|
|
|
|
|
|
|
|
runtime.block_on(async {
|
|
|
|
|
let mut client = OntologyClient::connect("http://[::1]:3000").await.unwrap();
|
|
|
|
|
let response = client.query(request).await.unwrap();
|
|
|
|
|
println!("{}", response.get_ref().results);
|
|
|
|
|
});
|
2026-08-05 11:21:25 -04:00
|
|
|
}
|
2026-08-07 18:16:03 -04:00
|
|
|
Some(Command::Search(args)) => {
|
2026-08-20 20:43:18 -04:00
|
|
|
let mut index = SearchIndex::builder()
|
|
|
|
|
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
|
|
|
|
|
.build()
|
|
|
|
|
.expect("Failed to build search index");
|
|
|
|
|
|
|
|
|
|
let limit = args.limit.unwrap_or(5);
|
|
|
|
|
for document in index.query(args.discriminant, &args.query, Schema::all_fields(), limit)? {
|
2026-08-12 14:11:47 -04:00
|
|
|
println!("{}", gl_search::to_json(document));
|
|
|
|
|
}
|
2026-08-07 18:16:03 -04:00
|
|
|
}
|
2026-08-05 11:21:25 -04:00
|
|
|
Some(Command::Reindex) => {
|
2026-08-20 20:43:18 -04:00
|
|
|
let mut index = SearchIndex::builder()
|
|
|
|
|
.with_path("/home/alex/.local/share/org.graphofliberty.desktop/index")
|
|
|
|
|
.build()
|
|
|
|
|
.expect("Failed to build search index");
|
|
|
|
|
|
2026-08-05 18:33:30 -04:00
|
|
|
let mut writer = index.writer()?;
|
2026-08-05 11:21:25 -04:00
|
|
|
debug_span!("Clear Index").in_scope(|| {
|
|
|
|
|
writer.delete_all_documents()?;
|
|
|
|
|
writer.commit()
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
let runtime = tokio::runtime::Builder::new_multi_thread()
|
|
|
|
|
.enable_all()
|
2026-08-12 14:11:47 -04:00
|
|
|
.name("reindex")
|
2026-08-05 11:21:25 -04:00
|
|
|
.build()?;
|
|
|
|
|
|
2026-08-12 14:11:47 -04:00
|
|
|
runtime.block_on(async {
|
2026-08-16 15:50:10 -04:00
|
|
|
let curie_helper = CurieHelper::new(gl_graph::PREFIXES.clone());
|
|
|
|
|
let indexer = Indexer::new(language::ENGLISH_OR_UNTAGGED.clone(), &curie_helper);
|
|
|
|
|
|
2026-08-13 09:44:46 -04:00
|
|
|
let mut client = OntologyClient::connect("http://[::1]:3000").await?;
|
2026-08-16 15:50:10 -04:00
|
|
|
let documents = indexer.ontology(&mut client).await?;
|
2026-08-12 14:11:47 -04:00
|
|
|
debug_span!("Index Ontology", documents = field::Empty).in_scope(|| {
|
|
|
|
|
for document in documents {
|
|
|
|
|
writer.add_document(document).unwrap();
|
|
|
|
|
}
|
|
|
|
|
});
|
2026-08-13 09:44:46 -04:00
|
|
|
Ok::<_, crate::error::Error>(())
|
|
|
|
|
})?;
|
2026-08-12 14:11:47 -04:00
|
|
|
|
|
|
|
|
let mut writer = runtime.block_on(async move {
|
2026-08-05 11:21:25 -04:00
|
|
|
let http_client = ClientBuilder::new(Client::new())
|
|
|
|
|
.with(BasicAuthMiddleware::new(
|
|
|
|
|
"fedoraAdmin".to_string(),
|
|
|
|
|
Some("fedoraAdmin".to_string()),
|
|
|
|
|
))
|
|
|
|
|
.build();
|
|
|
|
|
|
2026-08-13 09:44:46 -04:00
|
|
|
let starting_url = Url::parse("http://fedora.quill.lan/rest/")?;
|
2026-08-07 18:16:03 -04:00
|
|
|
let mut dataset = Dataset::new();
|
2026-08-05 11:21:25 -04:00
|
|
|
let mut traversal = Traverse::new(http_client, starting_url, None);
|
2026-08-13 09:44:46 -04:00
|
|
|
let mut rdf_source_count = 0usize;
|
2026-08-05 11:21:25 -04:00
|
|
|
while let Some(result) = traversal.next().await {
|
|
|
|
|
match result {
|
2026-08-13 09:44:46 -04:00
|
|
|
Ok(rdf_source) => {
|
|
|
|
|
dataset.extend(rdf_source.dataset());
|
|
|
|
|
rdf_source_count += 1;
|
|
|
|
|
},
|
2026-08-05 11:21:25 -04:00
|
|
|
Err(err) => error!(?err),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-07 18:16:03 -04:00
|
|
|
|
2026-08-13 22:44:37 -04:00
|
|
|
let span = debug_span!("Index Repository", rdf_sources = rdf_source_count, triples = field::Empty, documents = field::Empty);
|
|
|
|
|
let triple_count = async {
|
2026-08-16 15:50:10 -04:00
|
|
|
let curie_helper = CurieHelper::new(gl_graph::PREFIXES.clone());
|
|
|
|
|
let indexer = Indexer::new(language::ENGLISH_OR_UNTAGGED.clone(), &curie_helper);
|
|
|
|
|
|
|
|
|
|
let mut client = OntologyClient::connect("http://[::1]:3000").await?;
|
2026-08-13 22:44:37 -04:00
|
|
|
let mut request = OntologyQueryRequest::default();
|
|
|
|
|
|
|
|
|
|
let mut output_buffer = Vec::new();
|
|
|
|
|
let mut serializer = RdfSerializer::from_format(RdfFormat::Turtle)
|
|
|
|
|
.for_writer(output_buffer);
|
|
|
|
|
for quad in &dataset {
|
|
|
|
|
serializer.serialize_triple(TripleRef::from(quad))?;
|
|
|
|
|
}
|
|
|
|
|
output_buffer = serializer.finish()?;
|
|
|
|
|
let turtle = String::from_utf8_lossy(&output_buffer).to_string();
|
|
|
|
|
|
|
|
|
|
request.sparql_query = None;
|
|
|
|
|
request.turtle = Some(turtle);
|
|
|
|
|
request.prefixes = HashMap::new();
|
|
|
|
|
request.base = None;
|
2026-08-20 20:43:18 -04:00
|
|
|
request.inferences_only = false;
|
2026-08-13 22:44:37 -04:00
|
|
|
|
2026-08-16 15:50:10 -04:00
|
|
|
let response = client.query(request).await?;
|
2026-08-13 22:44:37 -04:00
|
|
|
let graph_with_inferences = RdfParser::from_format(RdfFormat::Turtle)
|
|
|
|
|
.for_slice(&response.get_ref().results)
|
|
|
|
|
.filter_map(Result::ok)
|
|
|
|
|
.map(Triple::from)
|
|
|
|
|
.collect::<Graph>();
|
|
|
|
|
|
2026-08-16 21:42:14 -04:00
|
|
|
for document in indexer.graph(&graph_with_inferences)? {
|
2026-08-16 15:50:10 -04:00
|
|
|
writer.add_document(document)?;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-13 22:44:37 -04:00
|
|
|
Ok::<usize, crate::error::Error>(graph_with_inferences.len())
|
|
|
|
|
}.instrument(span.clone()).await?;
|
|
|
|
|
span.record("triples", triple_count);
|
|
|
|
|
|
2026-08-13 09:44:46 -04:00
|
|
|
Ok::<_, crate::error::Error>(writer)
|
2026-08-12 14:11:47 -04:00
|
|
|
})?;
|
2026-08-05 11:21:25 -04:00
|
|
|
|
2026-08-08 23:50:04 -04:00
|
|
|
debug_span!("Commit").in_scope(|| writer.commit())?;
|
2026-08-05 11:21:25 -04:00
|
|
|
}
|
|
|
|
|
None => {
|
|
|
|
|
iced::daemon(Publisher::new, Publisher::update, Publisher::view)
|
|
|
|
|
.title(Publisher::title)
|
|
|
|
|
.subscription(Publisher::subscription)
|
|
|
|
|
.run()?;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-08 19:33:49 -04:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|