cyrtophora

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 6a5cc7e7251db3ccd0be39355336c5601345d14c
parent 21d82c8b7c83fd7e70caa8f05873d456a6e7e4b6
Author: Jackson G. Kaindume <kaindume@kwatafana.org>
Date:   Wed, 31 Aug 2022 19:46:27 +0200

[phora] initial database integration

Diffstat:
M.gitignore | 1+
Mphora/Cargo.lock | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mphora/Cargo.toml | 8++++++--
Aphora/src/database/#error.rs# | 22++++++++++++++++++++++
Aphora/src/database/error.rs | 22++++++++++++++++++++++
Aphora/src/database/mod.rs | 12++++++++++++
Aphora/src/database/sqlite.rs | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mphora/src/lib.rs | 1+
Aspec/database.md | 12++++++++++++
Aspec/sqlite-support.md | 17+++++++++++++++++
10 files changed, 255 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ *~ phora/target /Cargo.lock +test-data diff --git a/phora/Cargo.lock b/phora/Cargo.lock @@ -12,6 +12,17 @@ dependencies = [ ] [[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] name = "anyhow" version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -30,6 +41,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bdca834647821e0b13d9539a8634eb62d3501b6b6c2cec1722786ee6671b851" [[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] name = "block-buffer" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -127,6 +144,7 @@ dependencies = [ "base64", "chacha20poly1305", "ring", + "rusqlite", "scrypt", "serde", ] @@ -143,6 +161,18 @@ dependencies = [ ] [[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] name = "generic-array" version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -164,6 +194,24 @@ dependencies = [ ] [[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452c155cb93fecdfb02a73dd57b5d8e442c2063bd7aac72f1bc5e4263a43086" +dependencies = [ + "hashbrown", +] + +[[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -197,6 +245,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7" [[package]] +name = "libsqlite3-sys" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0455f2c1bc9a7caa792907026e469c1d91761fb0ea37cbb16427c77280cf35" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -238,6 +296,12 @@ dependencies = [ ] [[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] name = "poly1305" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -291,6 +355,20 @@ dependencies = [ ] [[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] name = "salsa20" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -344,6 +422,12 @@ dependencies = [ ] [[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -395,6 +479,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/phora/Cargo.toml b/phora/Cargo.toml @@ -9,4 +9,8 @@ ring = "0.16.20" chacha20poly1305 = "0.9.0" base64 = "0.13.0" scrypt = "0.10.0" -serde = { version = "1.0.144", features = ["derive"] } -\ No newline at end of file +serde = { version = "1.0.144", features = ["derive"] } +rusqlite = { version = "0.28.0", optional = true } + +[features] +sqlite = ["dep:rusqlite"] +\ No newline at end of file diff --git a/phora/src/database/#error.rs# b/phora/src/database/#error.rs# @@ -0,0 +1,22 @@ +use std::fmt; + +#[derive(Debug)] +pub enum DatabaseError { + ConnectionError, +} + +impl std::error::Error for DatabaseError {} + +impl fmt::Display for DatabaseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DatabaseError::ConnectionError => write!(f, "Database connection error"), + } + } +} + +impl From<rusqlite::> for CrawlError { + fn from(_: web3::error::Error) -> Self { + CrawlError::RPCConnection + } +} diff --git a/phora/src/database/error.rs b/phora/src/database/error.rs @@ -0,0 +1,22 @@ +use std::fmt; + +#[derive(Debug)] +pub enum DatabaseError { + ConnectionError, +} + +impl std::error::Error for DatabaseError {} + +impl fmt::Display for DatabaseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + DatabaseError::ConnectionError => write!(f, "Database connection error"), + } + } +} + +impl From<rusqlite::Error> for DatabaseError { + fn from(_: rusqlite::Error) -> Self { + DatabaseError::ConnectionError + } +} diff --git a/phora/src/database/mod.rs b/phora/src/database/mod.rs @@ -0,0 +1,12 @@ +use error::DatabaseError; +pub mod error; + +pub trait DB { + /// New database instance + fn new(path: &str) -> Self; + /// Connect to database + fn connect(&mut self) -> Result<(), DatabaseError>; +} + +#[cfg(feature = "sqlite")] +pub mod sqlite; diff --git a/phora/src/database/sqlite.rs b/phora/src/database/sqlite.rs @@ -0,0 +1,72 @@ +use super::{error::DatabaseError, DB}; +use rusqlite::{params, Connection, Result}; +use std::fmt; + +pub mod accounts_sql { + /// Cyrtophora Account Schema + pub const CREATE_ACCOUNTS_TABLE: &str = " + CREATE TABLE IF NOT EXISTS accounts ( + id INTEGER PRIMARY KEY, -- The Identifier of the User, the Rust Type is `i64` + name TEXT, -- Fullname of the account + username TEXT UNIQUE NOT NULL, -- The username of the User + email TEXT UNIQUE, -- Users's email address + password TEXT NOT NULL, -- The user's login password + joined TEXT DEFAULT(date('now')) NOT NULL) -- The date when the user joined, the Rust Type is `chrono::DateTime`"; + + /// Insert a user in the users table + pub const CREATE_ACCOUNT: &str = " + INSERT INTO accounts ( + name, + username, + password, + email + ) + VALUES (?1, ?2, ?3, ?4)"; + + /// Get by username + pub const GET_ACCOUNT: &str = "SELECT * FROM accounts WHERE username = :username;"; + + /// Drop accounts table + pub const DESTROY_ACCOUNTS: &str = "DROP table accounts"; +} + +/// database controller +pub struct SqliteDB { + /// Database file path + path: String, + /// An SQLite connection handle + conn: Option<Connection>, +} + +impl DB for SqliteDB { + fn new(path: &str) -> Self { + SqliteDB { + path: path.to_string(), + conn: None, + } + } + + fn connect(&mut self) -> Result<(), DatabaseError> { + let conn = Connection::open(self.path.clone())?; + self.conn = Some(conn); + Ok(()) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn connect_db() { + let mut db = SqliteDB::new("test-data/ACCOUNTS.db"); + + // Connect to database + db.connect().unwrap(); + + match db.conn { + Some(_conn) => assert!(true), + _ => assert!(false), + } + } +} diff --git a/phora/src/lib.rs b/phora/src/lib.rs @@ -2,4 +2,5 @@ pub mod account; pub mod api; pub mod crypto; pub mod data; +pub mod database; pub mod validate; diff --git a/spec/database.md b/spec/database.md @@ -0,0 +1,12 @@ +--- +title: Database +subtitle: +author: Jackson G. Kaindume +date: 2022-08-31 +... +--- + +Cyrtophora stores structured data in a database. The following data is +is stored: + +1. Accounts diff --git a/spec/sqlite-support.md b/spec/sqlite-support.md @@ -0,0 +1,17 @@ +--- +title: Sqlite Support +subtitle: +author: Jackson G. Kaindume +date: 2022-08-31 +... +--- + +Sqlite is supported in cyrtophora as an optional feature: + +```toml +cyrtophora = { path = "../../cyrtophora/phora", features = ["sqlite"] } +``` +When the sqlite feature is enabled user account data will be saved in +a sqlite database. + +