add memory cache for gemini identities search

This commit is contained in:
yggverse 2024-11-16 17:27:44 +02:00
parent d9bf85884b
commit f347c28f6f
4 changed files with 75 additions and 13 deletions

View File

@ -37,21 +37,18 @@ impl Identity {
}
}
/// Get `pem` record match `request`
///
/// https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates
/// Get `pem` record match `request` according to
/// [Gemini protocol specification](https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates)
/// * this function work with memory cache not database
pub fn gemini(&self, request: &str) -> Option<String> {
// @TODO apply protocol rules to certificate selection
for profile_identity_gemini_id in self.gemini.auth.memory.starts_with(request) {
if let Ok(gemini_records) = self.gemini.database.records() {
for gemini_record in gemini_records {
if gemini_record.id == profile_identity_gemini_id {
return Some(gemini_record.pem);
}
}
if let Ok(pem) = self.gemini.memory.get(profile_identity_gemini_id) {
return Some(pem);
}
}
None
} // @TODO apply protocol rules to selection
}
}
// Tools

View File

@ -1,8 +1,10 @@
mod auth;
mod database;
mod memory;
use auth::Auth;
use database::Database;
use memory::Memory;
use sqlite::{Connection, Transaction};
use std::{rc::Rc, sync::RwLock};
@ -12,7 +14,8 @@ use std::{rc::Rc, sync::RwLock};
/// https://geminiprotocol.net/docs/protocol-specification.gmi#client-certificates
pub struct Gemini {
pub auth: Rc<Auth>,
pub database: Rc<Database>,
// pub database: Rc<Database>,
pub memory: Rc<Memory>,
}
impl Gemini {
@ -20,9 +23,27 @@ impl Gemini {
/// Create new `Self`
pub fn new(connection: Rc<RwLock<Connection>>, profile_identity_id: Rc<i64>) -> Self {
// Init children components
let auth = Rc::new(Auth::new(connection.clone()));
let database = Rc::new(Database::new(connection, profile_identity_id));
let memory = Rc::new(Memory::new());
// Build initial index
match database.records() {
Ok(records) => {
for record in records {
if memory.add(record.id, record.pem).is_err() {
todo!()
}
}
}
Err(reason) => todo!("{reason}"),
}
Self {
auth: Rc::new(Auth::new(connection.clone())),
database: Rc::new(Database::new(connection, profile_identity_id)),
auth,
// database,
memory,
}
}

View File

@ -0,0 +1,39 @@
mod error;
use error::Error;
use std::{cell::RefCell, collections::HashMap};
/// Reduce disk usage by cache index in memory
pub struct Memory {
index: RefCell<HashMap<i64, String>>,
}
impl Memory {
// Constructors
/// Create new `Self`
pub fn new() -> Self {
Self {
index: RefCell::new(HashMap::new()),
}
}
// Actions
/// Add new record with `id` as key and `pem` as value
/// * validate record with same key does not exist yet
pub fn add(&self, id: i64, pem: String) -> Result<(), Error> {
match self.index.borrow_mut().insert(id, pem) {
Some(_) => Err(Error::Overwrite), // @TODO prevent?
None => Ok(()),
}
}
/// Get `pem` clone by `id` from memory index
pub fn get(&self, id: i64) -> Result<String, Error> {
match self.index.borrow().get(&id) {
Some(pem) => Ok(pem.clone()),
None => Err(Error::NotFound),
}
}
}

View File

@ -0,0 +1,5 @@
#[derive(Debug)]
pub enum Error {
NotFound,
Overwrite,
}