Compare commits

..
Author SHA1 Message Date
AxTps 8b94e7dbbe fix: 更新渠道默认值跟随安装包版本
Sync source to CNB / Sync Git ref (push) Skipped
从 GitHub 下载 Beta 安装包安装后,更新通道默认选中 Release,
因为 update-channel.json 状态文件不存在时会硬编码回退到 release。

新增 theseus::default_update_channel(),按编译期版本号判断:含预发布
后缀(如 1.0.2-beta7)默认 Beta,否则 Release。数据库渠道与设置页
渠道两处默认值统一改为调用它,保证两者一致。
2026-10-13 22:11:06 +08:00
5 changed files with 47 additions and 82 deletions

No files matched your search

+1 -1
View File
@@ -339,7 +339,7 @@ fn get_launcher_root_dir() -> api::Result<String> {
fn get_update_channel(app: tauri::AppHandle) -> api::Result<String> {
let channel = read_update_channel_state(&app)?
.active_channel
.unwrap_or_else(|| "release".to_string());
.unwrap_or_else(|| theseus::default_update_channel().to_string());
match channel.as_str() {
"release" | "beta" => Ok(channel),
@@ -109,7 +109,6 @@ pub struct CrashAnalysisMod {
struct SourceCandidate {
path: PathBuf,
filename: String,
upload_name: String,
source_type: &'static str,
modified: SystemTime,
}
@@ -117,25 +116,10 @@ struct SourceCandidate {
#[derive(Debug)]
struct SourceText {
filename: String,
upload_name: String,
source_type: &'static str,
modified: SystemTime,
content: String,
}
pub(super) struct CollectedCrashLog {
pub name: String,
pub content: CensoredString,
}
pub(super) struct CollectedCrashLogs {
pub combined_log: CensoredString,
pub sources: Vec<CollectedCrashLog>,
}
struct CrashContext {
sources: Vec<SourceText>,
credentials: Vec<Credentials>,
}
struct Rule {
id: &'static str,
@@ -1201,25 +1185,20 @@ async fn collect_candidates(
) -> crate::Result<Vec<SourceCandidate>> {
let mut candidates = Vec::new();
let mut locations = vec![
(
directories.game_logs_dir(instance_root),
"minecraft_log",
None,
),
(directories.game_logs_dir(instance_root), "minecraft_log"),
(
directories.game_crash_reports_dir(instance_root),
"crash_report",
Some("crash-reports"),
),
(instance_root.to_path_buf(), "instance_log", None),
(instance_root.to_path_buf(), "instance_log"),
];
if let Some(dot_minecraft) = isolated_minecraft_root(instance_root) {
// PCL-CE also searches the shared `.minecraft` root for JVM crash
// logs when a version-isolated instance is active.
locations.push((dot_minecraft, "minecraft_root_log", None));
locations.push((dot_minecraft, "minecraft_root_log"));
}
for (directory, default_type, upload_prefix) in locations {
for (directory, default_type) in locations {
if !tokio::fs::try_exists(&directory).await? {
continue;
}
@@ -1269,9 +1248,6 @@ async fn collect_candidates(
};
candidates.push(SourceCandidate {
path: entry.path(),
upload_name: upload_prefix
.map(|prefix| format!("{prefix}/{filename}"))
.unwrap_or_else(|| filename.clone()),
filename,
source_type,
modified: metadata.modified().unwrap_or(SystemTime::UNIX_EPOCH),
@@ -1281,53 +1257,6 @@ async fn collect_candidates(
Ok(candidates)
}
async fn collect_crash_context(
instance_id: &str,
) -> crate::Result<CrashContext> {
let state = State::get().await?;
let (instance_path, game_dir_override) =
resolve_instance_path(instance_id, &state).await?;
let instance_root = state
.directories
.resolve_game_dir(&instance_path, game_dir_override.as_deref());
let candidates =
collect_candidates(&instance_root, &state.directories).await?;
let selected = select_run_candidates(candidates);
let sources = read_sources(selected).await;
let credentials = Credentials::get_all(&state.pool)
.await?
.into_iter()
.map(|credential| credential.1)
.collect::<Vec<_>>();
Ok(CrashContext {
sources,
credentials,
})
}
pub(super) async fn collect_crash_logs(
instance_id: &str,
) -> crate::Result<CollectedCrashLogs> {
let CrashContext {
sources,
credentials,
..
} = collect_crash_context(instance_id).await?;
let combined_log =
CensoredString::censor(build_combined_log(&sources), &credentials);
let sources = sources
.into_iter()
.map(|source| CollectedCrashLog {
name: source.upload_name,
content: CensoredString::censor(source.content, &credentials),
})
.collect();
Ok(CollectedCrashLogs {
combined_log,
sources,
})
}
fn isolated_minecraft_root(instance_root: &Path) -> Option<PathBuf> {
let versions_dir = instance_root.parent()?;
if versions_dir
@@ -1391,7 +1320,6 @@ async fn read_sources(candidates: Vec<SourceCandidate>) -> Vec<SourceText> {
};
sources.push(SourceText {
filename: candidate.filename,
upload_name: candidate.upload_name,
source_type: candidate.source_type,
modified: candidate.modified,
content: String::from_utf8_lossy(bytes).into_owned(),
@@ -1851,7 +1779,6 @@ mod tests {
fn source(filename: &str, content: &str) -> SourceText {
SourceText {
filename: filename.to_string(),
upload_name: filename.to_string(),
source_type: "minecraft_log",
modified: SystemTime::now(),
content: content.to_string(),
@@ -1875,7 +1802,6 @@ mod tests {
let candidates = vec![SourceCandidate {
path: PathBuf::from("launcher_log.txt"),
filename: "launcher_log.txt".to_string(),
upload_name: "launcher_log.txt".to_string(),
source_type: "minecraft_log",
modified: SystemTime::now() - Duration::from_secs(181),
}];
+28 -1
View File
@@ -4,7 +4,8 @@ use futures::StreamExt;
use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use super::crash_analysis::collect_crash_logs;
use super::CensoredString;
use super::crash_analysis::analyze_crash;
use crate::State;
use crate::emit_logshare_ai_event;
@@ -199,6 +200,32 @@ fn source_identifier() -> String {
format!("{LOGSHARE_SOURCE_PREFIX}/{}", env!("CARGO_PKG_VERSION"))
}
struct CollectedCrashLog {
name: String,
content: CensoredString,
}
struct CollectedCrashLogs {
combined_log: CensoredString,
sources: Vec<CollectedCrashLog>,
}
async fn collect_crash_logs(
instance_id: &str,
) -> crate::Result<CollectedCrashLogs> {
let analysis = analyze_crash(instance_id).await?;
Ok(CollectedCrashLogs {
combined_log: analysis.combined_log,
sources: analysis
.sources
.into_iter()
.map(|source| CollectedCrashLog {
name: source.filename,
content: source.content,
})
.collect(),
})
}
async fn prepare_upload(instance_id: &str) -> crate::Result<UploadBody> {
let settings = get_log_share_settings().await?;
let logs = collect_crash_logs(instance_id).await?;
+1 -1
View File
@@ -33,7 +33,7 @@ pub use logger::start_logger;
pub use state::db::{
backup_current_app_db_for_update, beta_database_exists,
copy_database_between_channels, copy_release_database_to_beta,
current_app_database_path,
current_app_database_path, default_update_channel,
};
pub use state::{DirectoryInfo, State};
pub use storage::*;
+13 -1
View File
@@ -304,6 +304,18 @@ async fn app_db_path(settings_dir: &Path) -> crate::Result<PathBuf> {
Ok(settings_dir.join(channel).join(LEGACY_APP_DB_FILE))
}
/// The update channel a fresh install should default to. Beta builds carry a
/// pre-release version (e.g. `1.0.2-beta7`), so their installers should start
/// on the Beta channel instead of silently falling back to Release.
pub fn default_update_channel() -> &'static str {
let version = env!("CARGO_PKG_VERSION");
if version.contains('-') {
"beta"
} else {
"release"
}
}
async fn read_update_channel(
settings_dir: &Path,
) -> crate::Result<&'static str> {
@@ -311,7 +323,7 @@ async fn read_update_channel(
let contents = match tokio::fs::read_to_string(&path).await {
Ok(contents) => contents,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
return Ok("release");
return Ok(default_update_channel());
}
Err(error) => return Err(error.into()),
};