mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-01 21:59:43 +02:00
Replace the Go backend with the Rust workspace and route Android/iOS through UniFFI bindings. Include the migrated extension runtime, network, providers, media metadata, downloads and library operations, with version 5.0.0+147. Remove Go sources, adapters, native build selection and CI dependencies. Build Rust unconditionally and lock the iOS Rust pod using a relative path. Retain legacy source and migration evidence in a local ignored archive. Validation: Android Kotlin compile and 53 native tests; Swift Rust-branch equivalence and syntax; CocoaPods install; workflow, shell, Ruby, plist and diff checks. Reuse the preceding 100 Rust tests, fmt/Clippy and five-ABI build checkpoint; no new APK or iOS application build for this cleanup. Known follow-up: URL/URLSearchParams globals are missing from the Rust JS runtime. A controlled extension replay confirms a URL-resolution regression; this commit does not fix that runtime gap.
118 lines
3.6 KiB
Rust
118 lines
3.6 KiB
Rust
use chrono::{DateTime, Datelike, Timelike, Utc};
|
|
use serde::Serialize;
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct LocalTime {
|
|
year: i32,
|
|
month: u32,
|
|
day: u32,
|
|
hour: u32,
|
|
minute: u32,
|
|
second: u32,
|
|
weekday: u32,
|
|
offset_minutes: i32,
|
|
timezone: String,
|
|
timestamp: i64,
|
|
}
|
|
|
|
pub fn local_time() -> LocalTime {
|
|
local_time_at(Utc::now().timestamp()).expect("current timestamp fits calendar range")
|
|
}
|
|
|
|
pub fn local_time_at(timestamp: i64) -> Result<LocalTime, String> {
|
|
let (offset, _, timezone) = zone_at(timestamp);
|
|
let local = DateTime::from_timestamp(
|
|
timestamp
|
|
.checked_add(i64::from(offset))
|
|
.ok_or("timestamp overflow")?,
|
|
0,
|
|
)
|
|
.ok_or("timestamp outside calendar range")?;
|
|
Ok(LocalTime {
|
|
year: local.year(),
|
|
month: local.month(),
|
|
day: local.day(),
|
|
hour: local.hour(),
|
|
minute: local.minute(),
|
|
second: local.second(),
|
|
weekday: local.weekday().num_days_from_sunday(),
|
|
offset_minutes: -(offset / 60),
|
|
timezone,
|
|
timestamp,
|
|
})
|
|
}
|
|
|
|
pub(crate) fn zone_at(timestamp: i64) -> (i32, String, String) {
|
|
// Go 1.26's Android and iOS initLocal use UTC. Host Unix builds load TZ or
|
|
// /etc/localtime once; retain that distinction in the compatibility SDK.
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
{
|
|
let _ = timestamp;
|
|
(0, "UTC".into(), "UTC".into())
|
|
}
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
{
|
|
static LOCAL: std::sync::LazyLock<(tz::TimeZone, String)> =
|
|
std::sync::LazyLock::new(load_zone);
|
|
let (zone, name) = &*LOCAL;
|
|
match zone.find_local_time_type(timestamp) {
|
|
Ok(kind) => (
|
|
kind.ut_offset(),
|
|
kind.time_zone_designation().into(),
|
|
name.clone(),
|
|
),
|
|
Err(_) => (0, "UTC".into(), "UTC".into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
fn load_zone() -> (tz::TimeZone, String) {
|
|
use std::io::Read;
|
|
let load = |path: &std::path::Path| {
|
|
let file = std::fs::File::open(path).ok()?;
|
|
let mut data = Vec::new();
|
|
file.take(10 * 1024 * 1024 + 1)
|
|
.read_to_end(&mut data)
|
|
.ok()?;
|
|
if data.len() > 10 * 1024 * 1024 {
|
|
return None;
|
|
}
|
|
tz::TimeZone::from_tz_data(&data).ok()
|
|
};
|
|
let configured = std::env::var("TZ").ok();
|
|
if configured.is_none() {
|
|
if let Some(zone) = load(std::path::Path::new("/etc/localtime")) {
|
|
return (zone, "Local".into());
|
|
}
|
|
} else if let Some(raw) = configured {
|
|
let name = raw.strip_prefix(':').unwrap_or(&raw);
|
|
if name.starts_with('/') {
|
|
if let Some(zone) = load(std::path::Path::new(name)) {
|
|
return (
|
|
zone,
|
|
if name == "/etc/localtime" {
|
|
"Local"
|
|
} else {
|
|
name
|
|
}
|
|
.into(),
|
|
);
|
|
}
|
|
} else if !name.is_empty() && name != "UTC" && !name.contains("..") {
|
|
for directory in [
|
|
"/usr/share/zoneinfo",
|
|
"/usr/share/lib/zoneinfo",
|
|
"/usr/lib/locale/TZ",
|
|
"/etc/zoneinfo",
|
|
] {
|
|
if let Some(zone) = load(&std::path::Path::new(directory).join(name)) {
|
|
return (zone, name.into());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
(tz::TimeZone::utc(), "UTC".into())
|
|
}
|