Aldonu datumbazon kaj sesia-administradon
This commit is contained in:
parent
e48ed1f2dd
commit
823a701a2f
|
@ -1,2 +1,3 @@
|
|||
node_modules
|
||||
target
|
||||
*.db
|
||||
|
|
|
@ -2,6 +2,23 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom 0.2.3",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.52"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84450d0b4a8bd1ba4144ce8ce718fbc5d071358b1e5384bace6536b3d1f2d5b3"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
@ -84,6 +101,18 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[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 = "fnv"
|
||||
version = "1.0.7"
|
||||
|
@ -219,6 +248,18 @@ name = "hashbrown"
|
|||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
|
@ -361,6 +402,10 @@ checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
|
|||
name = "kampanja-kontrolada-servilo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"rusqlite",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"uuid",
|
||||
"warp",
|
||||
|
@ -378,6 +423,16 @@ version = "0.2.103"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.23.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cafc7c74096c336d9d27145f7ebd4f4b6f95ba16aa5a282387267e6925cb58"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.5"
|
||||
|
@ -558,6 +613,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.10"
|
||||
|
@ -687,6 +748,21 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ba4d3462c8b2e4d7f4fcfcf2b296dc6b65404fbbc7b63daa37fd485c149daf7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"memchr",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
@ -1058,6 +1134,12 @@ dependencies = [
|
|||
"getrandom 0.2.3",
|
||||
]
|
||||
|
||||
[[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.3"
|
||||
|
|
|
@ -6,6 +6,12 @@ edition = "2018"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1" }
|
||||
rusqlite = { version = "0.26" }
|
||||
thiserror = { version = "1" }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
warp = { version = "0.3.1" }
|
||||
uuid = { version = "0.8", features = ["v4"] }
|
||||
warp = { version = "0.3" }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { version = "3" }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use crate::datumbazo::Datumbazo;
|
||||
use rusqlite::OptionalExtension;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
convert::Infallible,
|
||||
|
@ -30,6 +32,21 @@ impl From<Ĵetono> for String {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct UzantIdentigilo(String);
|
||||
|
||||
impl From<&str> for UzantIdentigilo {
|
||||
fn from(s: &str) -> Self {
|
||||
UzantIdentigilo(s.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UzantIdentigilo> for String {
|
||||
fn from(s: UzantIdentigilo) -> Self {
|
||||
s.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct Uzantnomo(String);
|
||||
|
||||
|
@ -45,33 +62,95 @@ impl From<Uzantnomo> for String {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait AŭtentigoDB: Clone + Send + Sync {
|
||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<Uzantnomo>;
|
||||
pub trait AŭtentigoDB: Send {
|
||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)>;
|
||||
|
||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono;
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MemAŭtentigo {
|
||||
mem: HashMap<Ĵetono, Uzantnomo>,
|
||||
sesioj: HashMap<Ĵetono, UzantIdentigilo>,
|
||||
uzantoj: HashMap<UzantIdentigilo, Uzantnomo>,
|
||||
inversa_uzantoj: HashMap<Uzantnomo, UzantIdentigilo>,
|
||||
}
|
||||
|
||||
impl MemAŭtentigo {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mem: HashMap::new(),
|
||||
sesioj: HashMap::new(),
|
||||
uzantoj: HashMap::new(),
|
||||
inversa_uzantoj: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AŭtentigoDB for MemAŭtentigo {
|
||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<Uzantnomo> {
|
||||
self.mem.get(&ĵetono).cloned()
|
||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
||||
let identigilo = self.sesioj.get(&ĵetono).cloned()?;
|
||||
let uzantnomo = self.uzantoj.get(&identigilo).cloned()?;
|
||||
Some((identigilo, uzantnomo))
|
||||
}
|
||||
|
||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono {
|
||||
let identigilo = self.inversa_uzantoj.get(&uzantnomo).cloned().unwrap();
|
||||
let ĵetono = Ĵetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||
self.sesioj.insert(ĵetono.clone(), identigilo);
|
||||
ĵetono
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DBAŭtentigo {
|
||||
pool: Datumbazo,
|
||||
}
|
||||
|
||||
impl DBAŭtentigo {
|
||||
pub fn kreu(pool: Datumbazo) -> Self {
|
||||
DBAŭtentigo { pool }
|
||||
}
|
||||
}
|
||||
|
||||
impl AŭtentigoDB for DBAŭtentigo {
|
||||
fn aŭtentigu(&self, ĵetono: Ĵetono) -> Option<(UzantIdentigilo, Uzantnomo)> {
|
||||
let konekto = self.pool.konektu().unwrap();
|
||||
konekto
|
||||
.query_row(
|
||||
"SELECT uzantoj.id, uzantoj.nomo FROM sesioj INNER JOIN uzantoj on sesioj.uzanto == uzantoj.id WHERE sesioj.id = ?",
|
||||
[String::from(ĵetono)],
|
||||
|row| {
|
||||
let identigilo = row.get("id")
|
||||
.map(|s: String| UzantIdentigilo::from(s.as_str())).unwrap();
|
||||
let nomo = row.get("nomo")
|
||||
.map(|s: String| Uzantnomo::from(s.as_str())).unwrap();
|
||||
Ok((identigilo, nomo))
|
||||
},
|
||||
)
|
||||
.optional()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn kreu_ĵetono(&mut self, uzantnomo: Uzantnomo) -> Ĵetono {
|
||||
let ĵetono = Ĵetono::from(format!("{}", Hyphenated::from_uuid(Uuid::new_v4())).as_str());
|
||||
self.mem.insert(ĵetono.clone(), uzantnomo);
|
||||
let mut konekto = self.pool.konektu().unwrap();
|
||||
let tr = konekto.transaction().unwrap();
|
||||
let uzanta_id: Option<String> = tr
|
||||
.query_row(
|
||||
"SELECT id FROM uzantoj WHERE nomo = ?",
|
||||
[String::from(uzantnomo.clone())],
|
||||
|row| row.get("id"),
|
||||
)
|
||||
.optional()
|
||||
.unwrap();
|
||||
match uzanta_id {
|
||||
None => panic!("uzanto ne ekzistas"),
|
||||
Some(id) => {
|
||||
tr.execute(
|
||||
"INSERT INTO sesioj VALUES(?, ?)",
|
||||
[String::from(ĵetono.clone()), id],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
tr.commit().unwrap();
|
||||
ĵetono
|
||||
}
|
||||
}
|
||||
|
@ -82,8 +161,8 @@ pub struct AŭtentigoPostulas;
|
|||
impl Reject for AŭtentigoPostulas {}
|
||||
|
||||
pub fn kun_aŭtentigo(
|
||||
auth_ctx: Arc<RwLock<impl AŭtentigoDB>>,
|
||||
) -> impl Filter<Extract = (Uzantnomo,), Error = Rejection> + Clone {
|
||||
auth_ctx: Arc<RwLock<impl AŭtentigoDB + Sync>>,
|
||||
) -> impl Filter<Extract = ((UzantIdentigilo, Uzantnomo),), Error = Rejection> + Clone {
|
||||
let auth_ctx = auth_ctx.clone();
|
||||
warp::header("authentication").and_then({
|
||||
let auth_ctx = auth_ctx.clone();
|
||||
|
@ -91,7 +170,7 @@ pub fn kun_aŭtentigo(
|
|||
let auth_ctx = auth_ctx.clone();
|
||||
async move {
|
||||
match auth_ctx.read().unwrap().aŭtentigu(text) {
|
||||
Some(uzantnomo) => Ok(uzantnomo),
|
||||
Some(salutiloj) => Ok(salutiloj),
|
||||
None => Err(reject::custom(AŭtentigoPostulas)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
use rusqlite::{params, Connection};
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
path::PathBuf,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
pub struct ManagedConnection<'a> {
|
||||
pool: &'a Datumbazo,
|
||||
konekto: Option<Connection>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Datumbazo {
|
||||
dosierindiko: PathBuf,
|
||||
pool: Arc<Mutex<Vec<Connection>>>,
|
||||
}
|
||||
|
||||
impl Datumbazo {
|
||||
pub fn kreu(dosierindiko: PathBuf) -> Result<Datumbazo, anyhow::Error> {
|
||||
let mut konekto = Connection::open(dosierindiko.clone())?;
|
||||
|
||||
let tx = konekto.transaction()?;
|
||||
let versio: i32 = tx.pragma_query_value(None, "user_version", |r| r.get(0))?;
|
||||
println!("versio: {}", versio);
|
||||
if versio == 0 {
|
||||
tx.execute_batch(
|
||||
"CREATE TABLE uzantoj (id string primary key, nomo text);
|
||||
CREATE TABLE rajtoj (uzanto string, rajto string, foreign key(uzanto) references uzanto(id));
|
||||
CREATE TABLE sesioj (id string primary key not null, uzanto string, foreign key(uzanto) references uzantoj(id));
|
||||
PRAGMA user_version = 1;",
|
||||
)?;
|
||||
}
|
||||
let versio: i32 = tx.pragma_query_value(None, "user_version", |r| r.get(0))?;
|
||||
println!("versio: {}", versio);
|
||||
|
||||
tx.commit()?;
|
||||
|
||||
Ok(Datumbazo {
|
||||
dosierindiko,
|
||||
pool: Arc::new(Mutex::new(vec![konekto])),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn konektu<'a>(&'a self) -> Result<ManagedConnection<'a>, anyhow::Error> {
|
||||
let mut pool = self.pool.lock().unwrap();
|
||||
match pool.pop() {
|
||||
Some(konekto) => Ok(ManagedConnection {
|
||||
pool: &self,
|
||||
konekto: Some(konekto),
|
||||
}),
|
||||
None => {
|
||||
let konekto = Connection::open(self.dosierindiko.clone())?;
|
||||
Ok(ManagedConnection {
|
||||
pool: &self,
|
||||
konekto: Some(konekto),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn revenu(&self, konekto: Connection) {
|
||||
let mut pool = self.pool.lock().unwrap();
|
||||
pool.push(konekto);
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ManagedConnection<'_> {
|
||||
type Target = Connection;
|
||||
|
||||
fn deref(&self) -> &Connection {
|
||||
self.konekto.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ManagedConnection<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Connection {
|
||||
self.konekto.as_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ManagedConnection<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.pool.revenu(self.konekto.take().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn povas_krei_uzanton() {
|
||||
let vojo = NamedTempFile::new().unwrap().into_temp_path();
|
||||
let datumbazo = Datumbazo::kreu(vojo.to_path_buf()).unwrap();
|
||||
let mut konekto = datumbazo.konektu().unwrap();
|
||||
let tr = konekto.transaction().unwrap();
|
||||
tr.execute(
|
||||
"INSERT INTO uzantoj VALUES(?, ?)",
|
||||
params![1, String::from("mia-uzantnomo")],
|
||||
)
|
||||
.unwrap();
|
||||
tr.commit().unwrap();
|
||||
|
||||
let konekto = datumbazo.konektu().unwrap();
|
||||
let id: Option<u32> = konekto
|
||||
.query_row(
|
||||
"SELECT id FROM uzantoj WHERE nomo = ?",
|
||||
[String::from("mia-uzantnomo")],
|
||||
|row| row.get("id"),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(id, Some(1));
|
||||
}
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
use std::convert::Infallible;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use warp::{Filter, Rejection};
|
||||
|
||||
#[path = "aŭtentigo.rs"]
|
||||
mod aŭtentigo;
|
||||
use aŭtentigo::{kun_aŭtentigo, AŭtentigoDB, AŭtentigoPostulas, MemAŭtentigo, Uzantnomo};
|
||||
use aŭtentigo::{kun_aŭtentigo, AŭtentigoDB, AŭtentigoPostulas, Uzantnomo};
|
||||
|
||||
mod datumbazo;
|
||||
use datumbazo::Datumbazo;
|
||||
|
||||
use crate::rajtigo::{MemRajtigo, Rajtigo, Rajto};
|
||||
mod rajtigo;
|
||||
use rajtigo::{DBRajtigo, Rajtigo, Rajto};
|
||||
|
||||
use crate::aŭtentigo::{DBAŭtentigo, UzantIdentigilo};
|
||||
|
||||
async fn traktilo_de_listigu_ludantojn(
|
||||
uzantnomo: Uzantnomo,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtigo: Arc<RwLock<impl Rajtigo>>,
|
||||
) -> Result<impl warp::Reply, Rejection> {
|
||||
if rajtigo.read().unwrap().havas_rajton(uzantnomo, |rajtoj| {
|
||||
rajtoj.fold(false, |acc, r| acc || *r == Rajto::from("admin"))
|
||||
if rajtigo.read().unwrap().havas_rajton(identigilo, |rajtoj| {
|
||||
rajtoj.fold(false, |acc, r| acc || r == Rajto::from("admin"))
|
||||
}) {
|
||||
Ok(warp::reply::json(&vec!["Alice", "Betty", "Charles"]))
|
||||
} else {
|
||||
|
@ -42,17 +48,15 @@ async fn traktilu_erarojn(err: Rejection) -> Result<impl warp::Reply, Infallible
|
|||
|
||||
#[tokio::main]
|
||||
pub async fn main() {
|
||||
let auth_ctx = Arc::new(RwLock::new(MemAŭtentigo::new()));
|
||||
let db = Datumbazo::kreu(PathBuf::from("../servilo.db")).unwrap();
|
||||
|
||||
let auth_ctx = Arc::new(RwLock::new(DBAŭtentigo::kreu(db.clone())));
|
||||
let ĵetono = auth_ctx
|
||||
.write()
|
||||
.unwrap()
|
||||
.kreu_ĵetono(Uzantnomo::from("Savanni"));
|
||||
.kreu_ĵetono(Uzantnomo::from("savanni"));
|
||||
println!("ĵetono: {}", String::from(ĵetono));
|
||||
let rajtigo = Arc::new(RwLock::new(MemRajtigo::new()));
|
||||
rajtigo.write().unwrap().aldonu_rajtoj(
|
||||
Uzantnomo::from("Savanni"),
|
||||
&mut (vec![Rajto::from("admin")].into_iter()),
|
||||
);
|
||||
let rajtigo = Arc::new(RwLock::new(DBRajtigo::kreu(db)));
|
||||
|
||||
let listigu_ludantojn = {
|
||||
let auth_ctx = auth_ctx.clone();
|
||||
|
@ -60,9 +64,14 @@ pub async fn main() {
|
|||
.and(warp::path!("api" / "ludantoj"))
|
||||
.and_then({
|
||||
let rajtigo = rajtigo.clone();
|
||||
move |uzantnomo| {
|
||||
move |(identigilo, uzantnomo): (UzantIdentigilo, Uzantnomo)| {
|
||||
println!(
|
||||
"[{}] {}",
|
||||
String::from(identigilo.clone()),
|
||||
String::from(uzantnomo.clone())
|
||||
);
|
||||
let rajtigo = rajtigo.clone();
|
||||
traktilo_de_listigu_ludantojn(uzantnomo, rajtigo)
|
||||
traktilo_de_listigu_ludantojn(identigilo, rajtigo)
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::aŭtentigo::Uzantnomo;
|
||||
use crate::{aŭtentigo::UzantIdentigilo, datumbazo::Datumbazo};
|
||||
use rusqlite::OptionalExtension;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -17,17 +18,26 @@ impl From<Rajto> for String {
|
|||
}
|
||||
|
||||
pub trait Rajtigo {
|
||||
fn havas_rajton<'a, F>(&'a self, uzantnomo: Uzantnomo, provo: F) -> bool
|
||||
fn havas_rajton<'a, F>(&'a self, identigilo: UzantIdentigilo, provo: F) -> bool
|
||||
where
|
||||
F: FnOnce(&mut (dyn Iterator<Item = &'a Rajto> + 'a)) -> bool;
|
||||
fn rajtoj(&self, uzantnomo: &Uzantnomo) -> Vec<Rajto>;
|
||||
fn aldonu_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>));
|
||||
fn foriru_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>));
|
||||
fn foriru_uzanto(&mut self, uzantnomo: Uzantnomo);
|
||||
F: FnOnce(&mut (dyn Iterator<Item = Rajto>)) -> bool;
|
||||
fn rajtoj(&self, identigilo: &UzantIdentigilo) -> Vec<Rajto>;
|
||||
fn aldonu_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
);
|
||||
fn foriru_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
);
|
||||
fn foriru_uzanto(&mut self, identigilo: UzantIdentigilo);
|
||||
}
|
||||
|
||||
/*
|
||||
pub struct MemRajtigo {
|
||||
rajtoj: HashMap<Uzantnomo, HashSet<Rajto>>,
|
||||
rajtoj: HashMap<UzantIdentigilo, HashSet<Rajto>>,
|
||||
}
|
||||
|
||||
impl MemRajtigo {
|
||||
|
@ -39,36 +49,93 @@ impl MemRajtigo {
|
|||
}
|
||||
|
||||
impl Rajtigo for MemRajtigo {
|
||||
fn havas_rajton<'a, F>(&'a self, uzantnomo: Uzantnomo, provo: F) -> bool
|
||||
fn havas_rajton<'a, F>(&'a self, identigilo: UzantIdentigilo, provo: F) -> bool
|
||||
where
|
||||
F: FnOnce(&mut (dyn Iterator<Item = &'a Rajto> + 'a)) -> bool,
|
||||
F: FnOnce(&mut (dyn Iterator<Item = Rajto> + 'a)) -> bool,
|
||||
{
|
||||
match self.rajtoj.get(&uzantnomo) {
|
||||
Some(rajtoj) => provo(&mut rajtoj.iter()),
|
||||
match self.rajtoj.get(&identigilo) {
|
||||
Some(rajtoj) => provo(&mut rajtoj.clone().into_iter()),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
fn rajtoj(&self, uzantnomo: &Uzantnomo) -> Vec<Rajto> {
|
||||
fn rajtoj(&self, identigilo: &UzantIdentigilo) -> Vec<Rajto> {
|
||||
self.rajtoj
|
||||
.get(&uzantnomo)
|
||||
.get(&identigilo)
|
||||
.map(|r| r.into_iter().cloned().collect::<Vec<Rajto>>())
|
||||
.unwrap_or(vec![])
|
||||
}
|
||||
fn aldonu_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>)) {
|
||||
let valoro = self.rajtoj.entry(uzantnomo).or_insert(HashSet::new());
|
||||
fn aldonu_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
) {
|
||||
let valoro = self.rajtoj.entry(identigilo).or_insert(HashSet::new());
|
||||
|
||||
while let Some(r) = rajtoj.next() {
|
||||
valoro.insert(r);
|
||||
}
|
||||
}
|
||||
fn foriru_rajtoj(&mut self, uzantnomo: Uzantnomo, rajtoj: &mut (dyn Iterator<Item = Rajto>)) {
|
||||
let valoro = self.rajtoj.entry(uzantnomo).or_insert(HashSet::new());
|
||||
fn foriru_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
) {
|
||||
let valoro = self.rajtoj.entry(identigilo).or_insert(HashSet::new());
|
||||
|
||||
while let Some(r) = rajtoj.next() {
|
||||
valoro.remove(&r);
|
||||
}
|
||||
}
|
||||
fn foriru_uzanto(&mut self, uzantnomo: Uzantnomo) {
|
||||
let _ = self.rajtoj.remove(&uzantnomo);
|
||||
fn foriru_uzanto(&mut self, identigilo: UzantIdentigilo) {
|
||||
let _ = self.rajtoj.remove(&identigilo);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub struct DBRajtigo {
|
||||
pool: Datumbazo,
|
||||
}
|
||||
|
||||
impl DBRajtigo {
|
||||
pub fn kreu(pool: Datumbazo) -> Self {
|
||||
DBRajtigo { pool }
|
||||
}
|
||||
}
|
||||
|
||||
impl Rajtigo for DBRajtigo {
|
||||
fn havas_rajton<'a, F>(&'a self, identigilo: UzantIdentigilo, provo: F) -> bool
|
||||
where
|
||||
F: FnOnce(&mut (dyn Iterator<Item = Rajto>)) -> bool,
|
||||
{
|
||||
let konekto = self.pool.konektu().unwrap();
|
||||
let mut stmt = konekto
|
||||
.prepare("SELECT rajto FROM rajtoj WHERE uzanto = ?")
|
||||
.unwrap();
|
||||
let mut rajtoj = stmt
|
||||
.query_map([String::from(identigilo)], |row| {
|
||||
row.get("rajto").map(|s: String| Rajto::from(s.as_ref()))
|
||||
})
|
||||
.unwrap()
|
||||
.map(|r| r.unwrap());
|
||||
provo(&mut rajtoj)
|
||||
}
|
||||
|
||||
fn rajtoj(&self, identigilo: &UzantIdentigilo) -> Vec<Rajto> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn aldonu_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
) {
|
||||
}
|
||||
|
||||
fn foriru_rajtoj(
|
||||
&mut self,
|
||||
identigilo: UzantIdentigilo,
|
||||
rajtoj: &mut (dyn Iterator<Item = Rajto>),
|
||||
) {
|
||||
}
|
||||
fn foriru_uzanto(&mut self, identigilo: UzantIdentigilo) {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue