Skip to content

Commit

Permalink
Merge pull request TeamFlos#401 from TeamFlos/p2p
Browse files Browse the repository at this point in the history
feat: p2p download support using ANYS
  • Loading branch information
Mivik authored Sep 1, 2024
2 parents 013405c + 826a37a commit a39e52b
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions phira/locales/en-US/settings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ item-lowq = Low quality mode
item-lowq-sub = Enable this if the UI is laggy
item-insecure = Insecure mode
item-insecure-sub = Enable this if you can't use online functionalities. Makes your connection insecure!
item-enable-anys = Enable Anys
item-enable-anys-sub = Utilize Anys gateway to enhance connection quality
item-anys-gateway = Anys gateway
item-anys-gateway-sub = Anys gateway address
item-anys-gateway-invalid = Invalid gateway address
item-adjust = Automatic time adjustment
item-adjust-sub = Adjusts time dynamically to sync the music and beatmap
Expand Down
5 changes: 5 additions & 0 deletions phira/locales/zh-CN/settings.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ item-lowq = 低画质模式
item-lowq-sub = 建议在画面卡顿时启用
item-insecure = 不安全模式
item-insecure-sub = 当无法使用在线功能时可尝试该功能。这会使得你的连接不安全!
item-enable-anys = 启用 Anys
item-enable-anys-sub = 使用 Anys 网关以提升连接质量
item-anys-gateway = Anys 网关
item-anys-gateway-sub = Anys 网关地址
item-anys-gateway-invalid = 无效的网关地址
item-adjust = 自动对齐时间
item-adjust-sub = 自动调整延迟以同步音乐和谱面
Expand Down
9 changes: 8 additions & 1 deletion phira/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@ pub struct Client;
const API_URL: &str = "https://api.phira.cn";

pub fn basic_client_builder() -> ClientBuilder {
let mut builder = reqwest::ClientBuilder::new();
let policy = reqwest::redirect::Policy::custom(|attempt| {
if let Some(_cid) = attempt.url().as_str().strip_prefix("anys://") {
attempt.stop()
} else {
attempt.follow()
}
});
let mut builder = reqwest::ClientBuilder::new().redirect(policy);
if get_data().accept_invalid_cert {
builder = builder.danger_accept_invalid_certs(true);
}
Expand Down
41 changes: 34 additions & 7 deletions phira/src/client/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ mod record;
pub use record::*;

mod user;
use reqwest::{Response, Url};
use tracing::debug;
pub use user::*;

use super::{basic_client_builder, Client, CLIENT_TOKEN};
use super::{basic_client_builder, Client, API_URL, CLIENT_TOKEN};
use crate::{
dir,
dir, get_data,
images::{THUMBNAIL_HEIGHT, THUMBNAIL_WIDTH},
};
use anyhow::{bail, Result};
Expand Down Expand Up @@ -181,7 +183,16 @@ pub struct File {
}
impl File {
fn request(&self) -> reqwest::RequestBuilder {
let req = basic_client_builder().build().unwrap().get(&self.url);
let mut req = basic_client_builder().build().unwrap().get(&self.url);
// TODO: thread safety?
if get_data().enable_anys {
if let Some(path) = self.url.strip_prefix(API_URL) {
if let Some(rest_path) = path.strip_prefix("/files/") {
let url = format!("{API_URL}/anys/{rest_path}");
req = basic_client_builder().build().unwrap().get(url);
}
}
}
if let Some(token) = CLIENT_TOKEN.load().as_ref() {
req.header("Authorization", format!("Bearer {token}"))
} else {
Expand All @@ -190,16 +201,32 @@ impl File {
}

pub async fn fetch(&self) -> Result<Bytes> {
async fn fetch_raw(f: &File) -> Result<Response> {
Ok(f.request().send().await?)
}
match cacache::read(&*CACHE_DIR, &self.url).await {
Ok(data) => Ok(data.into()),
Err(cacache::Error::EntryNotFound(..)) => {
let resp = self.request().send().await?;
let mut resp = fetch_raw(self).await?;
if resp.status().is_redirection() {
let p2p_url = resp.headers().get("location").unwrap().to_str().unwrap().to_owned();
if let Some(cid) = p2p_url.strip_prefix("anys://") {
let cid = cid.to_owned();
let data = get_data();
let new_url = format!("{}/{}", data.anys_gateway, cid);
debug!("p2p redirection: {} -> {}", p2p_url, new_url);
resp = fetch_raw(&File { url: new_url }).await?
} else {
bail!("illegal p2p redirection: {}", p2p_url);
}
}
if !resp.status().is_success() {
bail!("{}", resp.text().await?);
} else {
let bytes = resp.error_for_status()?.bytes().await?;
cacache::write(&*CACHE_DIR, &self.url, &bytes).await?;
Ok(bytes)
}
let bytes = resp.error_for_status()?.bytes().await?;
cacache::write(&*CACHE_DIR, &self.url, &bytes).await?;
Ok(bytes)
}
Err(err) => Err(err.into()),
}
Expand Down
13 changes: 9 additions & 4 deletions phira/src/data.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{
client::{Character, Ptr, User},
dir,
};
use crate::{client::{Character, Ptr, User}, dir};
use anyhow::Result;
use chrono::{DateTime, Utc};
use prpr::{
Expand Down Expand Up @@ -69,6 +66,10 @@ pub struct LocalChart {
pub played_unlock: bool,
}

fn default_anys_gateway() -> String {
"https://anys.mivik.moe".to_string()
}

#[derive(Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Data {
Expand All @@ -88,6 +89,10 @@ pub struct Data {
pub terms_modified: Option<String>,
pub ignored_version: Option<semver::Version>,
pub character: Option<Character>,

pub enable_anys: bool,
#[serde(default = "default_anys_gateway")]
pub anys_gateway: String,
}

impl Data {
Expand Down
4 changes: 2 additions & 2 deletions phira/src/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use crate::{
get_data_mut,
page::Fader,
save_data,
scene::{check_read_tos_and_policy, dispatch_tos_task, JUST_ACCEPTED_TOS, JUST_LOADED_TOS, LOAD_TOS_TASK},
scene::{check_read_tos_and_policy, dispatch_tos_task, JUST_ACCEPTED_TOS},
};
use anyhow::Result;
use macroquad::prelude::*;
use once_cell::sync::Lazy;
use prpr::{
core::BOLD_FONT,
ext::{semi_black, semi_white, RectExt},
scene::{request_input, request_password, return_input, show_error, show_message, take_input, FullLoadingView},
scene::{request_input, request_password, return_input, show_error, show_message, take_input},
task::Task,
ui::{DRectButton, Dialog, Ui},
};
Expand Down
29 changes: 29 additions & 0 deletions phira/src/page/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use prpr::{
scene::{request_input, return_input, show_error, take_input},
ui::{DRectButton, Scroll, Slider, Ui},
};
use reqwest::Url;
use std::{borrow::Cow, net::ToSocketAddrs, sync::atomic::Ordering};

const ITEM_HEIGHT: f32 = 0.15;
Expand Down Expand Up @@ -273,6 +274,8 @@ struct GeneralList {
mp_addr_btn: DRectButton,
lowq_btn: DRectButton,
insecure_btn: DRectButton,
enable_anys_btn: DRectButton,
anys_gateway_btn: DRectButton,
}

impl GeneralList {
Expand All @@ -296,6 +299,8 @@ impl GeneralList {
mp_addr_btn: DRectButton::new(),
lowq_btn: DRectButton::new(),
insecure_btn: DRectButton::new(),
enable_anys_btn: DRectButton::new(),
anys_gateway_btn: DRectButton::new(),
}
}

Expand Down Expand Up @@ -336,6 +341,14 @@ impl GeneralList {
data.accept_invalid_cert ^= true;
return Ok(Some(true));
}
if self.enable_anys_btn.touch(touch, t) {
data.enable_anys ^= true;
return Ok(Some(true));
}
if self.anys_gateway_btn.touch(touch, t) {
request_input("anys_gateway", &data.anys_gateway);
return Ok(Some(true));
}
Ok(None)
}

Expand All @@ -356,6 +369,14 @@ impl GeneralList {
data.config.mp_address = text;
return Ok(true);
}
} else if id == "anys_gateway" {
if let Err(err) = Url::parse(&text) {
show_error(anyhow::Error::new(err).context(tl!("item-anys-gateway-invalid")));
return Ok(false);
} else {
data.anys_gateway = text.trim_end_matches('/').to_string();
return Ok(true);
}
} else {
return_input(id, text);
}
Expand Down Expand Up @@ -408,6 +429,14 @@ impl GeneralList {
render_title(ui, tl!("item-insecure"), Some(tl!("item-insecure-sub")));
render_switch(ui, rr, t, &mut self.insecure_btn, data.accept_invalid_cert);
}
item! {
render_title(ui, tl!("item-enable-anys"), Some(tl!("item-enable-anys-sub")));
render_switch(ui, rr, t, &mut self.enable_anys_btn, data.enable_anys);
}
item! {
render_title(ui, tl!("item-anys-gateway"), Some(tl!("item-anys-gateway-sub")));
self.anys_gateway_btn.render_text(ui, rr, t, &data.anys_gateway, 0.4, false);
}
self.lang_btn.render_top(ui, t, 1.);
(w, h)
}
Expand Down

0 comments on commit a39e52b

Please sign in to comment.