DK6254GRWC6DVMLYWI5WSKDFX2EE4R24ZT3IQWIWJJUIOKKVKWMQC
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2019 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
mod rdf {
pub static TYPE: &str = "http://www.w3.org/1999/02/22-rdf-syntax-ns#type";
}
mod ldp {
pub static CONTAINER: &str = "http://www.w3.org/ns/ldp#Container";
pub static RESOURCE: &str = "http://www.w3.org/ns/ldp#Resource";
pub static BASIC_CONTAINER: &str = "http://www.w3.org/ns/ldp#BasicContainer";
pub static CONTAINS: &str = "http://www.w3.org/ns/ldp#contains";
}
mod stat {
pub static FILE: &str = "http://www.w3.org/ns/posix/stat#File";
pub static DIR: &str = "http://www.w3.org/ns/posix/stat#Directory";
pub static MTIME: &str = "http://www.w3.org/ns/posix/stat#mtime";
pub static SIZE: &str = "http://www.w3.org/ns/posix/stat#size";
}
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2020 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
use crate::SETTINGS;
use fehler::throws;
use http_types::{ensure, Error};
#[throws]
pub async fn create_container() {}
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2020 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
use crate::files;
use crate::{SETTINGS, STORE};
use async_std::{fs, io::ErrorKind, net::SocketAddr, path::Path, path::PathBuf};
use fehler::{throw, throws};
use http_types::{ensure, Error};
use itertools::iproduct;
use oxigraph::store::rocksdb::RocksDbStore;
#[derive(Debug)]
pub struct Config {
/// Path where uploaded files are stored
pub file_path: PathBuf,
/// Path to the RDF tuplestore
pub db_path: PathBuf,
/// Address to bind the socket to
pub addr: SocketAddr,
}
#[throws]
fn configure() {
let mut settings = config::Config::default();
settings.set_default("file_path", "/srv/sparqlpuppy/files/")?;
settings.set_default("db_path", "/srv/sparqlpuppy/db/")?;
settings.set_default("addr", "127.0.0.1:8080")?;
settings.merge(config::Environment::with_prefix("SPARQLPUPPY"))?;
SETTINGS
.set(Config {
file_path: settings.get_str("file_path")?.into(),
db_path: settings.get_str("db_path")?.into(),
addr: settings.get_str("addr")?.parse()?,
})
.unwrap()
}
#[throws]
async fn mkhier(path: impl AsRef<Path>) {
let m = fs::metadata(&path).await;
match m {
Err(e) => {
if e.kind() == ErrorKind::NotFound {
fs::create_dir_all(&path).await?
} else {
throw!(e)
}
}
Ok(m) => ensure!(
m.is_dir(),
"{:?} exists but is not a directory",
path.as_ref()
),
}
}
#[throws]
async fn create_filehier() {
let settings = SETTINGS.get().unwrap();
let hexits = [
Path::new("0"),
Path::new("1"),
Path::new("2"),
Path::new("3"),
Path::new("4"),
Path::new("5"),
Path::new("6"),
Path::new("7"),
Path::new("8"),
Path::new("9"),
Path::new("a"),
Path::new("b"),
Path::new("c"),
Path::new("d"),
Path::new("e"),
Path::new("f"),
];
let base = settings.file_path.as_path();
for (i, j, k) in iproduct!(&hexits, &hexits, &hexits) {
let path: PathBuf = [base, i, j, k].iter().collect();
mkhier(path).await?
}
let path: PathBuf = [base, Path::new("ephem")].iter().collect();
fs::remove_dir_all(&path).await?;
mkhier(path).await?;
}
#[throws]
pub async fn setup() {
configure()?;
create_filehier().await?;
let settings = SETTINGS.get().unwrap();
ensure!(
STORE.set(RocksDbStore::open(&settings.db_path)?).is_ok(),
"Can't happen: Unable to store database handle."
);
}
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2019 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
use http_types::Result;
use rio_api::formatter::TriplesFormatter;
use rio_api::model::{Literal, NamedNode, Triple};
use rio_turtle::TurtleFormatter;
use std::fs::Metadata;
use std::io::Write;
use std::time::SystemTime;
use crate::urls::{
BASIC_CONTAINER, CONTAINER, CONTAINS, STAT_DIR, STAT_FILE, STAT_MTIME, STAT_SIZE, TYPE,
};
pub fn is_container<W: Write>(formatter: &mut TurtleFormatter<W>, iri: &str) -> Result<()> {
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: TYPE },
object: NamedNode { iri: CONTAINER }.into(),
})?;
Ok(())
}
pub fn is_basic_container<W: Write>(formatter: &mut TurtleFormatter<W>, iri: &str) -> Result<()> {
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: TYPE },
object: NamedNode {
iri: BASIC_CONTAINER,
}
.into(),
})?;
Ok(())
}
pub fn contains<W: Write>(formatter: &mut TurtleFormatter<W>, c: &str, d: &str) -> Result<()> {
formatter.format(&Triple {
subject: NamedNode { iri: c }.into(),
predicate: NamedNode { iri: CONTAINS },
object: NamedNode { iri: d }.into(),
})?;
Ok(())
}
pub fn posix<W: Write>(formatter: &mut TurtleFormatter<W>, iri: &str, m: &Metadata) -> Result<()> {
if m.is_file() {
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: TYPE },
object: NamedNode { iri: STAT_FILE }.into(),
})?;
} else if m.is_dir() {
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: TYPE },
object: NamedNode { iri: STAT_DIR }.into(),
})?;
}
if let Ok(mt) = m.modified() {
if let Ok(mtime) = mt.duration_since(SystemTime::UNIX_EPOCH) {
let secs = mtime.as_secs().to_string();
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: STAT_MTIME },
object: Literal::Simple { value: &secs }.into(),
})?;
}
}
let len = m.len().to_string();
formatter.format(&Triple {
subject: NamedNode { iri }.into(),
predicate: NamedNode { iri: STAT_SIZE },
object: Literal::Simple { value: &len }.into(),
})?;
Ok(())
}
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2020 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
#![forbid(unsafe_code)]
mod files;
mod setup;
mod store;
mod urls;
use crate::setup::Config;
use async_std::{
net::{TcpListener, TcpStream},
prelude::*,
task,
};
use fehler::throws;
use http_types::{Error, Request, Response, StatusCode};
use once_cell::sync::OnceCell;
use oxigraph::store::rocksdb::RocksDbStore;
static SETTINGS: OnceCell<Config> = OnceCell::new();
static STORE: OnceCell<RocksDbStore> = OnceCell::new();
#[throws]
#[async_std::main]
async fn main() {
setup::setup().await?;
let settings = SETTINGS.get().unwrap();
let listener = TcpListener::bind(&settings.addr).await?;
// For each incoming TCP connection, spawn a task and call `accept`.
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
let stream = stream?;
task::spawn(async {
if let Err(err) = accept(stream).await {
eprintln!("{}", err);
}
});
}
}
#[throws]
async fn accept(stream: TcpStream) {
async_h1::accept(stream.clone(), |req| async { req_handler(req).await }).await?;
}
pub static BASIC_CONTAINER: &str = "<http://www.w3.org/ns/ldp#BasicContainer>; rel=\"type\"";
// static RESOURCE: &str =
// "<http://www.w3.org/ns/ldp#Resource>; rel=\"type\"";
// static TURTLE_TYPE: &str = "text/turtle; charset=UTF-8";
// static ALLOWABLES: &str = "OPTIONS,HEAD,GET,POST,PUT,PATCH";
// static PATCHABLES: &str = "text/ldpatch";
// static POSTABLES: &str = "text/turtle, application/ld+json, image/bmp, image/jpeg";
#[throws]
async fn req_handler(_req: Request) -> Response {
// let reqpath = req.url().path().trim_start_matches('/');
return Response::new(StatusCode::Ok);
}
// sparqlpuppy - an LDP/SOLID Server
// Copyright (C) 2020 Azure <azure@fox.blue>
//
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <https://www.gnu.org/licenses/>.
use crate::SETTINGS;
use fehler::throws;
use http_types::{ensure, Error};
# sparqlpuppy
sparqlpuppy is written in Rust and wants to be a Linked Data
Platform/SoLiD server when it grows up.
## Installation
Fetch from https://git.sr.ht/~azure/sparqlpuppy and build with cargo.
## Usage
sparqlpuppy is configured with environment
variables. `SPARQLPUPPY_LISTEN`, defaulting to `127.0.0.1:8080`, and
`SPARQLPUPPY_ROOT`, defaulting to, `/srv/ldp`.
## Contributing
Patchsets are welcome. For major changes, please open an issue first
to discuss what you would like to change.
Please make sure to update tests as appropriate.
## License
[AGPL3](https://www.gnu.org/licenses/agpl-3.0.en.html)
[package]
name = "sparqlpuppy"
version = "0.1.0"
authors = ["Azure <azure@fox.blue>"]
edition = "2018"
publish = false
description = "An experimental SOLID Server"
license = "AGPL-3.0-or-later"
repository = "https://git.sr.ht/~azure/sparqlpuppy"
readme = "README.md"
[dependencies]
async-h1 = "^2.1"
async-native-tls = "~0.3"
async-std = { version = "^1.6", features = ["attributes", "unstable"] }
config = "~0.10"
fehler = "^1"
futures = "~0.3"
http-types = "^2.4.0"
itertools = "~0.9"
mime = "~0.3"
once_cell = "^1.4"
oxigraph = { version = "~0.1", features = ["rocksdb"] }
rio_api = "~0.5"
rio_turtle = "~0.5"
[profile.release]
lto = "fat"
codegen-units = 1
# The Rust Code of Conduct #
The Code of Conduct for this repository [can be found
online](https://www.rust-lang.org/conduct.html).