Compare commits
No commits in common. "14f8bc8b3988e1126a55d394eba29b05ed6a470a" and "b3cd7266e4f020a56e1dd1e0953dbc911ba940c4" have entirely different histories.
14f8bc8b39
...
b3cd7266e4
|
@ -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",
|
||||||
|
|
40
src/bot.rs
40
src/bot.rs
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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),
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue