Compare commits

..

No commits in common. "14f8bc8b3988e1126a55d394eba29b05ed6a470a" and "b3cd7266e4f020a56e1dd1e0953dbc911ba940c4" have entirely different histories.

6 changed files with 12 additions and 130 deletions

2
Cargo.lock generated
View File

@ -245,7 +245,7 @@ dependencies = [
[[package]] [[package]]
name = "chronicle-dicebot" name = "chronicle-dicebot"
version = "0.9.0" version = "0.8.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"bincode", "bincode",

View File

@ -120,40 +120,20 @@ impl DiceBot {
}) })
} }
/// Logs in to matrix and potentially records a new device ID. If /// Logs the bot into Matrix and listens for events until program
/// no device ID is found in the database, a new one will be
/// generated by the matrix SDK, and we will store it.
async fn login(&self, client: &Client) -> Result<(), BotError> {
let username = self.config.matrix_username();
let password = self.config.matrix_password();
// Pull device ID from database, if it exists. Then write it
// to DB if the library generated one for us.
let device_id: Option<String> = self.db.state.get_device_id()?;
let device_id: Option<&str> = device_id.as_deref();
client
.login(username, password, device_id, Some("matrix dice bot"))
.await?;
if device_id.is_none() {
let device_id = client.device_id().await.ok_or(BotError::NoDeviceIdFound)?;
self.db.state.set_device_id(device_id.as_str())?;
info!("Recorded new device ID: {}", device_id.as_str());
} else {
info!("Using existing device ID: {}", device_id.unwrap());
}
info!("Logged in as {}", username);
Ok(())
}
/// Logs the bot in to Matrix and listens for events until program
/// terminated, or a panic occurs. Originally adapted from the /// terminated, or a panic occurs. Originally adapted from the
/// matrix-rust-sdk command bot example. /// matrix-rust-sdk command bot example.
pub async fn run(self) -> Result<(), BotError> { pub async fn run(self) -> Result<(), BotError> {
let username = &self.config.matrix_username();
let password = &self.config.matrix_password();
//TODO provide a device id from config.
let client = self.client.clone(); let client = self.client.clone();
self.login(&client).await?; client
.login(username, password, None, Some("matrix dice bot"))
.await?;
info!("Logged in as {}", username);
// Initial sync without event handler prevents responding to // Initial sync without event handler prevents responding to
// messages received while bot was offline. TODO: selectively // messages received while bot was offline. TODO: selectively

View File

@ -1,7 +1,6 @@
use crate::db::errors::{DataError, MigrationError}; use crate::db::errors::{DataError, MigrationError};
use crate::db::migrations::{get_migration_version, Migrations}; use crate::db::migrations::{get_migration_version, Migrations};
use crate::db::rooms::Rooms; use crate::db::rooms::Rooms;
use crate::db::state::DbState;
use crate::db::variables::Variables; use crate::db::variables::Variables;
use log::info; use log::info;
use sled::{Config, Db}; use sled::{Config, Db};
@ -12,7 +11,6 @@ pub mod errors;
pub mod migrations; pub mod migrations;
pub mod rooms; pub mod rooms;
pub mod schema; pub mod schema;
pub mod state;
pub mod variables; pub mod variables;
#[derive(Clone)] #[derive(Clone)]
@ -21,7 +19,6 @@ pub struct Database {
pub(crate) variables: Variables, pub(crate) variables: Variables,
pub(crate) migrations: Migrations, pub(crate) migrations: Migrations,
pub(crate) rooms: Rooms, pub(crate) rooms: Rooms,
pub(crate) state: DbState,
} }
impl Database { impl Database {
@ -33,7 +30,6 @@ impl Database {
variables: Variables::new(&db)?, variables: Variables::new(&db)?,
migrations: Migrations(migrations), migrations: Migrations(migrations),
rooms: Rooms::new(&db)?, rooms: Rooms::new(&db)?,
state: DbState::new(&db)?,
}; };
//Start any event handlers. //Start any event handlers.

View File

@ -29,11 +29,8 @@ pub enum DataError {
#[error("unexpected or corruptd data bytes")] #[error("unexpected or corruptd data bytes")]
InvalidValue, InvalidValue,
#[error("expected string ref, but utf8 schema was violated: {0}")]
Utf8RefSchemaViolation(#[from] std::str::Utf8Error),
#[error("expected string, but utf8 schema was violated: {0}")] #[error("expected string, but utf8 schema was violated: {0}")]
Utf8SchemaViolation(#[from] std::string::FromUtf8Error), Utf8chemaViolation(#[from] std::str::Utf8Error),
#[error("internal database error: {0}")] #[error("internal database error: {0}")]
InternalError(#[from] sled::Error), InternalError(#[from] sled::Error),

View File

@ -1,88 +0,0 @@
use crate::db::errors::DataError;
use sled::Tree;
#[derive(Clone)]
pub struct DbState {
/// Tree of simple key-values for global state values that persist
/// between restarts (e.g. device ID).
pub(in crate::db) global_metadata: Tree,
}
const DEVICE_ID_KEY: &'static [u8] = b"device_id";
impl DbState {
pub(in crate::db) fn new(db: &sled::Db) -> Result<DbState, sled::Error> {
Ok(DbState {
global_metadata: db.open_tree("global_metadata")?,
})
}
pub fn get_device_id(&self) -> Result<Option<String>, DataError> {
self.global_metadata
.get(DEVICE_ID_KEY)?
.map(|v| String::from_utf8(v.to_vec()))
.transpose()
.map_err(|e| e.into())
}
pub fn set_device_id(&self, device_id: &str) -> Result<(), DataError> {
self.global_metadata
.insert(DEVICE_ID_KEY, device_id.as_bytes())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use sled::Config;
fn create_test_instance() -> DbState {
let config = Config::new().temporary(true);
let db = config.open().unwrap();
DbState::new(&db).unwrap()
}
#[test]
fn set_device_id_works() {
let state = create_test_instance();
let result = state.set_device_id("test-device");
assert!(result.is_ok());
}
#[test]
fn set_device_id_can_overwrite() {
let state = create_test_instance();
state.set_device_id("test-device").expect("insert 1 failed");
let result = state.set_device_id("test-device2");
assert!(result.is_ok());
}
#[test]
fn get_device_id_returns_some_when_set() {
let state = create_test_instance();
state
.set_device_id("test-device")
.expect("could not store device id properly");
let device_id = state.get_device_id();
assert!(device_id.is_ok());
let device_id = device_id.unwrap();
assert!(device_id.is_some());
assert_eq!("test-device", device_id.unwrap());
}
#[test]
fn get_device_id_returns_none_when_unset() {
let state = create_test_instance();
let device_id = state.get_device_id();
assert!(device_id.is_ok());
let device_id = device_id.unwrap();
assert!(device_id.is_none());
}
}

View File

@ -12,9 +12,6 @@ pub enum BotError {
#[error("the sync token could not be retrieved")] #[error("the sync token could not be retrieved")]
SyncTokenRequired, SyncTokenRequired,
#[error("could not retrieve device id")]
NoDeviceIdFound,
#[error("command error: {0}")] #[error("command error: {0}")]
CommandError(#[from] CommandError), CommandError(#[from] CommandError),