-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(swagger-ui): cache swagger zip #1214
Changes from 1 commit
2bd2174
c2ed269
0410c94
dcf94c3
e8a3799
6f73708
93a9abe
90b4746
cbefe60
1eea457
5b9a654
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I am not educated enough, do we need all that C crap and pointer juggling? Aren't there a better and perhaps more simply way to the the same result or at least similar result? As I understand this tries to use the users local cache dir for caching the data. I'd rather place it just the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd expect at least some level of documentation what all that black magic does. Whats more is that I can guarantee that there are few that even dare to touch this code and I don't want to maintain this code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I also doesn't like that. though it's that expressive because the original dev wanted to support as many platforms as he can. but it's just for caching and I guess windows/linux/macos support is enough so we can simplify it into few lines There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
We shouldn't use OUTPUT dir the whole idea is to cache the downlloaded file in known location that will be still cached even if we rebuild the whole project / delete target folder and rebuild There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It just returns the cache directory on different platforms |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
// based on https://github.com/pykeio/ort/blob/main/ort-sys/src/internal/dirs.rs and https://github.com/dirs-dev/dirs-sys-rs/blob/main/src/lib.rs | ||
|
||
pub const PACKAGE_NAME: &str = "utoipa-swagger-ui"; | ||
|
||
#[cfg(all(target_os = "windows", target_arch = "x86"))] | ||
macro_rules! win32_extern { | ||
($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( | ||
#[link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated")] | ||
extern $abi { | ||
$(#[$doc])? | ||
$(#[link_name=$link_name])? | ||
fn $($function)*; | ||
} | ||
) | ||
} | ||
#[cfg(all(target_os = "windows", not(target_arch = "x86")))] | ||
macro_rules! win32_extern { | ||
($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( | ||
#[link(name = $library, kind = "raw-dylib", modifiers = "+verbatim")] | ||
extern "C" { | ||
$(#[$doc])? | ||
$(#[link_name=$link_name])? | ||
fn $($function)*; | ||
} | ||
) | ||
} | ||
|
||
#[cfg(target_os = "windows")] | ||
#[allow(non_camel_case_types, clippy::upper_case_acronyms)] | ||
mod windows { | ||
use std::{ | ||
ffi::{c_void, OsString}, | ||
os::windows::prelude::OsStringExt, | ||
path::PathBuf, | ||
ptr, slice, | ||
}; | ||
|
||
#[repr(C)] | ||
#[derive(Clone, Copy)] | ||
struct GUID { | ||
data1: u32, | ||
data2: u16, | ||
data3: u16, | ||
data4: [u8; 8], | ||
} | ||
|
||
impl GUID { | ||
pub const fn from_u128(uuid: u128) -> Self { | ||
Self { | ||
data1: (uuid >> 96) as u32, | ||
data2: (uuid >> 80 & 0xffff) as u16, | ||
data3: (uuid >> 64 & 0xffff) as u16, | ||
#[allow(clippy::cast_possible_truncation)] | ||
data4: (uuid as u64).to_be_bytes(), | ||
} | ||
} | ||
} | ||
|
||
type HRESULT = i32; | ||
type PWSTR = *mut u16; | ||
type PCWSTR = *const u16; | ||
type HANDLE = isize; | ||
type KNOWN_FOLDER_FLAG = i32; | ||
|
||
win32_extern!("SHELL32.DLL" "system" fn SHGetKnownFolderPath(rfid: *const GUID, dwflags: KNOWN_FOLDER_FLAG, htoken: HANDLE, ppszpath: *mut PWSTR) -> HRESULT); | ||
win32_extern!("KERNEL32.DLL" "system" fn lstrlenW(lpstring: PCWSTR) -> i32); | ||
win32_extern!("OLE32.DLL" "system" fn CoTaskMemFree(pv: *const ::core::ffi::c_void) -> ()); | ||
|
||
fn known_folder(folder_id: GUID) -> Option<PathBuf> { | ||
unsafe { | ||
let mut path_ptr: PWSTR = ptr::null_mut(); | ||
let result = SHGetKnownFolderPath(&folder_id, 0, HANDLE::default(), &mut path_ptr); | ||
if result == 0 { | ||
let len = lstrlenW(path_ptr) as usize; | ||
let path = slice::from_raw_parts(path_ptr, len); | ||
let ostr: OsString = OsStringExt::from_wide(path); | ||
CoTaskMemFree(path_ptr as *const c_void); | ||
Some(PathBuf::from(ostr)) | ||
} else { | ||
CoTaskMemFree(path_ptr as *const c_void); | ||
None | ||
} | ||
} | ||
} | ||
|
||
#[allow(clippy::unusual_byte_groupings)] | ||
const FOLDERID_LOCAL_APP_DATA: GUID = GUID::from_u128(0xf1b32785_6fba_4fcf_9d557b8e7f157091); | ||
|
||
#[must_use] | ||
pub fn known_folder_local_app_data() -> Option<PathBuf> { | ||
known_folder(FOLDERID_LOCAL_APP_DATA) | ||
} | ||
} | ||
#[cfg(target_os = "windows")] | ||
#[must_use] | ||
pub fn cache_dir() -> Option<std::path::PathBuf> { | ||
self::windows::known_folder_local_app_data().map(|h| h.join(PACKAGE_NAME)) | ||
} | ||
|
||
#[cfg(unix)] | ||
#[allow(non_camel_case_types)] | ||
mod unix { | ||
use std::{ | ||
env, | ||
ffi::{c_char, c_int, c_long, CStr, OsString}, | ||
mem, | ||
os::unix::prelude::OsStringExt, | ||
path::PathBuf, | ||
ptr, | ||
}; | ||
|
||
type uid_t = u32; | ||
type gid_t = u32; | ||
type size_t = usize; | ||
#[repr(C)] | ||
struct passwd { | ||
pub pw_name: *mut c_char, | ||
pub pw_passwd: *mut c_char, | ||
pub pw_uid: uid_t, | ||
pub pw_gid: gid_t, | ||
pub pw_gecos: *mut c_char, | ||
pub pw_dir: *mut c_char, | ||
pub pw_shell: *mut c_char, | ||
} | ||
|
||
extern "C" { | ||
fn sysconf(name: c_int) -> c_long; | ||
fn getpwuid_r( | ||
uid: uid_t, | ||
pwd: *mut passwd, | ||
buf: *mut c_char, | ||
buflen: size_t, | ||
result: *mut *mut passwd, | ||
) -> c_int; | ||
fn getuid() -> uid_t; | ||
} | ||
|
||
const SC_GETPW_R_SIZE_MAX: c_int = 70; | ||
|
||
#[must_use] | ||
#[cfg(target_os = "linux")] | ||
pub fn is_absolute_path(path: OsString) -> Option<PathBuf> { | ||
let path = PathBuf::from(path); | ||
if path.is_absolute() { | ||
Some(path) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
#[cfg(not(target_os = "windows"))] | ||
#[must_use] | ||
pub fn home_dir() -> Option<PathBuf> { | ||
return env::var_os("HOME") | ||
.and_then(|h| if h.is_empty() { None } else { Some(h) }) | ||
.or_else(|| unsafe { fallback() }) | ||
.map(PathBuf::from); | ||
|
||
#[cfg(any(target_os = "android", target_os = "ios", target_os = "emscripten"))] | ||
unsafe fn fallback() -> Option<OsString> { | ||
None | ||
} | ||
#[cfg(not(any(target_os = "android", target_os = "ios", target_os = "emscripten")))] | ||
unsafe fn fallback() -> Option<OsString> { | ||
let amt = match sysconf(SC_GETPW_R_SIZE_MAX) { | ||
n if n < 0 => 512, | ||
n => n as usize, | ||
}; | ||
let mut buf = Vec::with_capacity(amt); | ||
let mut passwd: passwd = mem::zeroed(); | ||
let mut result = ptr::null_mut(); | ||
match getpwuid_r( | ||
getuid(), | ||
&mut passwd, | ||
buf.as_mut_ptr(), | ||
buf.capacity(), | ||
&mut result, | ||
) { | ||
0 if !result.is_null() => { | ||
let ptr = passwd.pw_dir as *const _; | ||
let bytes = CStr::from_ptr(ptr).to_bytes(); | ||
if bytes.is_empty() { | ||
None | ||
} else { | ||
Some(OsStringExt::from_vec(bytes.to_vec())) | ||
} | ||
} | ||
_ => None, | ||
} | ||
} | ||
} | ||
} | ||
|
||
#[cfg(target_os = "linux")] | ||
#[must_use] | ||
pub fn cache_dir() -> Option<std::path::PathBuf> { | ||
std::env::var_os("XDG_CACHE_HOME") | ||
.and_then(self::unix::is_absolute_path) | ||
.or_else(|| self::unix::home_dir().map(|h| h.join(".cache").join(PACKAGE_NAME))) | ||
} | ||
|
||
#[cfg(target_os = "macos")] | ||
#[must_use] | ||
pub fn cache_dir() -> Option<std::path::PathBuf> { | ||
self::unix::home_dir().map(|h| h.join("Library/Caches").join(PACKAGE_NAME)) | ||
} |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than using See more here: The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! didn't knew we can do the same thing without using mod.rs files. thanks |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod dirs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what happens if the user changes the url? I guess the validation will then just fail?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it is only used as a suffix, well this is not very good to be hard coded because users can change the
SWAGGER_UI_DOWNLOAD_URL
which effectively is changing the version that changes the hash as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should avoid use cache if user supplied the URL