link shorting
This commit is contained in:
parent
dddf53d352
commit
026a91fc4e
5 changed files with 117 additions and 0 deletions
|
|
@ -13,6 +13,9 @@ pub enum DataTypes {
|
||||||
accepted_ids,
|
accepted_ids,
|
||||||
uuid,
|
uuid,
|
||||||
register_id,
|
register_id,
|
||||||
|
|
||||||
|
link,
|
||||||
|
|
||||||
settings,
|
settings,
|
||||||
settings_name,
|
settings_name,
|
||||||
chat_partner_id,
|
chat_partner_id,
|
||||||
|
|
@ -124,6 +127,9 @@ pub enum CommunicationType {
|
||||||
error_no_call_id,
|
error_no_call_id,
|
||||||
error_invalid_call_id,
|
error_invalid_call_id,
|
||||||
success,
|
success,
|
||||||
|
|
||||||
|
shorten_link,
|
||||||
|
|
||||||
settings_save,
|
settings_save,
|
||||||
settings_load,
|
settings_load,
|
||||||
settings_list,
|
settings_list,
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@ pub mod api;
|
||||||
pub mod omikron_connection;
|
pub mod omikron_connection;
|
||||||
pub mod omikron_manager;
|
pub mod omikron_manager;
|
||||||
pub mod server;
|
pub mod server;
|
||||||
|
pub mod short_link;
|
||||||
pub mod socket;
|
pub mod socket;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes};
|
||||||
|
use crate::server::short_link::add_short_link;
|
||||||
use crate::sql::connection_status::ConnectionType;
|
use crate::sql::connection_status::ConnectionType;
|
||||||
use crate::sql::sql::{self, get_by_user_id, get_by_username, get_iota_by_id, get_omikron_by_id};
|
use crate::sql::sql::{self, get_by_user_id, get_by_username, get_iota_by_id, get_omikron_by_id};
|
||||||
use crate::sql::user_online_tracker::{self};
|
use crate::sql::user_online_tracker::{self};
|
||||||
|
|
@ -472,6 +473,21 @@ impl OmikronConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cv.is_type(CommunicationType::shorten_link) {
|
||||||
|
if let Some(link) = cv.get_data(DataTypes::link) {
|
||||||
|
if let Some(link) = link.as_str() {
|
||||||
|
if let Ok(short_link) = add_short_link(link).await {
|
||||||
|
let response = CommunicationValue::new(CommunicationType::shorten_link)
|
||||||
|
.with_id(cv.get_id())
|
||||||
|
.add_data(DataTypes::link, JsonValue::String(short_link));
|
||||||
|
self.send_message(&response).await;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let response =
|
let response =
|
||||||
CommunicationValue::new(CommunicationType::error_not_found).with_id(cv.get_id());
|
CommunicationValue::new(CommunicationType::error_not_found).with_id(cv.get_id());
|
||||||
self.send_message(&response).await;
|
self.send_message(&response).await;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::log;
|
use crate::log;
|
||||||
use crate::server::api;
|
use crate::server::api;
|
||||||
|
use crate::server::short_link::get_short_link;
|
||||||
use crate::server::socket;
|
use crate::server::socket;
|
||||||
use crate::util::file_util::load_file_buf;
|
use crate::util::file_util::load_file_buf;
|
||||||
|
|
||||||
|
|
@ -126,6 +127,22 @@ impl Service<HttpRequest<Incoming>> for HttpService {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(api::handle(&path, headers.clone(), body_string).await)
|
Ok(api::handle(&path, headers.clone(), body_string).await)
|
||||||
|
} else if path.starts_with("/direct") {
|
||||||
|
let short = path.split('/').nth(2).unwrap_or_default();
|
||||||
|
if let Ok(long) = get_short_link(short).await {
|
||||||
|
let response = HttpResponse::builder()
|
||||||
|
.status(StatusCode::FOUND)
|
||||||
|
.header("Location", long)
|
||||||
|
.body(Full::new(Bytes::from("")))
|
||||||
|
.unwrap();
|
||||||
|
Ok(response)
|
||||||
|
} else {
|
||||||
|
let response = HttpResponse::builder()
|
||||||
|
.status(StatusCode::NOT_FOUND)
|
||||||
|
.body(Full::new(Bytes::from("Short link not found")))
|
||||||
|
.unwrap();
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let response = HttpResponse::builder()
|
let response = HttpResponse::builder()
|
||||||
.status(StatusCode::BAD_REQUEST)
|
.status(StatusCode::BAD_REQUEST)
|
||||||
|
|
|
||||||
77
src/server/short_link.rs
Normal file
77
src/server/short_link.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
use dashmap::DashMap;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use rand::{Rng, thread_rng};
|
||||||
|
|
||||||
|
static LINKS: Lazy<DashMap<String, String>> = Lazy::new(DashMap::new);
|
||||||
|
|
||||||
|
const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPRSTUVWXYZ#1234567890";
|
||||||
|
|
||||||
|
pub async fn add_short_link(long: &str) -> Result<String, ()> {
|
||||||
|
let raw = generate_unique_short_link().await;
|
||||||
|
LINKS.insert(raw.clone(), long.to_string());
|
||||||
|
|
||||||
|
Ok(format!(
|
||||||
|
"omega.tensamin.net/direct/{}",
|
||||||
|
format_with_dashes(&raw)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn generate_unique_short_link() -> String {
|
||||||
|
loop {
|
||||||
|
let short = generate_short_link().await;
|
||||||
|
if !LINKS.contains_key(&short) {
|
||||||
|
return short;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn generate_short_link() -> String {
|
||||||
|
let len = short_length();
|
||||||
|
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
(0..len)
|
||||||
|
.map(|_| {
|
||||||
|
let idx = rng.gen_range(0..CHARSET.len());
|
||||||
|
CHARSET[idx] as char
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_short_link(short: &str) -> Result<String, ()> {
|
||||||
|
let normalized = normalize_short(short);
|
||||||
|
|
||||||
|
LINKS.get(&normalized).map(|v| v.value().clone()).ok_or(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- helpers ---------------- */
|
||||||
|
|
||||||
|
fn short_length() -> usize {
|
||||||
|
let count = LINKS.len();
|
||||||
|
|
||||||
|
match count {
|
||||||
|
0..=1_999 => 4,
|
||||||
|
2_000..=999_999 => 8,
|
||||||
|
_ => 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_with_dashes(s: &str) -> String {
|
||||||
|
s.chars()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.chunks(4)
|
||||||
|
.map(|c| c.iter().collect::<String>())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join("-")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_short(input: &str) -> String {
|
||||||
|
input
|
||||||
|
.chars()
|
||||||
|
.filter(|c| *c != '-')
|
||||||
|
.map(|c| match c {
|
||||||
|
'Q' | 'O' => '0',
|
||||||
|
'I' => 'l',
|
||||||
|
_ => c,
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue