Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
iamcco committed Apr 10, 2024
1 parent 36d3dbd commit 2fe0972
Show file tree
Hide file tree
Showing 13 changed files with 193 additions and 55 deletions.
2 changes: 2 additions & 0 deletions .vim/coc-settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"bufs",
"datap",
"dbuf",
"dioxus",
"dlink",
"eabi",
"eboot",
Expand All @@ -43,6 +44,7 @@
"libime",
"libtai",
"libv",
"libvita",
"livearea",
"mapname",
"modid",
Expand Down
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
![save cloud](./screenshot.png)

### Build
# Save Cloud for PSVita

> 游戏存档云备份工具
## 功能

- 游戏存档备份(本地/云盘)
- 文件管理(本地/云盘)
- ...等

## VitaShell 扫码安装

![qrcode](./qrcode.png)

## 项目结构

- PSVita SDK
- [vitasdk](https://github.com/vitasdk)
- rust
- [vita-rust](https://github.com/vita-rust)
- UI
- > 没有使用 UI 框架,界面使用 [`libvita2d`](https://github.com/xerpi/libvita2d) 绘制
- > TODO: 使用 [dioxus](https://github.com/DioxusLabs/dioxus) 重构
- 网络
- ureq

## Build

- `cargo vita build vpk --release`
- > 如果需要构建 vpk,需要实现 [ `save_cloud_api`](./src/api.rs)
- > 或者删除 `save_cloud_api` 相关部分
### Reference
## Reference

- [vitasdk](https://github.com/vitasdk)
- [vita-rust](https://github.com/vita-rust)
Expand Down
Binary file added qrcode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 12 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::time::Instant;

use crate::{
constant::{BUTTON_HOLDING_DELAY, BUTTON_HOLDING_REPEAT_DELAY},
tai::{unmount_pfs, Titles},
tai::{psv_prevent_sleep, unmount_pfs, Titles},
ui::{
ui_base::UIBase, ui_cloud::UICloud, ui_desktop::UIDesktop, ui_loading::Loading,
ui_titles::UITitles, ui_toast::Toast,
Expand Down Expand Up @@ -76,6 +78,7 @@ impl App {
let mut button_first_active_at = 0;
let mut button_active_at = 0;
let mut buttons_pre = 0;
let mut sleep_lock_at = Instant::now();
'main: loop {
// get the inputs here
let buttons_origins = vita2d_ctrl_peek_positive();
Expand All @@ -94,10 +97,14 @@ impl App {
};
buttons_pre = buttons_origins;

// update
let is_forces = self.update(buttons);
// exit
if !is_forces && is_button(buttons, SceCtrlButtons::SceCtrlStart) {
// if update is forces
if self.update(buttons) {
if sleep_lock_at.elapsed().as_secs() >= 10 {
psv_prevent_sleep();
sleep_lock_at = Instant::now();
}
} else if is_button(buttons, SceCtrlButtons::SceCtrlStart) {
// exit
break 'main;
}
// draw
Expand Down
6 changes: 6 additions & 0 deletions src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,9 @@ pub const DIALOG_CANCEL_TEXT: &str = "(X) 取消";
pub const HOME_PAGE_URL: &str = "https://save-cloud.sketchraw.com?psvita=go";
pub const INVALID_EAT_PANCAKE: &str = "缺少 eat.pancake";
pub const ABOUT_TEXT: &str = "Save Cloud 云存档,扫码访问主页!";

// certificate
pub const SSL_CERT_ENV_KEY: &str = "SSL_CERT_FILE";
pub const CURL_CERT_CURL: &str = "https://curl.se/ca/cacert.pem";
pub const SAVE_CLOUD_CERT: &str = "ux0:data/save-cloud/cacert.pem";
pub const PSV_DEVICE_CERT: &str = "vs0:data/external/cert/CA_LIST.cer";
53 changes: 47 additions & 6 deletions src/tai.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
use core::slice;
use std::{cell::RefCell, ffi::CStr, os::raw::*, ptr::null};
use std::{cell::RefCell, ffi::CStr, fs, os::raw::*, path::Path, ptr::null};

use crate::utils::str_to_c_str;
use crate::utils::{create_parent_if_not_exists, str_to_c_str};

const APP_KERNEL_PATH: &str = "app0:sce_sys/resources/kernel.skprx";
const PLUGIN_KERNEL_PATHS: [&str; 3] = [
"ux0:data/SAVECLOUD/sce_sys/resources/kernel.skprx",
"ux0:VitaShell/module/kernel.skprx",
"ux0:data/save-cloud/kernel.skprx",
];

extern "C" {
fn sceAppUtilLoad();
fn sceAppUtilExit();
fn taiLoad() -> i32;
fn taiLoad(path: *const c_char) -> i32;
fn sceLoad() -> i32;
fn pfs_mount(path: *const c_char) -> i32;
fn pfs_unmount() -> i32;
Expand All @@ -17,6 +24,8 @@ extern "C" {
fn get_account_id() -> c_ulonglong;
// return < 0 if failed
fn change_account_id(fs_path: *const c_char, account_id: c_ulonglong) -> c_char;
fn prevent_to_sleep();
fn launch_app_by_title_id(title_id: *const c_char);
}

#[repr(C)]
Expand Down Expand Up @@ -168,9 +177,28 @@ pub fn sce_app_util_exit() {
/// load skprx module
pub fn tai_load_start_kernel_module() -> Result<(), String> {
unsafe {
let id = taiLoad();
if id < 0 && id != -2147299309 {
return Err(format!("cannot find kernel module: {:#x}\n", id));
let mut loaded = false;
for path in PLUGIN_KERNEL_PATHS {
let path = str_to_c_str(path);
let id = taiLoad(path.as_slice().as_ptr() as *const c_char);
if id >= 0 || id == -2147299309 {
loaded = true;
break;
}
}
if !loaded {
if Path::new(APP_KERNEL_PATH).exists() {
let to_path = PLUGIN_KERNEL_PATHS[2];
create_parent_if_not_exists(to_path).ok();
fs::copy(APP_KERNEL_PATH, to_path).ok();
let path = str_to_c_str(to_path);
let id = taiLoad(path.as_slice().as_ptr() as *const c_char);
if id < 0 && id != -2147299309 {
return Err(format!("cannot find kernel module: {:#x}\n", id));
}
} else {
return Err("cannot find kernel module\n".to_string());
}
}
}

Expand Down Expand Up @@ -238,3 +266,16 @@ pub fn change_psv_account_id(sfo_path: &str, account_id: u64) -> i8 {
change_account_id(c_str.as_slice().as_ptr() as *const c_char, account_id)
}
}

pub fn psv_prevent_sleep() {
unsafe {
prevent_to_sleep();
}
}

pub fn psv_launch_app_by_title_id(title_id: &str) {
unsafe {
let c_str = str_to_c_str(title_id);
launch_app_by_title_id(c_str.as_slice().as_ptr() as *const c_char);
}
}
20 changes: 13 additions & 7 deletions src/ui/ui_cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::{
};

use log::{error, info};
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};

use crate::{
api::{Api, AuthData},
Expand Down Expand Up @@ -79,9 +80,7 @@ impl UICloud {
panel.init();
}
if self.no_data_tex.is_none() {
self.no_data_tex = Some(vita2d_load_png_file(
"ux0:app/SAVECLOUD/sce_sys/resources/no-data.png",
));
self.no_data_tex = Some(vita2d_load_png_file("app0:sce_sys/resources/no-data.png"));
}
if self.qr_code_state.qr_code.is_some() {
if Api::get_read().is_login() {
Expand Down Expand Up @@ -308,9 +307,9 @@ impl UICloud {
Loading::notify_title("正在重命名".to_string());
Loading::notify_desc(input.clone());
match Api::start_file_manager(
&from,
&utf8_percent_encode(&from, NON_ALPHANUMERIC).to_string(),
None,
Some(&input),
Some(&utf8_percent_encode(&input, NON_ALPHANUMERIC).to_string()),
crate::api::ApiOperates::Rename,
) {
Ok(_) => {
Expand Down Expand Up @@ -398,7 +397,7 @@ impl UICloud {
Loading::notify_title("正在删除文件".to_string());
Loading::notify_desc(name.to_string());
match Api::start_file_manager(
&join_path(&from_path, &name),
&utf8_percent_encode(&join_path(&from_path, &name), NON_ALPHANUMERIC).to_string(),
None,
None,
crate::api::ApiOperates::Delete,
Expand Down Expand Up @@ -600,7 +599,7 @@ impl UICloud {
tokio::spawn(async move {
Loading::notify_title("正在解压".to_string());
Loading::notify_desc(name.clone());
match zip_extract(join_path(&from_path, &name), output_dir) {
match zip_extract(join_path(&from_path, &name), output_dir, None) {
Ok(_) => {
do_local_action(
&from_path,
Expand Down Expand Up @@ -668,6 +667,13 @@ impl UICloud {
fs_id: u64,
to_path: &str,
) -> bool {
if !UIDialog::present(&format!("确定下载 {} ?", name)) {
return false;
}
if to_path == "" {
Toast::show("请先选择下载位置!".to_string());
return false;
}
if Path::new(&join_path(to_path, name)).exists() {
Toast::show("目标文件已存在!".to_string());
return false;
Expand Down
18 changes: 13 additions & 5 deletions src/ui/ui_cloud/action/cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ const INIT_RETRY_DURATION: Duration = Duration::from_millis(1000 * 10);
use super::{do_cloud_action, Action};

pub struct CloudAction {
last_init_at: Instant,
last_init_at: Arc<RwLock<Instant>>,
}

impl CloudAction {
pub fn new() -> CloudAction {
CloudAction {
last_init_at: Instant::now() - INIT_RETRY_DURATION,
last_init_at: Arc::new(RwLock::new(Instant::now() - INIT_RETRY_DURATION)),
}
}
}
Expand All @@ -35,11 +35,15 @@ impl Action for CloudAction {
if !Api::get_read().is_login() {
return;
}
if Instant::now() - self.last_init_at < INIT_RETRY_DURATION {
if Arc::strong_count(&self.last_init_at) > 1 {
return;
}
self.last_init_at = Instant::now();
self.do_action("", "/", DirPendingAction::Enter, dir);
if let Ok(last_init_at) = self.last_init_at.try_read() {
if Instant::now() - *last_init_at < INIT_RETRY_DURATION {
return;
}
self.do_action("", "/", DirPendingAction::Enter, dir);
}
}

fn do_action(
Expand All @@ -52,9 +56,13 @@ impl Action for CloudAction {
let dir = Arc::clone(dir);
let path = path.to_string();
let name = item_name.to_string();
let last_init_at = Arc::clone(&self.last_init_at);
Loading::show();
tokio::spawn(async move {
do_cloud_action(&path, &name, action, dir);
if let Ok(mut last_init_at) = last_init_at.write() {
*last_init_at = Instant::now();
}
Loading::hide();
});
}
Expand Down
10 changes: 5 additions & 5 deletions src/ui/ui_desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ use crate::{

use super::ui_base::UIBase;

const IMAGE_ICON_PATH: &str = "ux0:app/SAVECLOUD/sce_sys/resources/icon.png";
const IMAGE_DEVICE_PATH: &str = "ux0:app/SAVECLOUD/sce_sys/resources/device.png";
const IMAGE_CLOUD_PATH: &str = "ux0:app/SAVECLOUD/sce_sys/resources/cloud.png";
const IMAGE_DEVICE_BG_PATH: &str = "ux0:app/SAVECLOUD/sce_sys/resources/device_bg.jpg";
const IMAGE_ICON_PATH: &str = "app0:sce_sys/resources/icon.png";
const IMAGE_DEVICE_PATH: &str = "app0:sce_sys/resources/device.png";
const IMAGE_CLOUD_PATH: &str = "app0:sce_sys/resources/cloud.png";
const IMAGE_DEVICE_BG_PATH: &str = "app0:sce_sys/resources/device_bg.jpg";
const ICON_SIZE: i32 = 70;
const ICON_OFFSET: i32 = 10;
const ICON_GAP: i32 = 20;
const TEXT_VERSION: &str = "V2023.12.26";
const TEXT_VERSION: &str = "V2024.02.28";

pub struct UIDesktop {
selected_idx: i32,
Expand Down
Loading

0 comments on commit 2fe0972

Please sign in to comment.