pluralsync/src/main.rs

296 lines
8.0 KiB
Rust
Raw Normal View History

2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Imports][Imports:1]]
2023-11-21 13:20:21 +00:00
use std::fs;
use std::fs::create_dir;
2023-11-20 15:39:40 +00:00
use std::path::Path;
2023-11-21 13:20:21 +00:00
use std::collections::HashMap;
2023-11-20 15:39:40 +00:00
use reqwest::header::{USER_AGENT, AUTHORIZATION};
2023-11-21 13:20:21 +00:00
2023-11-20 15:39:40 +00:00
use serde::{Serialize, Deserialize};
use serde_json::Value;
2023-11-21 13:20:21 +00:00
2023-11-20 15:39:40 +00:00
use dirs;
2023-11-21 11:47:07 +00:00
// Imports:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Constants][Constants:1]]
2023-11-20 15:39:40 +00:00
const PK_URL: &str = "https://api.pluralkit.me/v2";
const SP_URL: &str = "https://api.apparyllis.com/v1";
2023-11-21 11:47:07 +00:00
// Constants:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Structs][Structs:1]]
2023-11-20 15:39:40 +00:00
#[derive(Debug)]
#[derive(Serialize)]
2023-11-21 13:20:21 +00:00
#[derive(Deserialize)]
2023-11-20 15:39:40 +00:00
struct System {
pk_userid: String,
sp_userid: String,
members: Vec<Member>,
}
#[derive(Debug)]
#[derive(Serialize)]
2023-11-21 13:20:21 +00:00
#[derive(Deserialize)]
2023-11-20 15:39:40 +00:00
#[derive(Clone)]
struct Member {
pk_id: String,
sp_id: String,
name: String,
alias: String
}
2023-11-21 11:47:07 +00:00
// Structs:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Main][Main:1]]
2023-11-20 15:39:40 +00:00
fn main() {
if std::env::args().len() > 1 {
let command = std::env::args().nth(1).expect("No command given");
let config_path: String;
match dirs::config_dir() {
Some(x) => {
config_path = format!("{}/pluralshit", x.display());
match command.as_str() {
2023-11-21 13:20:21 +00:00
"sync" => {
let _ = sync(config_path);
},
2023-11-20 15:39:40 +00:00
"set" => {
if std::env::args().len() > 2 {
2023-11-21 13:20:21 +00:00
match set_member(config_path, std::env::args().nth(2).expect("No member given")) {
Ok(_) => (),
Err(e) => println!("{e}"),
}
2023-11-20 15:39:40 +00:00
} else {
2023-11-21 13:20:21 +00:00
//set_empty(config_path);
2023-11-20 15:39:40 +00:00
}
},
&_ => println!("Invalid command"),
}
},
None => println!("Something went wrong")
}
} else {
println!("No arguments given");
}
}
2023-11-21 11:47:07 +00:00
// Main:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Main commands][Main commands:1]]
2023-11-21 13:20:21 +00:00
fn set_member(config_path: String, member: String) -> Result<(), &'static str> {
let config = get_config(&config_path);
if config == Value::Null {
return Err("Config not found. Stopping");
}
let system: System = get_system(&config_path);
let mut flag = false;
for mem in system.members {
if mem.name.to_lowercase() == member.to_lowercase() {
flag = true;
}
}
if flag {
println!("Member {member} found");
Ok(())
} else {
Err("Member {member} not found")
}
2023-11-20 15:39:40 +00:00
}
2023-11-21 13:20:21 +00:00
/*
2023-11-20 15:39:40 +00:00
fn set_empty(config_path: String) {
let config = load_json(format!("{}/config.json", config_path));
2023-11-21 13:20:21 +00:00
let system = get_system(&config_path);
2023-11-20 15:39:40 +00:00
}
2023-11-21 13:20:21 +00:00
*/
2023-11-20 15:39:40 +00:00
2023-11-21 13:20:21 +00:00
fn sync(config_path: String) -> Result<(), String>{
2023-11-20 15:39:40 +00:00
// Get config
2023-11-21 13:20:21 +00:00
let config = get_config(&config_path);
if config == Value::Null {
println!("Stopping.");
return Ok(());
}
2023-11-20 15:39:40 +00:00
let pk_key = &config["pk_key"].as_str().unwrap();
let sp_key = &config["sp_key"].as_str().unwrap();
// Get Pluralkit system id
let pk_sys = pk_get_system(pk_key);
let pk_sysid = pk_sys["id"].as_str().unwrap();
// Get Simplyplural user id
let sp_user_id = sp_get_userid(sp_key);
// Get Simplyplural member ids
let sp_member_ids = sp_get_memberids(sp_key, &sp_user_id);
// get members
let pk_members = pk_get_members(pk_key, pk_sysid);
let mut members: Vec<Member> = Vec::new();
for member in pk_members {
let mut m = Member {
pk_id: member["id"].as_str().unwrap().to_string(),
sp_id: String::new(),
name: member["name"].as_str().unwrap().to_string(),
alias: String::new()
};
if member["display_name"].as_str() != None {
m.alias = member["display_name"].as_str().unwrap().to_string();
} else {
m.alias = String::from(&m.name);
}
m.sp_id = get_sp_id(&m, &sp_member_ids);
members.push(m);
}
let sys = System {
pk_userid: pk_sysid.to_string(),
sp_userid: sp_user_id,
members: members.clone(),
};
let json = serde_json::to_string(&sys);
let _ = fs::write(format!("{}/system.json", config_path), &json.unwrap());
2023-11-21 13:20:21 +00:00
Ok(())
2023-11-20 15:39:40 +00:00
}
2023-11-21 11:47:07 +00:00
// Main commands:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Pluralkit][Pluralkit:1]]
fn pk_get_system(key: &str) -> Value {
let url = format!("{}/systems/@me", PK_URL);
2023-11-20 15:39:40 +00:00
2023-11-21 13:20:21 +00:00
let res = http_get_request(url,key);
2023-11-21 11:47:07 +00:00
return serde_json::from_str(&res.unwrap()).unwrap();
}
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
fn pk_get_members(key: &str, sysid: &str) -> Vec<Value> {
let url = format!("{}/systems/{}/members", PK_URL, sysid);
2023-11-20 15:39:40 +00:00
2023-11-21 13:20:21 +00:00
let res = http_get_request(url,key);
2023-11-21 11:47:07 +00:00
let datas: Vec<Value> = serde_json::from_str(&res.unwrap()).unwrap();
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
return datas;
2023-11-20 15:39:40 +00:00
}
2023-11-21 11:47:07 +00:00
// Pluralkit:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Simplyplural][Simplyplural:1]]
2023-11-20 15:39:40 +00:00
fn sp_get_userid(key: &str) -> String {
let url = format!("{}/me", SP_URL);
2023-11-21 13:20:21 +00:00
let res = http_get_request(url,key);
2023-11-20 15:39:40 +00:00
let json_res : Value = serde_json::from_str(&res.unwrap()).unwrap();
return json_res["id"].as_str().unwrap().to_string();
}
fn sp_get_memberids(key: &str, system_id: &str) -> HashMap<String, String> {
let url = format!("{}/members/{}", SP_URL, system_id);
2023-11-21 13:20:21 +00:00
let res = http_get_request(url,key);
2023-11-20 15:39:40 +00:00
let datas: Vec<Value> = serde_json::from_str(&res.unwrap()).unwrap();
let mut sp_memberdata: HashMap<String, String> = HashMap::new();
for data in datas {
sp_memberdata.insert(String::from(data["content"]["name"].as_str().unwrap()), String::from(data["id"].as_str().unwrap()));
}
return sp_memberdata;
}
fn get_sp_id(mem: &Member, ids: &HashMap<String, String>) -> String {
let mut member_id = String::new();
for (mn, mid) in ids {
if &mem.name == mn || &mem.alias == mn {
member_id = String::from(mid);
}
}
return member_id;
}
2023-11-21 11:47:07 +00:00
// Simplyplural:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Utilities][Utilities:1]]
fn load_json(path: String) -> Value {
if Path::new(&path).exists() {
2023-11-21 13:20:21 +00:00
let config_data = fs::read_to_string(&path).expect("File not found");
2023-11-21 11:47:07 +00:00
return serde_json::from_str(&config_data).unwrap();
} else {
println!("Config file in {path} not found");
return Value::Null;
}
2023-11-20 15:39:40 +00:00
}
2023-11-21 13:20:21 +00:00
fn get_config(config_path: &str) -> Value {
let path = format!("{}/config.json", config_path);
if Path::new(config_path).exists() {
2023-11-20 15:39:40 +00:00
2023-11-21 13:20:21 +00:00
let result = load_json(String::from(&path));
2023-11-20 15:39:40 +00:00
2023-11-21 13:20:21 +00:00
if result == Value::Null {
println!("Config file missing, creating template in {path}");
let _ = fs::write(path, r#"
{
"pk_key": "// Pluralkit token",
"sp_key": "// Simplplural token"
}
"#);
}
2023-11-21 11:47:07 +00:00
2023-11-21 13:20:21 +00:00
return result;
2023-11-21 11:47:07 +00:00
} else {
2023-11-21 13:20:21 +00:00
println!("Directory {config_path} does not exist. Creating with template config");
let _ = create_dir(config_path);
let _ = fs::write(path, r#"
{
"pk_key": "// Pluralkit token",
"sp_key": "// Simplplural token"
}
"#);
return Value::Null;
2023-11-21 11:47:07 +00:00
}
2023-11-20 15:39:40 +00:00
}
2023-11-21 13:20:21 +00:00
fn get_system(config_path: &str) -> System {
let path = format!("{}/system.json", config_path);
let mut result = load_json(String::from(&path));
if result == Value::Null {
println!("Syncing system config");
let _ = sync(String::from(config_path));
result = load_json(String::from(&path));
}
let vec = serde_json::to_vec(&result).unwrap();
let sys = serde_json::from_slice::<System>(&vec).unwrap();
return sys;
}
2023-11-21 11:47:07 +00:00
// Utilities:1 ends here
2023-11-20 15:39:40 +00:00
2023-11-21 11:47:07 +00:00
// [[file:../README.org::*Http Request handler][Http Request handler:1]]
2023-11-20 15:39:40 +00:00
#[tokio::main]
2023-11-21 13:20:21 +00:00
async fn http_get_request(url: String, key: &str) -> Result<String, Box<dyn std::error::Error>> {
2023-11-20 15:39:40 +00:00
let client = reqwest::Client::new();
let res = client
.get(url)
.header(USER_AGENT, "Pluralsync")
.header(AUTHORIZATION, key)
.send()
.await?
.text()
.await?;
Ok(res)
}
2023-11-21 11:47:07 +00:00
// Http Request handler:1 ends here