You've already forked AstralRinth
* Update Rust version * Update async-compression 0.4.25 -> 0.4.27 * Update async-tungstenite 0.29.1 -> 0.30.0 * Update bytemuck 1.23.0 -> 1.23.1 * Update clap 4.5.40 -> 4.5.43 * Update deadpool-redis 0.21.1 -> 0.22.0 and redis 0.31.0 -> 0.32.4 * Update enumset 1.1.6 -> 1.1.7 * Update hyper-util 0.1.14 -> 0.1.16 * Update indexmap 2.9.0 -> 2.10.0 * Update indicatif 0.17.11 -> 0.18.0 * Update jemalloc_pprof 0.7.0 -> 0.8.1 * Update lettre 0.11.17 -> 0.11.18 * Update meilisearch-sdk 0.28.0 -> 0.29.1 * Update notify 8.0.0 -> 8.2.0 and notify-debouncer-mini 0.6.0 -> 0.7.0 * Update quick-xml 0.37.5 -> 0.38.1 * Fix theseus lint * Update reqwest 0.12.20 -> 0.12.22 * Cargo fmt in theseus * Update rgb 0.8.50 -> 0.8.52 * Update sentry 0.41.0 -> 0.42.0 and sentry-actix 0.41.0 -> 0.42.0 * Update serde_json 1.0.140 -> 1.0.142 * Update serde_with 3.13.0 -> 3.14.0 * Update spdx 0.10.8 -> 0.10.9 * Update sysinfo 0.35.2 -> 0.36.1 * Update tauri suite * Fix build by updating mappings * Update tokio 1.45.1 -> 1.47.1 and tokio-util 0.7.15 -> 0.7.16 * Update tracing-actix-web 0.7.18 -> 0.7.19 * Update zip 4.2.0 -> 4.3.0 * Misc Cargo.lock updates * Update Dockerfiles
220 lines
6.2 KiB
Rust
220 lines
6.2 KiB
Rust
use std::collections::HashSet;
|
|
use std::time::{Duration, Instant};
|
|
use tauri::plugin::TauriPlugin;
|
|
use tauri::{Manager, PhysicalPosition, PhysicalSize, Runtime};
|
|
use tauri_plugin_opener::OpenerExt;
|
|
use theseus::settings;
|
|
use tokio::sync::RwLock;
|
|
|
|
pub struct AdsState {
|
|
pub shown: bool,
|
|
pub modal_shown: bool,
|
|
pub last_click: Option<Instant>,
|
|
pub malicious_origins: HashSet<String>,
|
|
}
|
|
|
|
const AD_LINK: &str = "https://modrinth.com/wrapper/app-ads-cookie";
|
|
|
|
pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|
tauri::plugin::Builder::<R>::new("ads")
|
|
.setup(|app, _api| {
|
|
app.manage(RwLock::new(AdsState {
|
|
shown: true,
|
|
modal_shown: false,
|
|
last_click: None,
|
|
malicious_origins: HashSet::new(),
|
|
}));
|
|
|
|
// We refresh the ads window every 5 minutes for performance
|
|
let app = app.clone();
|
|
tauri::async_runtime::spawn(async move {
|
|
loop {
|
|
if let Some(webview) = app.webviews().get_mut("ads-window")
|
|
{
|
|
let _ = webview.navigate(AD_LINK.parse().unwrap());
|
|
}
|
|
|
|
tokio::time::sleep(std::time::Duration::from_secs(60 * 5))
|
|
.await;
|
|
}
|
|
});
|
|
|
|
Ok(())
|
|
})
|
|
.invoke_handler(tauri::generate_handler![
|
|
init_ads_window,
|
|
hide_ads_window,
|
|
show_ads_window,
|
|
record_ads_click,
|
|
open_link,
|
|
get_ads_personalization,
|
|
])
|
|
.build()
|
|
}
|
|
|
|
fn get_webview_position<R: Runtime>(
|
|
app: &tauri::AppHandle<R>,
|
|
dpr: f32,
|
|
) -> crate::api::Result<(PhysicalPosition<f32>, PhysicalSize<f32>)> {
|
|
let main_window = app.get_window("main").unwrap();
|
|
|
|
let width = 300.0 * dpr;
|
|
let height = 250.0 * dpr;
|
|
|
|
let main_window_size = main_window.outer_size()?;
|
|
let x = (main_window_size.width as f32) - width;
|
|
let y = (main_window_size.height as f32) - height;
|
|
|
|
Ok((
|
|
PhysicalPosition::new(x, y),
|
|
PhysicalSize::new(width, height),
|
|
))
|
|
}
|
|
|
|
#[tauri::command]
|
|
#[cfg(not(target_os = "linux"))]
|
|
pub async fn init_ads_window<R: Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
dpr: f32,
|
|
override_shown: bool,
|
|
) -> crate::api::Result<()> {
|
|
use tauri::WebviewUrl;
|
|
const LINK_SCRIPT: &str = include_str!("ads-init.js");
|
|
|
|
let state = app.state::<RwLock<AdsState>>();
|
|
let mut state = state.write().await;
|
|
|
|
if override_shown {
|
|
state.shown = true;
|
|
}
|
|
|
|
if state.modal_shown {
|
|
return Ok(());
|
|
}
|
|
|
|
if let Ok((position, size)) = get_webview_position(&app, dpr) {
|
|
if let Some(webview) = app.webviews().get("ads-window") {
|
|
if state.shown {
|
|
let _ = webview.set_position(position);
|
|
let _ = webview.set_size(size);
|
|
} else {
|
|
let _ =
|
|
webview.set_position(PhysicalPosition::new(-1000, -1000));
|
|
}
|
|
} else if let Some(window) = app.get_window("main") {
|
|
let _ = window.add_child(
|
|
tauri::webview::WebviewBuilder::new(
|
|
"ads-window",
|
|
WebviewUrl::External(
|
|
AD_LINK.parse().unwrap(),
|
|
),
|
|
)
|
|
.initialization_script(LINK_SCRIPT)
|
|
// .initialization_script_for_main_only(LINK_SCRIPT, false)
|
|
.user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36")
|
|
.zoom_hotkeys_enabled(false)
|
|
.transparent(true),
|
|
if state.shown {
|
|
position
|
|
} else {
|
|
PhysicalPosition::new(-1000.0, -1000.0)
|
|
},
|
|
size,
|
|
);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
// TODO: make ads work on linux
|
|
#[tauri::command]
|
|
#[cfg(target_os = "linux")]
|
|
pub async fn init_ads_window() {}
|
|
|
|
#[tauri::command]
|
|
pub async fn show_ads_window<R: Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
dpr: f32,
|
|
) -> crate::api::Result<()> {
|
|
if let Some(webview) = app.webviews().get("ads-window") {
|
|
let state = app.state::<RwLock<AdsState>>();
|
|
let mut state = state.write().await;
|
|
|
|
state.modal_shown = false;
|
|
|
|
if state.shown {
|
|
let (position, size) = get_webview_position(&app, dpr)?;
|
|
let _ = webview.set_size(size);
|
|
let _ = webview.set_position(position);
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn hide_ads_window<R: Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
reset: Option<bool>,
|
|
) -> crate::api::Result<()> {
|
|
if let Some(webview) = app.webviews().get("ads-window") {
|
|
let state = app.state::<RwLock<AdsState>>();
|
|
let mut state = state.write().await;
|
|
|
|
if reset.unwrap_or(false) {
|
|
state.shown = false;
|
|
} else {
|
|
state.modal_shown = true;
|
|
}
|
|
|
|
let _ = webview.set_position(PhysicalPosition::new(-1000, -1000));
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn record_ads_click<R: Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
) -> crate::api::Result<()> {
|
|
let state = app.state::<RwLock<AdsState>>();
|
|
|
|
let mut state = state.write().await;
|
|
state.last_click = Some(Instant::now());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn open_link<R: Runtime>(
|
|
app: tauri::AppHandle<R>,
|
|
path: String,
|
|
origin: String,
|
|
) -> crate::api::Result<()> {
|
|
let state = app.state::<RwLock<AdsState>>();
|
|
let mut state = state.write().await;
|
|
|
|
if url::Url::parse(&path).is_ok()
|
|
&& !state.malicious_origins.contains(&origin)
|
|
&& let Some(last_click) = state.last_click
|
|
&& last_click.elapsed() < Duration::from_millis(100)
|
|
{
|
|
let _ = app.opener().open_url(&path, None::<String>);
|
|
state.last_click = None;
|
|
|
|
return Ok(());
|
|
}
|
|
|
|
tracing::info!("Malicious click: {path} origin {origin}");
|
|
state.malicious_origins.insert(origin);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn get_ads_personalization() -> crate::api::Result<bool> {
|
|
let res = settings::get().await?;
|
|
Ok(res.personalized_ads)
|
|
}
|