Skip to content
This repository was archived by the owner on Apr 20, 2023. It is now read-only.

Commit 6b1ad77

Browse files
committed
indexer-node: Initial commit
Signed-off-by: xphoniex <[email protected]>
1 parent 3eb09d0 commit 6b1ad77

File tree

8 files changed

+626
-0
lines changed

8 files changed

+626
-0
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"org-node",
55
"git-server",
66
"service-init",
7+
"indexer-node",
78
"shared",
89
]
910

indexer-node/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "radicle-indexer-node"
3+
license = "MIT OR Apache-2.0"
4+
version = "0.0.1"
5+
authors = ["Alexis Sellier <[email protected]>"]
6+
edition = "2018"
7+
build = "../build.rs"
8+
default-run = "radicle-indexer-node"
9+
10+
[dependencies]
11+
shared = { path = "../shared", default-features = false }
12+
async-trait = { version = "0.1" }
13+
serde = { version = "1", features = ["derive"] }
14+
serde_json = { version = "1" }
15+
librad = { version = "0" }
16+
tokio = { version = "1.2", features = ["macros", "rt", "sync"] }
17+
thiserror = { version = "1" }
18+
argh = { version = "0.1.4" }
19+
tracing = "0.1"
20+
anyhow = "1.0"
21+
warp = { version = "0.3.1", features = ["tls"] }
22+
rocksdb = "0.17.0"
23+
url = { version = "*" }
24+
git2 = "0.13"

indexer-node/src/db.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use rocksdb::{DBWithThreadMode, Direction, Error, IteratorMode, MultiThreaded, DB};
2+
3+
use std::sync::Arc;
4+
5+
#[derive(Debug, Clone)]
6+
pub struct Handle {
7+
pub db: Arc<DBWithThreadMode<MultiThreaded>>,
8+
}
9+
10+
impl Handle {
11+
/// Creates a DB handle and stores its data at the path (folder).
12+
pub fn from_path(path: &str) -> Result<Handle, Error> {
13+
type MDB = DBWithThreadMode<MultiThreaded>;
14+
let db = MDB::open_default(path)?;
15+
//let db = DB::open_default(path)?;
16+
Ok(Handle { db: Arc::new(db) })
17+
}
18+
19+
/// Key should hold alias::urn, and value holds the server
20+
/// in which repo is hosted.
21+
pub fn add_repository<K, V>(&self, k: K, v: V) -> Result<(), Error>
22+
where
23+
K: AsRef<[u8]>,
24+
V: AsRef<[u8]>,
25+
{
26+
let k = [b"repo::", k.as_ref()].concat();
27+
self.db.put(k, v)
28+
}
29+
30+
/// Iterates through all keys starting with prefix and returns (key, value).
31+
fn iterate_prefix<P>(&self, prefix: P) -> impl Iterator<Item = (String, String)> + '_
32+
where
33+
P: AsRef<[u8]> + 'static,
34+
{
35+
self.db
36+
.iterator(IteratorMode::From(prefix.as_ref(), Direction::Forward))
37+
.into_iter()
38+
.take_while(move |(k, _)| k.starts_with(prefix.as_ref()))
39+
// This is safe because inputs are checked on insertion
40+
// and leaking the Box leaves sole ownership to String.
41+
.map(|(k, v)| unsafe {
42+
let k = Box::leak(k);
43+
let v = Box::leak(v);
44+
(
45+
String::from_raw_parts(k.as_mut_ptr(), k.len(), k.len()),
46+
String::from_raw_parts(v.as_mut_ptr(), v.len(), v.len()),
47+
)
48+
})
49+
}
50+
51+
/// Iterates through all keys starting *from* prefix and returns (key, value).
52+
pub fn iterate_from_prefix<P>(&self, prefix: P) -> impl Iterator<Item = (String, String)> + '_
53+
where
54+
P: AsRef<[u8]> + 'static,
55+
{
56+
self.db
57+
.iterator(IteratorMode::From(prefix.as_ref(), Direction::Forward))
58+
.into_iter()
59+
// This is safe because inputs are checked on insertion
60+
// and leaking the Box leaves sole ownership to String.
61+
.map(|(k, v)| unsafe {
62+
let k = Box::leak(k);
63+
let v = Box::leak(v);
64+
(
65+
String::from_raw_parts(k.as_mut_ptr(), k.len(), k.len()),
66+
String::from_raw_parts(v.as_mut_ptr(), v.len(), v.len()),
67+
)
68+
})
69+
}
70+
71+
/// Lists all repositories' alias::urn (key) and servers (value) hosting them.
72+
pub fn list_repositories(&self) -> impl Iterator<Item = (String, String)> + '_ {
73+
let prefix = b"repo::";
74+
self.iterate_prefix(prefix)
75+
}
76+
77+
/// Lists all repositories starting with alias::<any_urn>.
78+
pub fn repos_starting_with(&self, alias: &str) -> impl Iterator<Item = (String, String)> + '_ {
79+
let prefix = [b"repo::", alias.as_bytes()].concat();
80+
self.iterate_prefix(prefix)
81+
}
82+
83+
/// Lists all users starting with username::<any_urn>.
84+
pub fn users_starting_with(
85+
&self,
86+
username: &str,
87+
) -> impl Iterator<Item = (String, String)> + '_ {
88+
let prefix = [b"user::", username.as_bytes()].concat();
89+
self.iterate_prefix(prefix)
90+
}
91+
92+
/// Key should hold username::urn, and value holds the server
93+
/// in which user is active.
94+
pub fn add_user<K, V>(&self, k: K, v: V) -> Result<(), Error>
95+
where
96+
K: AsRef<[u8]>,
97+
V: AsRef<[u8]>,
98+
{
99+
let k = [b"user::", k.as_ref()].concat();
100+
self.db.put(k, v)
101+
}
102+
}

indexer-node/src/error.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// Errors that may occur when interacting with [`librad::net::peer::Peer`].
2+
#[derive(Debug, thiserror::Error)]
3+
pub enum Error {
4+
/// The entity was not found.
5+
#[error("entity not found")]
6+
NotFound,
7+
8+
/// An error occured while parsing URL.
9+
#[error(transparent)]
10+
ParseError(#[from] url::ParseError),
11+
}
12+
13+
impl warp::reject::Reject for Error {}

indexer-node/src/git.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::process::Command;
2+
3+
pub fn git<S: AsRef<std::ffi::OsStr>>(
4+
repo: &std::path::Path,
5+
args: impl IntoIterator<Item = S>,
6+
) -> Result<String, anyhow::Error> {
7+
let output = Command::new("git").current_dir(repo).args(args).output()?;
8+
9+
if output.status.success() {
10+
let out = if output.stdout.is_empty() {
11+
&output.stderr
12+
} else {
13+
&output.stdout
14+
};
15+
return Ok(String::from_utf8_lossy(out).into());
16+
}
17+
18+
Err(anyhow::Error::new(std::io::Error::new(
19+
std::io::ErrorKind::Other,
20+
String::from_utf8_lossy(&output.stderr),
21+
)))
22+
}

0 commit comments

Comments
 (0)