Skip to content

Commit 2bc5c25

Browse files
committed
feat: refactor API URL handling to use centralized vercel_api module for consistency
1 parent 56fb982 commit 2bc5c25

12 files changed

Lines changed: 126 additions & 49 deletions

File tree

src-tauri/src/analysis/livery_patterns.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ struct LiveryPatternsData {
5151
patterns: Vec<LiveryPattern>,
5252
}
5353

54-
/// Remote URL for the livery patterns JSON file via proxy
55-
const REMOTE_URL: &str = "https://x-fast-manager.vercel.app/api/livery-patterns-data";
56-
5754
/// Loaded livery patterns (embedded by default, remote override when available)
5855
static LIVERY_PATTERNS: LazyLock<RwLock<Vec<LiveryPattern>>> =
5956
LazyLock::new(|| RwLock::new(load_embedded_patterns()));
@@ -102,8 +99,10 @@ async fn fetch_remote_patterns() -> Result<Vec<LiveryPattern>, String> {
10299
.build()
103100
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
104101

105-
let remote_url =
106-
std::env::var("XFAST_LIVERY_PATTERNS_API_URL").unwrap_or_else(|_| REMOTE_URL.to_string());
102+
let remote_url = crate::vercel_api::endpoint_with_override(
103+
"livery-patterns-data",
104+
"XFAST_LIVERY_PATTERNS_API_URL",
105+
);
107106
let response = client
108107
.get(&remote_url)
109108
.send()

src-tauri/src/analysis/output_cleanup.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ use walkdir::WalkDir;
1313

1414
use crate::logger;
1515

16-
const REMOTE_URL: &str = "https://x-fast-manager.vercel.app/api/output-cleanup-items-data";
1716
const UNKNOWN_PREFIX: &str = "unknown:";
1817
const PROTECTED_OUTPUT_DIRS: &[&str] = &["preferences"];
1918
const ALLOWED_LEVELS: &[&str] = &["recommended", "cleanable", "cautious"];
@@ -325,8 +324,10 @@ async fn fetch_remote_catalog() -> Result<OutputCleanupCatalog, String> {
325324
.build()
326325
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
327326

328-
let remote_url = std::env::var("XFAST_OUTPUT_CLEANUP_ITEMS_API_URL")
329-
.unwrap_or_else(|_| REMOTE_URL.to_string());
327+
let remote_url = crate::vercel_api::endpoint_with_override(
328+
"output-cleanup-items-data",
329+
"XFAST_OUTPUT_CLEANUP_ITEMS_API_URL",
330+
);
330331
let response = client
331332
.get(&remote_url)
332333
.send()
@@ -721,9 +722,10 @@ pub async fn submit_unknown_output_cleanup_item(
721722
let app_version = env!("CARGO_PKG_VERSION").to_string();
722723
let os = std::env::consts::OS.to_string();
723724
let arch = std::env::consts::ARCH.to_string();
724-
let api_url = std::env::var("XFAST_OUTPUT_CLEANUP_SUBMISSION_API_URL").unwrap_or_else(|_| {
725-
"https://x-fast-manager.vercel.app/api/output-cleanup-item-submission".to_string()
726-
});
725+
let api_url = crate::vercel_api::endpoint_with_override(
726+
"output-cleanup-item-submission",
727+
"XFAST_OUTPUT_CLEANUP_SUBMISSION_API_URL",
728+
);
727729

728730
let client = reqwest::Client::builder()
729731
.user_agent("XFast Manager")

src-tauri/src/core/vercel_api.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
const DEFAULT_VERCEL_API_BASE_URL: &str = "https://x-fast-manager.vercel.app/api";
2+
3+
fn normalized_base_url() -> String {
4+
let configured = std::env::var("XFAST_VERCEL_API_BASE_URL").ok();
5+
let base = configured
6+
.as_deref()
7+
.map(str::trim)
8+
.filter(|value| !value.is_empty())
9+
.unwrap_or(DEFAULT_VERCEL_API_BASE_URL);
10+
let trimmed = base.trim_end_matches('/');
11+
12+
if trimmed.ends_with("/api") {
13+
trimmed.to_string()
14+
} else {
15+
format!("{}/api", trimmed)
16+
}
17+
}
18+
19+
fn normalized_route(route: &str) -> &str {
20+
route.trim().trim_start_matches('/')
21+
}
22+
23+
pub fn endpoint(route: &str) -> String {
24+
format!("{}/{}", normalized_base_url(), normalized_route(route))
25+
}
26+
27+
pub fn endpoint_with_override(route: &str, override_env: &str) -> String {
28+
if let Ok(value) = std::env::var(override_env) {
29+
let trimmed = value.trim();
30+
if !trimmed.is_empty() {
31+
return trimmed.to_string();
32+
}
33+
}
34+
35+
endpoint(route)
36+
}
37+
38+
pub fn append_query_param(url: &str, key: &str, value: &str) -> String {
39+
let separator = if url.contains('?') { '&' } else { '?' };
40+
format!("{url}{separator}{key}={value}")
41+
}

src-tauri/src/lib.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ mod performance;
1717
mod registry;
1818
#[path = "core/task_control.rs"]
1919
mod task_control;
20+
#[path = "core/vercel_api.rs"]
21+
mod vercel_api;
2022

2123
// Data
2224
#[path = "data/database/mod.rs"]
@@ -217,8 +219,7 @@ async fn create_library_link_issue(
217219
return Err("Download URL must be http/https".to_string());
218220
}
219221

220-
let api_url = std::env::var("XFAST_LINK_API_URL")
221-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/library-link".to_string());
222+
let api_url = crate::vercel_api::endpoint_with_override("library-link", "XFAST_LINK_API_URL");
222223

223224
let client = reqwest::Client::builder()
224225
.user_agent("XFast Manager")
@@ -286,8 +287,8 @@ async fn create_bug_report_issue(
286287
let os = std::env::consts::OS.to_string();
287288
let arch = std::env::consts::ARCH.to_string();
288289

289-
let api_url = std::env::var("XFAST_BUG_REPORT_API_URL")
290-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/bug-report".to_string());
290+
let api_url =
291+
crate::vercel_api::endpoint_with_override("bug-report", "XFAST_BUG_REPORT_API_URL");
291292

292293
let client = reqwest::Client::builder()
293294
.user_agent("XFast Manager")
@@ -382,8 +383,8 @@ async fn create_feedback_issue(
382383
let arch = std::env::consts::ARCH.to_string();
383384
let feedback_type = feedback_type.trim().to_lowercase();
384385

385-
let api_url = std::env::var("XFAST_FEEDBACK_API_URL")
386-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/feedback-issue".to_string());
386+
let api_url =
387+
crate::vercel_api::endpoint_with_override("feedback-issue", "XFAST_FEEDBACK_API_URL");
387388

388389
let client = reqwest::Client::builder()
389390
.user_agent("XFast Manager")
@@ -475,8 +476,8 @@ async fn post_issue_comment(
475476
return Err("comment_body is required".to_string());
476477
}
477478

478-
let api_url = std::env::var("XFAST_ISSUE_COMMENT_API_URL")
479-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/issue-comment".to_string());
479+
let api_url =
480+
crate::vercel_api::endpoint_with_override("issue-comment", "XFAST_ISSUE_COMMENT_API_URL");
480481

481482
let client = reqwest::Client::builder()
482483
.user_agent("XFast Manager")
@@ -551,13 +552,11 @@ struct IssueUpdateResult {
551552
}
552553

553554
fn issue_updates_api_url() -> String {
554-
std::env::var("XFAST_ISSUE_UPDATES_API_URL")
555-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/issue-updates".to_string())
555+
crate::vercel_api::endpoint_with_override("issue-updates", "XFAST_ISSUE_UPDATES_API_URL")
556556
}
557557

558558
fn issue_detail_api_url() -> String {
559-
std::env::var("XFAST_ISSUE_DETAIL_API_URL")
560-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/issue-detail".to_string())
559+
crate::vercel_api::endpoint_with_override("issue-detail", "XFAST_ISSUE_DETAIL_API_URL")
561560
}
562561

563562
#[tauri::command]

src-tauri/src/services/library_links.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ static CACHE: LazyLock<Mutex<Option<CachedLinks>>> = LazyLock::new(|| Mutex::new
2929
/// Cache TTL: 24 hours (matching updater pattern)
3030
const CACHE_TTL: Duration = Duration::from_secs(24 * 60 * 60);
3131

32-
/// Remote URL for the library links JSON file via proxy
33-
const REMOTE_URL: &str = "https://x-fast-manager.vercel.app/api/library-links-data";
34-
3532
fn normalize_library_key(raw: &str) -> String {
3633
let trimmed = raw
3734
.trim()
@@ -129,8 +126,10 @@ async fn fetch_remote_links() -> Result<HashMap<String, String>, String> {
129126
.build()
130127
.map_err(|e| format!("Failed to create HTTP client: {}", e))?;
131128

132-
let remote_url =
133-
std::env::var("XFAST_LIBRARY_LINKS_API_URL").unwrap_or_else(|_| REMOTE_URL.to_string());
129+
let remote_url = crate::vercel_api::endpoint_with_override(
130+
"library-links-data",
131+
"XFAST_LIBRARY_LINKS_API_URL",
132+
);
134133
let response = client
135134
.get(&remote_url)
136135
.send()

src-tauri/src/services/updater.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,14 @@ impl UpdateChecker {
8484
}
8585

8686
fn update_release_api_url(include_pre_release: bool) -> String {
87-
let base = std::env::var("XFAST_UPDATE_RELEASE_API_URL")
88-
.unwrap_or_else(|_| "https://x-fast-manager.vercel.app/api/update-release".to_string());
89-
let has_query = base.contains('?');
90-
let sep = if has_query { "&" } else { "?" };
91-
format!(
92-
"{}{}includePreRelease={}",
93-
base,
94-
sep,
95-
if include_pre_release { "1" } else { "0" }
87+
let base = crate::vercel_api::endpoint_with_override(
88+
"update-release",
89+
"XFAST_UPDATE_RELEASE_API_URL",
90+
);
91+
crate::vercel_api::append_query_param(
92+
&base,
93+
"includePreRelease",
94+
if include_pre_release { "1" } else { "0" },
9695
)
9796
}
9897

src/services/bugReport.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { invoke } from '@tauri-apps/api/core'
22
import { logError } from '@/services/logger'
33
import { getItem, setItem, STORAGE_KEYS, type TrackedIssue } from '@/services/storage'
4+
import { buildVercelApiUrl } from '@/services/vercelApi'
45
import { useIssueTrackerStore } from '@/stores/issueTracker'
56

67
export interface BugReportToast {
@@ -18,9 +19,10 @@ export interface SubmitBugReportParams {
1819
}
1920

2021
const DEFAULT_BUG_REPORT_TIMEOUT_MS = 20000
21-
const ISSUE_DRAFT_API_BASE =
22-
import.meta.env.VITE_XFAST_ISSUE_DRAFT_API_URL ||
23-
'https://x-fast-manager.vercel.app/api/issue-draft'
22+
const ISSUE_DRAFT_API_BASE = buildVercelApiUrl(
23+
'issue-draft',
24+
import.meta.env.VITE_XFAST_ISSUE_DRAFT_API_URL,
25+
)
2426

2527
function buildFallbackBugReportUrl(errorTitle: string, errorMessage: string, logs: string): string {
2628
const fallbackTitle = `[Bug]: ${(errorTitle || errorMessage).slice(0, 80)}`

src/services/vercelApi.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const DEFAULT_VERCEL_API_BASE_URL = 'https://x-fast-manager.vercel.app/api'
2+
3+
function normalizeApiBaseUrl(rawValue?: string): string {
4+
const trimmed = rawValue?.trim()
5+
const base = trimmed && trimmed.length > 0 ? trimmed : DEFAULT_VERCEL_API_BASE_URL
6+
const normalized = base.replace(/\/+$/, '')
7+
8+
return normalized.endsWith('/api') ? normalized : `${normalized}/api`
9+
}
10+
11+
function normalizeRoute(route: string): string {
12+
return route.trim().replace(/^\/+/, '')
13+
}
14+
15+
export function buildVercelApiUrl(route: string, overrideUrl?: string): string {
16+
const override = overrideUrl?.trim()
17+
if (override) {
18+
return override
19+
}
20+
21+
const baseUrl = normalizeApiBaseUrl(import.meta.env.VITE_XFAST_VERCEL_API_BASE_URL)
22+
return `${baseUrl}/${normalizeRoute(route)}`
23+
}

src/stores/update.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ import { i18n } from '@/i18n'
1010
import { logError, logDebug, logBasic } from '@/services/logger'
1111
import { invokeVoidCommand, CommandError } from '@/services/api'
1212
import { getItem, setItem, STORAGE_KEYS } from '@/services/storage'
13+
import { buildVercelApiUrl } from '@/services/vercelApi'
1314
import bundledChangelog from '@/generated/changelog'
1415

1516
const t = i18n.global.t
16-
const RELEASE_REDIRECT_API_BASE =
17-
import.meta.env.VITE_XFAST_RELEASE_REDIRECT_API_URL ||
18-
'https://x-fast-manager.vercel.app/api/release-redirect'
17+
const RELEASE_REDIRECT_API_BASE = buildVercelApiUrl(
18+
'release-redirect',
19+
import.meta.env.VITE_XFAST_RELEASE_REDIRECT_API_URL,
20+
)
1921

2022
export const useUpdateStore = defineStore('update', () => {
2123
const toast = useToastStore()

src/views/FeedbackCenter.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ import {
313313
} from '@/stores/issueTracker'
314314
import { useToastStore } from '@/stores/toast'
315315
import { logError } from '@/services/logger'
316+
import { buildVercelApiUrl } from '@/services/vercelApi'
316317
import { useFeedbackStore } from '@/stores/feedback'
317318
318319
const route = useRoute()
@@ -463,9 +464,10 @@ function displayFeedbackType(type?: string): string {
463464
}
464465
465466
async function openIssue(url: string) {
466-
const issueRedirectApiBase =
467-
import.meta.env.VITE_XFAST_ISSUE_REDIRECT_API_URL ||
468-
'https://x-fast-manager.vercel.app/api/issue-redirect'
467+
const issueRedirectApiBase = buildVercelApiUrl(
468+
'issue-redirect',
469+
import.meta.env.VITE_XFAST_ISSUE_REDIRECT_API_URL,
470+
)
469471
let finalUrl = String(url || '').trim()
470472
if (!finalUrl) return
471473

0 commit comments

Comments
 (0)