mirror of
https://github.com/IntQuant/noita_entangled_worlds.git
synced 2025-10-19 15:13:16 +00:00
Proxy self update
This commit is contained in:
parent
42e390cdb9
commit
94432c21e1
6 changed files with 247 additions and 18 deletions
34
noita-proxy/Cargo.lock
generated
34
noita-proxy/Cargo.lock
generated
|
@ -943,6 +943,15 @@ version = "3.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
|
@ -1398,6 +1407,15 @@ dependencies = [
|
|||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.9.0"
|
||||
|
@ -1675,7 +1693,7 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
|
|||
|
||||
[[package]]
|
||||
name = "noita-proxy"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bitcode",
|
||||
"clipboard",
|
||||
|
@ -1686,6 +1704,7 @@ dependencies = [
|
|||
"poll-promise",
|
||||
"rand",
|
||||
"reqwest",
|
||||
"self-replace",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"socket2",
|
||||
|
@ -2388,6 +2407,17 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "self-replace"
|
||||
version = "1.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525db198616b2bcd0f245daf7bfd8130222f7ee6af9ff9984c19a61bf1160c55"
|
||||
dependencies = [
|
||||
"fastrand 1.9.0",
|
||||
"tempfile",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.199"
|
||||
|
@ -2638,7 +2668,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"fastrand 2.1.0",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
|
|
@ -3,7 +3,7 @@ members = ["tangled"]
|
|||
|
||||
[package]
|
||||
name = "noita-proxy"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
@ -28,6 +28,7 @@ serde_json = "1.0.117"
|
|||
thiserror = "1.0.61"
|
||||
poll-promise = "0.3.0"
|
||||
zip = "1.3.1"
|
||||
self-replace = "1.3.7"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
|
|
@ -4,8 +4,9 @@ use std::{
|
|||
|
||||
use bitcode::{Decode, Encode};
|
||||
use clipboard::{ClipboardContext, ClipboardProvider};
|
||||
use eframe::egui::{self, Align2, Color32, Layout};
|
||||
use eframe::egui::{self, Align2, Color32};
|
||||
use mod_manager::{Modmanager, ModmanagerSettings};
|
||||
use self_update::SelfUpdateManager;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use steamworks::{LobbyId, SteamAPIInitError};
|
||||
use tangled::Peer;
|
||||
|
@ -13,6 +14,7 @@ use tracing::info;
|
|||
|
||||
pub mod messages;
|
||||
mod mod_manager;
|
||||
mod self_update;
|
||||
pub mod releases;
|
||||
|
||||
#[derive(Debug, Decode, Encode, Clone)]
|
||||
|
@ -28,6 +30,7 @@ enum AppState {
|
|||
ModManager,
|
||||
Netman { netman: Arc<net::NetManager> },
|
||||
Error { message: String },
|
||||
SelfUpdate,
|
||||
}
|
||||
|
||||
struct SteamState {
|
||||
|
@ -57,8 +60,6 @@ struct AppSavedState {
|
|||
addr: String,
|
||||
debug_mode: bool,
|
||||
use_constant_seed: bool,
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Default for AppSavedState {
|
||||
|
@ -76,7 +77,8 @@ pub struct App {
|
|||
modmanager: Modmanager,
|
||||
steam_state: Result<SteamState, SteamAPIInitError>,
|
||||
saved_state: AppSavedState,
|
||||
modmanager_settings: ModmanagerSettings
|
||||
modmanager_settings: ModmanagerSettings,
|
||||
self_update: SelfUpdateManager,
|
||||
}
|
||||
|
||||
const MODMANAGER: &str = "modman";
|
||||
|
@ -94,6 +96,7 @@ impl App {
|
|||
modmanager: Modmanager::default(),
|
||||
steam_state: SteamState::new(),saved_state,
|
||||
modmanager_settings,
|
||||
self_update: SelfUpdateManager::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,9 +200,10 @@ impl eframe::App for App {
|
|||
ui.label(format!("Could not init steam networking: {}", err));
|
||||
}
|
||||
}
|
||||
ui.with_layout(Layout::right_to_left(egui::Align::Max), |ui| {
|
||||
ui.label(concat!("Noita Proxy version ", env!("CARGO_PKG_VERSION")))
|
||||
})
|
||||
self.self_update.display_version(ui);
|
||||
if self.self_update.request_update {
|
||||
self.state = AppState::SelfUpdate;
|
||||
}
|
||||
});
|
||||
}
|
||||
AppState::Netman { netman } => {
|
||||
|
@ -262,6 +266,12 @@ impl eframe::App for App {
|
|||
self.state = AppState::Connect;
|
||||
}
|
||||
},
|
||||
AppState::SelfUpdate => {
|
||||
egui::Window::new("Self update").auto_sized().anchor(Align2::CENTER_CENTER, [0.0, 0.0])
|
||||
.show(ctx, |ui| {
|
||||
self.self_update.self_update(ui);
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -262,11 +262,11 @@ fn mod_downloader_for(
|
|||
.and_then(|asset| asset.download(&client, &download_path))
|
||||
}
|
||||
|
||||
fn extract_and_remove_zip(zip_file: PathBuf, extact_to: PathBuf) -> Result<(), ReleasesError> {
|
||||
fn extract_and_remove_zip(zip_file: PathBuf, extract_to: PathBuf) -> Result<(), ReleasesError> {
|
||||
let reader = File::open(&zip_file)?;
|
||||
let mut zip = zip::ZipArchive::new(reader)?;
|
||||
info!("Extracting zip file");
|
||||
zip.extract(extact_to)?;
|
||||
zip.extract(extract_to)?;
|
||||
info!("Zip file extracted");
|
||||
fs::remove_file(&zip_file).ok();
|
||||
Ok(())
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
fmt::Display,
|
||||
fs::File,
|
||||
io::{self, Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
|
@ -45,7 +46,7 @@ impl From<ZipError> for ReleasesError {
|
|||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Release {
|
||||
pub tag_name: String,
|
||||
pub tag_name: Tag,
|
||||
assets_url: String,
|
||||
}
|
||||
|
||||
|
@ -157,9 +158,10 @@ impl AssetList {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Tag(String);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
|
||||
pub struct Version {
|
||||
pub major: u32,
|
||||
pub minor: u32,
|
||||
|
@ -185,6 +187,15 @@ impl Version {
|
|||
pub fn current() -> Self {
|
||||
Self::parse_from_string(env!("CARGO_PKG_VERSION")).expect("can always parse crate version")
|
||||
}
|
||||
pub fn parse_from_tag(tag: Tag) -> Option<Self> {
|
||||
Self::parse_from_string(tag.0.strip_prefix("v")?)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Version {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "v{}.{}.{}", self.major, self.minor, self.patch)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Version> for Tag {
|
||||
|
|
177
noita-proxy/src/self_update.rs
Normal file
177
noita-proxy/src/self_update.rs
Normal file
|
@ -0,0 +1,177 @@
|
|||
use std::{
|
||||
cmp::Ordering,
|
||||
fs::{self, File},
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use eframe::egui::{Align, Layout, Ui};
|
||||
use poll_promise::Promise;
|
||||
use reqwest::blocking::Client;
|
||||
use tracing::info;
|
||||
|
||||
use crate::releases::{get_latest_release, Downloader, ReleasesError, Version};
|
||||
|
||||
struct VersionCheckResult {
|
||||
newest: Version,
|
||||
ord: Ordering,
|
||||
}
|
||||
|
||||
enum State {
|
||||
Initial,
|
||||
Download(Promise<Result<Downloader, ReleasesError>>),
|
||||
ReleasesError(ReleasesError),
|
||||
Unpack(Promise<Result<(), ReleasesError>>),
|
||||
}
|
||||
|
||||
pub struct SelfUpdateManager {
|
||||
latest_check: Promise<Option<VersionCheckResult>>,
|
||||
pub request_update: bool,
|
||||
state: State,
|
||||
}
|
||||
|
||||
impl SelfUpdateManager {
|
||||
pub fn new() -> Self {
|
||||
let latest_check = Promise::spawn_thread("version check", || {
|
||||
let client = Client::new();
|
||||
get_latest_release(&client)
|
||||
.map(|release| release.tag_name)
|
||||
.ok()
|
||||
.and_then(|tag| Version::parse_from_tag(tag))
|
||||
.map(|ver| VersionCheckResult {
|
||||
ord: ver.cmp(&Version::current()),
|
||||
newest: ver,
|
||||
})
|
||||
});
|
||||
Self {
|
||||
latest_check,
|
||||
request_update: false,
|
||||
state: State::Initial,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_version(&mut self, ui: &mut Ui) {
|
||||
ui.with_layout(Layout::right_to_left(Align::Max), |ui| {
|
||||
match self.latest_check.ready() {
|
||||
Some(&Some(VersionCheckResult {
|
||||
newest: _,
|
||||
ord: Ordering::Equal,
|
||||
})) => {
|
||||
ui.label("(latest)");
|
||||
}
|
||||
Some(&Some(VersionCheckResult { newest, ord: _ })) => {
|
||||
if ui
|
||||
.small_button(format!("Update available to {}", newest))
|
||||
.clicked()
|
||||
{
|
||||
self.request_update = true;
|
||||
}
|
||||
}
|
||||
Some(None) => {
|
||||
ui.label("(could not check for updates)");
|
||||
}
|
||||
None => {
|
||||
ui.label("(checking for updates)");
|
||||
}
|
||||
}
|
||||
ui.label(concat!("Noita Proxy version v", env!("CARGO_PKG_VERSION"),));
|
||||
});
|
||||
}
|
||||
|
||||
pub fn self_update(&mut self, ui: &mut Ui) {
|
||||
let ctx = ui.ctx();
|
||||
match &self.state {
|
||||
State::Initial => {
|
||||
if ui.button("Confirm update").clicked() {
|
||||
let promise = Promise::spawn_thread("get_release", || {
|
||||
proxy_downloader_for("newer.zip".into())
|
||||
});
|
||||
self.state = State::Download(promise)
|
||||
}
|
||||
}
|
||||
State::Download(promise) => match promise.ready() {
|
||||
Some(Ok(downloader)) => {
|
||||
downloader.show_progress(ui);
|
||||
match downloader.ready() {
|
||||
Some(Ok(_)) => {
|
||||
let path = downloader.path().to_path_buf();
|
||||
let promise: Promise<Result<(), ReleasesError>> =
|
||||
Promise::spawn_thread("unpack", move || {
|
||||
extract_and_remove_zip(path)
|
||||
});
|
||||
self.state = State::Unpack(promise);
|
||||
}
|
||||
Some(Err(err)) => self.state = State::ReleasesError(err.clone()),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
Some(Err(err)) => self.state = State::ReleasesError(err.clone()),
|
||||
None => {
|
||||
ui.label("Receiving release info...");
|
||||
ui.spinner();
|
||||
}
|
||||
},
|
||||
State::Unpack(promise) => match promise.ready() {
|
||||
Some(Ok(_)) => {
|
||||
ui.label("Proxy updated! Restart it now.");
|
||||
}
|
||||
Some(Err(err)) => {
|
||||
ui.label(format!("Could not update proxy: {}", err));
|
||||
}
|
||||
None => {
|
||||
ctx.request_repaint();
|
||||
ui.label("Unpacking...");
|
||||
ui.spinner();
|
||||
}
|
||||
},
|
||||
State::ReleasesError(err) => {
|
||||
ui.label(format!("Encountered an error: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_asset_name() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"noita-proxy-win.zip"
|
||||
} else {
|
||||
"noita-proxy-linux.zip"
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_bin_name() -> &'static str {
|
||||
if cfg!(target_os = "windows") {
|
||||
"noita_proxy.exe"
|
||||
} else {
|
||||
"noita_proxy.x86_64"
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_downloader_for(download_path: PathBuf) -> Result<Downloader, ReleasesError> {
|
||||
let client = reqwest::blocking::Client::builder()
|
||||
.timeout(None)
|
||||
.build()
|
||||
.unwrap();
|
||||
get_latest_release(&client)
|
||||
.and_then(|release| release.get_release_assets(&client))
|
||||
.and_then(|asset_list| asset_list.find_by_name(proxy_asset_name()).cloned())
|
||||
.and_then(|asset| asset.download(&client, &download_path))
|
||||
}
|
||||
|
||||
fn extract_and_remove_zip(zip_file: PathBuf) -> Result<(), ReleasesError> {
|
||||
let extract_to = Path::new("tmp.exec");
|
||||
let bin_name = proxy_bin_name();
|
||||
let reader = File::open(&zip_file)?;
|
||||
let mut zip = zip::ZipArchive::new(reader)?;
|
||||
info!("Extracting zip file");
|
||||
let mut src = zip.by_name(&bin_name)?;
|
||||
let mut dst = File::create(extract_to)?;
|
||||
io::copy(&mut src, &mut dst)?;
|
||||
|
||||
self_replace::self_replace(extract_to)?;
|
||||
|
||||
info!("Zip file extracted");
|
||||
fs::remove_file(&zip_file).ok();
|
||||
fs::remove_file(extract_to).ok();
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue