mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-19 19:46:50 +00:00
Settings overhaul: put in Globals, load syncronously at startup; load/save as a unit
This commit is contained in:
parent
422c60062b
commit
f1f905e595
@ -30,7 +30,7 @@ use tracing::info;
|
||||
|
||||
// This sets up the database
|
||||
#[allow(clippy::or_fun_call)]
|
||||
pub async fn setup_database() -> Result<(), Error> {
|
||||
pub fn setup_database() -> Result<(), Error> {
|
||||
let mut data_dir = dirs::data_dir()
|
||||
.ok_or::<Error>("Cannot find a directory to store application data.".into())?;
|
||||
data_dir.push("gossip");
|
||||
@ -51,18 +51,18 @@ pub async fn setup_database() -> Result<(), Error> {
|
||||
|
||||
// Save the connection globally
|
||||
{
|
||||
let mut db = GLOBALS.db.lock().await;
|
||||
let mut db = GLOBALS.db.blocking_lock();
|
||||
*db = Some(connection);
|
||||
}
|
||||
|
||||
// Check and upgrade our data schema
|
||||
check_and_upgrade().await?;
|
||||
check_and_upgrade()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_and_upgrade() -> Result<(), Error> {
|
||||
let maybe_db = GLOBALS.db.lock().await;
|
||||
fn check_and_upgrade() -> Result<(), Error> {
|
||||
let maybe_db = GLOBALS.db.blocking_lock();
|
||||
let db = maybe_db.as_ref().unwrap();
|
||||
|
||||
// Load the current version
|
||||
|
@ -63,6 +63,7 @@ impl DbSetting {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn fetch_setting_u64_or_default(key: &str, default: u64) -> Result<u64, Error> {
|
||||
let db_settings = DbSetting::fetch(Some(&format!("key='{}'", key))).await?;
|
||||
|
||||
@ -108,6 +109,7 @@ impl DbSetting {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn update<T: ToSql + Send + 'static>(key: String, value: T) -> Result<(), Error> {
|
||||
let sql = "UPDATE settings SET value=? WHERE key=?";
|
||||
|
||||
|
@ -2,6 +2,7 @@ use crate::comms::BusMessage;
|
||||
use crate::db::{DbPerson, DbPersonRelay, DbRelay};
|
||||
use crate::error::Error;
|
||||
use crate::feed_event::FeedEvent;
|
||||
use crate::settings::Settings;
|
||||
use nostr_proto::{Event, EventKind, Id, Metadata, PublicKey, PublicKeyHex, Tag, Unixtime, Url};
|
||||
use rusqlite::Connection;
|
||||
use std::collections::HashMap;
|
||||
@ -40,6 +41,9 @@ pub struct Globals {
|
||||
/// Whether or not we have a saved private key and need the password to unlock it
|
||||
#[allow(dead_code)]
|
||||
pub need_password: AtomicBool,
|
||||
|
||||
/// Settings
|
||||
pub settings: Mutex<Settings>,
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
@ -60,6 +64,7 @@ lazy_static! {
|
||||
desired_events: Mutex::new(HashMap::new()),
|
||||
people: Mutex::new(HashMap::new()),
|
||||
need_password: AtomicBool::new(false),
|
||||
settings: Mutex::new(Settings::default()),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
11
src/main.rs
11
src/main.rs
@ -20,9 +20,16 @@ use crate::globals::GLOBALS;
|
||||
use std::ops::DerefMut;
|
||||
use std::{mem, thread};
|
||||
|
||||
fn main() {
|
||||
fn main() -> Result<(), Error> {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
// Setup the database (possibly create, possibly upgrade)
|
||||
crate::db::setup_database()?;
|
||||
|
||||
// Load settings
|
||||
let settings = crate::settings::Settings::blocking_load()?;
|
||||
*GLOBALS.settings.blocking_lock() = settings;
|
||||
|
||||
// Start async code
|
||||
// We do this on a separate thread because egui is most portable by
|
||||
// being on the main thread.
|
||||
@ -42,6 +49,8 @@ fn main() {
|
||||
|
||||
// Wait for the async thread to complete
|
||||
async_thread.join().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn tokio_main() {
|
||||
|
@ -6,7 +6,6 @@ use crate::comms::BusMessage;
|
||||
use crate::db::{DbPersonRelay, DbRelay};
|
||||
use crate::error::Error;
|
||||
use crate::globals::GLOBALS;
|
||||
use crate::settings::Settings;
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use futures_util::stream::{SplitSink, SplitStream};
|
||||
use http::Uri;
|
||||
@ -25,7 +24,6 @@ pub struct Minion {
|
||||
pubkeys: Vec<PublicKeyHex>,
|
||||
to_overlord: UnboundedSender<BusMessage>,
|
||||
from_overlord: Receiver<BusMessage>,
|
||||
settings: Settings,
|
||||
dbrelay: DbRelay,
|
||||
nip11: Option<RelayInformationDocument>,
|
||||
stream: Option<SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>>,
|
||||
@ -37,7 +35,6 @@ impl Minion {
|
||||
pub async fn new(url: Url, pubkeys: Vec<PublicKeyHex>) -> Result<Minion, Error> {
|
||||
let to_overlord = GLOBALS.to_overlord.clone();
|
||||
let from_overlord = GLOBALS.to_minions.subscribe();
|
||||
let settings = Settings::load().await?;
|
||||
let dbrelay = match DbRelay::fetch_one(&url).await? {
|
||||
Some(dbrelay) => dbrelay,
|
||||
None => {
|
||||
@ -52,7 +49,6 @@ impl Minion {
|
||||
pubkeys,
|
||||
to_overlord,
|
||||
from_overlord,
|
||||
settings,
|
||||
dbrelay,
|
||||
nip11: None,
|
||||
stream: None,
|
||||
@ -224,7 +220,7 @@ impl Minion {
|
||||
info!("Websocket listener {} shutting down", &self.url);
|
||||
keepgoing = false;
|
||||
} else if &*bus_message.kind == "settings_changed" {
|
||||
self.settings = serde_json::from_str(&bus_message.json_payload)?;
|
||||
// TBD: possibly redo filters based on overlap, feed_chunk, etc.
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -269,12 +265,14 @@ impl Minion {
|
||||
let mut special_since: i64 =
|
||||
DbPersonRelay::fetch_oldest_last_fetched(&self.pubkeys, &self.url.0).await? as i64;
|
||||
|
||||
let settings = GLOBALS.settings.lock().await.clone();
|
||||
|
||||
// Subtract overlap to avoid gaps due to clock sync and event
|
||||
// propogation delay
|
||||
special_since -= self.settings.overlap as i64;
|
||||
special_since -= settings.overlap as i64;
|
||||
|
||||
// For feed related events, don't look back more than one feed_chunk ago
|
||||
let one_feedchunk_ago = Unixtime::now().unwrap().0 - self.settings.feed_chunk as i64;
|
||||
let one_feedchunk_ago = Unixtime::now().unwrap().0 - settings.feed_chunk as i64;
|
||||
let feed_since = special_since.max(one_feedchunk_ago);
|
||||
|
||||
(Unixtime(feed_since), Unixtime(special_since))
|
||||
|
@ -60,12 +60,6 @@ impl Overlord {
|
||||
}
|
||||
|
||||
pub async fn run_inner(&mut self) -> Result<(), Error> {
|
||||
// Setup the database (possibly create, possibly upgrade)
|
||||
crate::db::setup_database().await?;
|
||||
|
||||
// Load settings
|
||||
self.settings = Settings::load().await?;
|
||||
|
||||
// Check for a private key
|
||||
if DbSetting::fetch_setting("user_private_key")
|
||||
.await?
|
||||
@ -82,7 +76,7 @@ impl Overlord {
|
||||
// FIXME - if this needs doing, it should be done dynamically as
|
||||
// new people are encountered, not batch-style on startup.
|
||||
// Create a person record for every person seen, possibly autofollow
|
||||
DbPerson::populate_new_people(self.settings.autofollow != 0).await?;
|
||||
DbPerson::populate_new_people(self.settings.autofollow).await?;
|
||||
|
||||
// FIXME - if this needs doing, it should be done dynamically as
|
||||
// new people are encountered, not batch-style on startup.
|
||||
|
@ -1,16 +1,24 @@
|
||||
use crate::db::DbSetting;
|
||||
use crate::error::Error;
|
||||
use crate::globals::GLOBALS;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const DEFAULT_FEED_CHUNK: u64 = 43200; // 12 hours
|
||||
pub const DEFAULT_OVERLAP: u64 = 600; // 10 minutes
|
||||
pub const DEFAULT_AUTOFOLLOW: u64 = 0;
|
||||
pub const DEFAULT_AUTOFOLLOW: bool = false;
|
||||
pub const DEFAULT_VIEW_POSTS_REFERRED_TO: bool = true;
|
||||
pub const DEFAULT_VIEW_POSTS_REFERRING_TO: bool = false;
|
||||
pub const DEFAULT_VIEW_THREADED: bool = true;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct Settings {
|
||||
// user_private_key
|
||||
// version
|
||||
pub feed_chunk: u64,
|
||||
pub overlap: u64,
|
||||
pub autofollow: u64,
|
||||
pub autofollow: bool,
|
||||
pub view_posts_referred_to: bool,
|
||||
pub view_posts_referring_to: bool,
|
||||
pub view_threaded: bool,
|
||||
}
|
||||
|
||||
impl Default for Settings {
|
||||
@ -18,33 +26,75 @@ impl Default for Settings {
|
||||
Settings {
|
||||
feed_chunk: DEFAULT_FEED_CHUNK,
|
||||
overlap: DEFAULT_OVERLAP,
|
||||
autofollow: 0,
|
||||
autofollow: DEFAULT_AUTOFOLLOW,
|
||||
view_posts_referred_to: DEFAULT_VIEW_POSTS_REFERRED_TO,
|
||||
view_posts_referring_to: DEFAULT_VIEW_POSTS_REFERRING_TO,
|
||||
view_threaded: DEFAULT_VIEW_THREADED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub async fn load() -> Result<Settings, Error> {
|
||||
let feed_chunk =
|
||||
DbSetting::fetch_setting_u64_or_default("feed_chunk", DEFAULT_FEED_CHUNK).await?;
|
||||
pub fn blocking_load() -> Result<Settings, Error> {
|
||||
let mut settings = Settings::default();
|
||||
|
||||
let overlap = DbSetting::fetch_setting_u64_or_default("overlap", DEFAULT_OVERLAP).await?;
|
||||
let maybe_db = GLOBALS.db.blocking_lock();
|
||||
let db = maybe_db.as_ref().unwrap();
|
||||
|
||||
let autofollow =
|
||||
DbSetting::fetch_setting_u64_or_default("autofollow", DEFAULT_AUTOFOLLOW).await?;
|
||||
let mut stmt = db.prepare("SELECT key, value FROM settings")?;
|
||||
|
||||
Ok(Settings {
|
||||
feed_chunk,
|
||||
overlap,
|
||||
autofollow,
|
||||
})
|
||||
let rows = stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?)))?;
|
||||
|
||||
let numstr_to_bool = |s: String| -> bool { &s == "1" };
|
||||
|
||||
for row in rows {
|
||||
let row: (String, String) = row?;
|
||||
match &*row.0 {
|
||||
"feed_chunk" => {
|
||||
settings.feed_chunk = row.1.parse::<u64>().unwrap_or(DEFAULT_FEED_CHUNK)
|
||||
}
|
||||
"overlap" => settings.overlap = row.1.parse::<u64>().unwrap_or(DEFAULT_OVERLAP),
|
||||
"autofollow" => settings.autofollow = numstr_to_bool(row.1),
|
||||
"view_posts_referred_to" => settings.view_posts_referred_to = numstr_to_bool(row.1),
|
||||
"view_posts_referring_to" => {
|
||||
settings.view_posts_referring_to = numstr_to_bool(row.1)
|
||||
}
|
||||
"view_threaded" => settings.view_threaded = numstr_to_bool(row.1),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(settings)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub async fn save(&self) -> Result<(), Error> {
|
||||
DbSetting::update("feed_chunk".to_string(), self.feed_chunk).await?;
|
||||
DbSetting::update("overlap".to_string(), self.overlap).await?;
|
||||
DbSetting::update("autofollow".to_string(), self.autofollow).await?;
|
||||
let maybe_db = GLOBALS.db.lock().await;
|
||||
let db = maybe_db.as_ref().unwrap();
|
||||
|
||||
let mut stmt = db.prepare(
|
||||
"REPLACE INTO settings (key, value) VALUES \
|
||||
('feed_chunk', ?),('overlap', ?),('autofollow', ?),\
|
||||
('view_posts_referred_to', ?),('view_posts_referring_to', ?),\
|
||||
('view_threaded', ?)",
|
||||
)?;
|
||||
stmt.execute((
|
||||
self.feed_chunk,
|
||||
self.overlap,
|
||||
if self.autofollow { "1" } else { "0" },
|
||||
if self.view_posts_referred_to {
|
||||
"1"
|
||||
} else {
|
||||
"0"
|
||||
},
|
||||
if self.view_posts_referring_to {
|
||||
"1"
|
||||
} else {
|
||||
"0"
|
||||
},
|
||||
if self.view_threaded { "1" } else { "0" },
|
||||
))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ mod you;
|
||||
|
||||
use crate::about::About;
|
||||
use crate::error::Error;
|
||||
use crate::globals::GLOBALS;
|
||||
use eframe::{egui, IconData, Theme};
|
||||
use egui::{ColorImage, Context, ImageData, TextureHandle, TextureOptions};
|
||||
|
||||
@ -101,13 +102,15 @@ impl GossipUi {
|
||||
)
|
||||
};
|
||||
|
||||
let threaded = GLOBALS.settings.blocking_lock().view_threaded;
|
||||
|
||||
GossipUi {
|
||||
page: Page::Feed,
|
||||
about: crate::about::about(),
|
||||
icon: icon_texture_handle,
|
||||
placeholder_avatar: placeholder_avatar_texture_handle,
|
||||
draft: "".to_owned(),
|
||||
threaded: true,
|
||||
threaded,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user