You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
2.4 KiB

use std::ffi::{c_char, c_double, CStr, CString};
use chrono::Local;
use chrono_tz::{Tz, TZ_VARIANTS};
use strsim::levenshtein;
#[no_mangle]
pub extern "C" fn id() -> *const c_char {
str_to_ptr("time")
}
#[no_mangle]
pub extern "C" fn name() -> *const c_char {
str_to_ptr("Time")
}
#[no_mangle]
pub extern "C" fn panel() -> *const c_char {
str_to_ptr(include_str!("./panel/dist/index.js"))
}
#[no_mangle]
pub extern "C" fn get_priority(data: *const c_char) -> c_double {
if ptr_to_string(data).starts_with("time") {
100.0
} else {
0.0
}
}
#[no_mangle]
pub extern "C" fn get_timezone_name(data: *const c_char) -> *const c_char {
let data = ptr_to_string(data);
let local_timezone = iana_time_zone::get_timezone().unwrap_or_default();
if data == "" {
return str_to_ptr(&local_timezone);
}
if let Some(timezone) = get_closest_zone(data) {
return str_to_ptr(&timezone.to_string());
};
str_to_ptr("INVALID_TIME_ZONE")
}
#[no_mangle]
pub extern "C" fn get_time(data: *const c_char) -> *const c_char {
let data = ptr_to_string(data);
let Some(timezone) = get_closest_zone(data) else {
return str_to_ptr("INVALID_TIME_ZONE");
};
let current = Local::now();
let converted = current.with_timezone(&timezone);
let converted_string = converted.time().format("%H:%M:%S").to_string();
str_to_ptr(&converted_string)
}
#[no_mangle]
pub extern "C" fn get_local_time() -> *const c_char {
let current = Local::now();
let current_string = current.time().format("%H:%M:%S").to_string();
str_to_ptr(&current_string)
}
fn get_closest_zone(zone: String) -> Option<Tz> {
let mut closest_distance = usize::MAX;
let mut closest_zone = None;
for variant in TZ_VARIANTS {
let variant_distance = levenshtein(
&zone.to_string().to_lowercase(),
&variant.to_string().to_lowercase(),
);
if variant_distance < closest_distance {
closest_distance = variant_distance;
closest_zone = Some(variant);
}
}
closest_zone
}
fn ptr_to_string(c_buf: *const c_char) -> String {
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
let str_slice: &str = c_str.to_str().unwrap();
let str_buf: String = str_slice.to_owned();
str_buf
}
fn str_to_ptr(str: &str) -> *const c_char {
CString::new(str).unwrap().into_raw()
}