Inital Commit

This commit is contained in:
Woljix 2021-06-12 13:19:23 +02:00
parent 4bab661b50
commit ec7268f645
5 changed files with 265 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

21
Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "neo"
version = "0.1.0"
authors = ["Woljix"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
matrix-sdk = "0.2.0"
url = "2.2.1"
tokio = { version = "0.2.25", features = ["full"] }
mime = "0.3.16"
serde = { version = "1.0.126", features = ["derive"] }
serde_json = "1.0.64"
indexmap = { version = "1.6.2", features = ["serde-1"] }
rand = "0.8.3"
#[profile.release]
#opt-level = 'z'
#lto = 'thin'

38
src/config.rs Normal file
View File

@ -0,0 +1,38 @@
use indexmap::IndexMap;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct ConfigLogin {
pub username: String,
pub password: String,
pub device_id: String,
}
impl Default for ConfigLogin {
fn default() -> ConfigLogin {
ConfigLogin {
username: "".to_string(),
password: "".to_string(),
device_id: "".to_string(),
}
}
}
#[derive(Serialize, Deserialize)]
#[serde(default)]
pub struct ConfigImages {
pub last_image: String,
pub files: Vec<String>,
pub cache: IndexMap<String, String>
}
impl Default for ConfigImages {
fn default() -> ConfigImages {
ConfigImages {
last_image: "".to_string(),
files: Vec::new(),
cache: IndexMap::new(),
}
}
}

147
src/main.rs Normal file
View File

@ -0,0 +1,147 @@
use matrix_sdk::{self, Client};
use rand::prelude::SliceRandom;
use std::{
fs::File,
io::{Error, ErrorKind},
path::PathBuf,
process,
};
use url::Url;
mod config;
use config::{ConfigImages, ConfigLogin};
mod settings;
use settings::Settings;
const HOME_SERVER: &str = "https://e1m1.xyz";
#[tokio::main]
async fn main() {
if let Err(e) = run().await {
println!("Application error: {}", e);
process::exit(1);
}
}
async fn run() -> Result<(), Box<std::io::Error>> {
let dir_exe: PathBuf = {
let exe = std::env::current_exe().unwrap();
let parent = exe.parent().unwrap();
parent.to_path_buf()
};
let dir_login = &dir_exe.join("login.json");
let dir_images = &dir_exe.join("images.json");
let settings_login: Settings<ConfigLogin> =
Settings::<ConfigLogin>::load(&dir_login).unwrap();
let mut settings_images: Settings<ConfigImages> =
Settings::<ConfigImages>::load(&dir_images).unwrap();
let conf_login = &settings_login.loaded;
let conf_images = &mut settings_images.loaded;
let mut flag_debug: bool = false;
let mut flag_generate: bool = false;
for x in std::env::args() {
match x.as_str() {
"-debug" => {
flag_debug = true;
break;
}
"generate" => {
flag_generate = true;
break;
}
_ => {}
}
}
if flag_generate {
println!("Generating config files..");
Settings::<ConfigLogin>::new(ConfigLogin::default())
.unwrap()
.save(&dir_login.with_extension("json.template").clone())
.unwrap();
Settings::<ConfigImages>::new(ConfigImages::default())
.unwrap()
.save(&dir_images.with_extension("json.template").clone())
.unwrap();
return Ok(());
}
if let Ok(client) = login(
conf_login.username.as_str(),
conf_login.password.as_str(),
conf_login.device_id.as_str(),
)
.await
{
let selection = {
if flag_debug {
// Note: This assumes that "last_image" is not empty and has a valid image path.
conf_images.last_image.to_string()
} else {
let mut rng = rand::thread_rng();
conf_images.files.choose(&mut rng).unwrap().to_string()
}
};
println!("Selection was: '{}'", selection);
if conf_images.cache.contains_key(&selection) {
if let Some(url) = conf_images.cache.get(&selection) {
println!("Setting Avatar URL: '{}'", url);
client.set_avatar_url(Some(url)).await.unwrap();
}
} else {
let path = dir_exe.join(&selection);
if path.exists() {
conf_images.last_image = selection.clone();
let mut image = File::open(&path).unwrap();
match client.upload_avatar(&mime::IMAGE_JPEG, &mut image).await {
Ok(_) => {
println!("Successfully uploaded avatar!");
if let Some(avatar_url) = client.avatar_url().await.unwrap() {
conf_images.cache.insert(selection.clone(), avatar_url);
}
}
Err(err) => {
return Err(Box::new(Error::new(
ErrorKind::Other,
format!("Error occurred while uploading avatar: '{}'", err),
)));
}
}
} else {
println!("Error: file does not exist!");
}
}
settings_images.save(&dir_images).unwrap();
} else {
return Err(Box::new(Error::new(ErrorKind::Other, "Login failed!")));
}
Ok(())
}
async fn login(
username: &str,
password: &str,
device_id: &str,
) -> Result<Client, matrix_sdk::Error> {
let client = Client::new(Url::parse(HOME_SERVER).unwrap()).unwrap();
match client
.login(username, password, Some(device_id), Some("NEO bot"))
.await
{
Ok(_) => return Ok(client),
Err(e) => return Err(e),
}
}

45
src/settings.rs Normal file
View File

@ -0,0 +1,45 @@
use std::{fs::OpenOptions};
use std::path::Path;
use std::io::{self, Write, prelude::*};
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde_json;
pub struct Settings<T> {
pub loaded: T
}
impl<T: DeserializeOwned + Serialize> Settings<T> {
pub fn new(import: T) -> io::Result<Self> {
Ok(Self {
loaded: import
})
}
pub fn load(file: &Path) -> io::Result<Self> {
let mut f = match OpenOptions::new().read(true).write(false).open(&file) {
Ok(file) => file,
Err(error) => panic!("Error opening this file: {:?}", error)
};
let mut contents = String::new();
f.read_to_string(&mut contents).unwrap();
Ok(Self {
loaded: serde_json::from_str(contents.as_str()).unwrap()
})
}
pub fn save(&self, file: &Path) -> io::Result<()> {
let json = serde_json::to_string_pretty(&self.loaded).unwrap();
let mut f = match OpenOptions::new().read(true).write(true).create(true).open(&file) {
Ok(file) => file,
Err(error) => panic!("Error saving this file: {:?}", error)
};
f.write_all(json.as_bytes()).unwrap();
Ok(())
}
}