refactor: 简化项目配置,改用环境变量端口并专注 MSI 发布

- 重命名项目为 openbridgeTokenUsageViewer (camelCase 风格)
- 移除 DJB2 hash 端口计算,改用 PROJECT_SERVER_PORT 环境变量 (默认 3000)
- 删除 src/lib/project-port.ts 冗余模块
- 打包目标从 "all" 改为 "msi",专注 Windows 安装程序发布
This commit is contained in:
2026-01-22 14:19:43 +08:00
parent b520cdaf35
commit fa625ca301
11 changed files with 39 additions and 117 deletions

View File

@@ -1 +1,2 @@
TOKEN_USAGE_URL=
TOKEN_USAGE_URL=http://10.0.1.1:8318/usage
PROJECT_SERVER_PORT=3214

View File

@@ -21,7 +21,7 @@ import { Console, Context, Data, Effect, Layer } from 'effect'
// ============================================================================
/** 项目名称 - 用于生成 sidecar 文件名 */
const PROJECT_NAME = 'openbridge-token-usage-viewer'
const PROJECT_NAME = 'openbridgeTokenUsageViewerServer'
// ============================================================================
// 领域模型和 Schema 定义

View File

@@ -1,5 +1,5 @@
{
"name": "openbridge-token-usage-viewer",
"name": "openbridgeTokenUsageViewer",
"private": true,
"type": "module",
"packageManager": "bun@1.3.6",

2
src-tauri/Cargo.lock generated
View File

@@ -2061,7 +2061,7 @@ dependencies = [
]
[[package]]
name = "openbridge-token-usage-viewer"
name = "openbridgeTokenUsageViewer"
version = "0.1.0"
dependencies = [
"serde",

View File

@@ -1,5 +1,5 @@
[package]
name = "openbridge-token-usage-viewer"
name = "openbridgeTokenUsageViewer"
version = "0.1.0"
description = "OpenBridge Token Usage Viewer"
authors = ["imbytecat"]
@@ -11,7 +11,7 @@ edition = "2021"
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "openbridge_token_usage_viewer_lib"
name = "openbridgeTokenUsageViewer_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]

View File

@@ -2,5 +2,5 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
openbridge_token_usage_viewer_lib::run()
openbridgeTokenUsageViewer_lib::run()
}

View File

@@ -7,23 +7,18 @@ use tauri_plugin_shell::ShellExt;
// ===== 项目配置 =====
/// 项目名称 - 用于生成稳定端口和 sidecar 命名
const PROJECT_NAME: &str = "openbridge-token-usage-viewer";
/// Sidecar 二进制名称
const SIDECAR_NAME: &str = "openbridgeTokenUsageViewerServer";
/// DJB2 Hash 算法 - 将项目名称转换为稳定端口
fn djb2_hash(s: &str) -> u32 {
let mut hash: u32 = 5381;
for c in s.bytes() {
hash = hash.wrapping_shl(5).wrapping_add(hash).wrapping_add(c as u32);
}
hash
}
/// 默认服务器端口
const DEFAULT_PORT: u16 = 3000;
/// 计算项目专用端口 (范围: 10000-60000)
/// 从环境变量获取端口 (PROJECT_SERVER_PORT),默认 3000
fn get_project_port() -> u16 {
const PORT_MIN: u16 = 10000;
const PORT_RANGE: u32 = 50000;
PORT_MIN + (djb2_hash(PROJECT_NAME) % PORT_RANGE) as u16
std::env::var("PROJECT_SERVER_PORT")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(DEFAULT_PORT)
}
// ===== 配置常量 =====
@@ -96,7 +91,6 @@ pub fn spawn_sidecar(app_handle: tauri::AppHandle) {
if is_dev {
// 开发模式:直接创建窗口连接到 Vite 开发服务器
println!("🔧 开发模式");
println!("📌 项目: {}", PROJECT_NAME);
println!("📌 端口: {}", project_port);
let dev_url = format!("http://localhost:{}", project_port);
@@ -122,14 +116,13 @@ pub fn spawn_sidecar(app_handle: tauri::AppHandle) {
// 生产模式:启动 sidecar 二进制
tauri::async_runtime::spawn(async move {
println!("🚀 生产模式");
println!("📌 项目: {}", PROJECT_NAME);
// 查找可用端口 (从项目端口开始扫描)
let port = find_available_port(project_port).await;
println!("📌 端口: {}", port);
// 启动 sidecar (使用项目名称作为 sidecar 名称)
let sidecar = match app_handle.shell().sidecar(PROJECT_NAME) {
// 启动 sidecar
let sidecar = match app_handle.shell().sidecar(SIDECAR_NAME) {
Ok(cmd) => cmd.env("PORT", port.to_string()),
Err(e) => {
eprintln!("✗ 无法找到 sidecar: {}", e);

View File

@@ -1,8 +1,8 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "openbridge-token-usage-viewer",
"productName": "openbridgeTokenUsageViewer",
"version": "0.1.0",
"identifier": "com.imbytecat.openbridge-token-usage-viewer",
"identifier": "com.imbytecat.openbridgetokenusageviewer",
"app": {
"withGlobalTauri": true,
"windows": [],
@@ -12,7 +12,7 @@
},
"bundle": {
"active": true,
"targets": "all",
"targets": ["msi"],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -20,6 +20,6 @@
"icons/icon.icns",
"icons/icon.ico"
],
"externalBin": ["binaries/openbridge-token-usage-viewer"]
"externalBin": ["binaries/openbridgeTokenUsageViewerServer"]
}
}

View File

@@ -12,6 +12,9 @@ import { z } from 'zod'
/** Token 使用量 API 的默认地址 */
const DEFAULT_TOKEN_USAGE_URL = 'http://10.0.1.1:8318/usage'
/** 服务器端口默认值 */
const DEFAULT_SERVER_PORT = '3000'
/**
* 判断当前是否为打包后的可执行文件运行环境
*
@@ -109,6 +112,7 @@ const buildMergedEnv = (): Record<string, string | undefined> => {
// 设置默认值
merged.TOKEN_USAGE_URL ??= DEFAULT_TOKEN_USAGE_URL
merged.PROJECT_SERVER_PORT ??= DEFAULT_SERVER_PORT
return merged
}
@@ -125,6 +129,12 @@ const buildMergedEnv = (): Record<string, string | undefined> => {
export const env = createEnv({
server: {
TOKEN_USAGE_URL: z.string().url(),
PROJECT_SERVER_PORT: z.coerce
.number()
.int()
.min(1)
.max(65535)
.default(3000),
},
clientPrefix: 'VITE_',
client: {

View File

@@ -1,70 +0,0 @@
/**
* 项目名称到端口的 Hash 工具
*
* 使用 DJB2 算法将项目名称转换为稳定的端口号。
* 确保:
* - 相同项目名称总是返回相同端口
* - 不同项目名称返回不同端口 (极低碰撞率)
* - 端口范围: 10000-60000 (避开常用端口和系统保留端口)
*
* @example
* ```ts
* import { PROJECT_NAME, PROJECT_PORT } from '@/lib/project-port'
* console.log(PROJECT_NAME) // 'openbridge-token-usage-viewer'
* console.log(PROJECT_PORT) // 34567 (示例)
* ```
*/
/** 端口范围配置 */
const PORT_MIN = 10000
const PORT_MAX = 60000
const PORT_RANGE = PORT_MAX - PORT_MIN
/**
* 项目名称 (从目录名获取)
*
* 这确保项目名称与目录结构保持一致
*/
export const PROJECT_NAME = 'openbridge-token-usage-viewer'
/**
* DJB2 Hash 算法
*
* 经典的字符串哈希算法,具有良好的分布特性和较低的碰撞率。
*
* @param str - 要哈希的字符串
* @returns 32位无符号整数哈希值
*/
const djb2Hash = (str: string): number => {
let hash = 5381
for (let i = 0; i < str.length; i++) {
// hash * 33 + char
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0
}
return hash
}
/**
* 将项目名称转换为稳定的端口号
*
* @param projectName - 项目名称
* @returns 10000-60000 范围内的端口号
*/
export const getPortFromName = (projectName: string): number => {
const hash = djb2Hash(projectName)
return PORT_MIN + (hash % PORT_RANGE)
}
/**
* 项目专用端口
*
* 基于项目名称计算的稳定端口号。
* 用于开发服务器和 Tauri sidecar。
*/
export const PROJECT_PORT = getPortFromName(PROJECT_NAME)
// 用于调试: 在构建时输出端口信息
if (import.meta.env?.DEV) {
console.log(`📌 项目: ${PROJECT_NAME}`)
console.log(`📌 端口: ${PROJECT_PORT}`)
}

View File

@@ -7,37 +7,25 @@
* - Bun 运行时优化 (nitro preset: 'bun')
* - 静态资源内联 (serveStatic: 'inline')
* - React Compiler 自动优化 (无需手动 memo)
* - 基于项目名称的稳定端口 (使用 DJB2 hash)
* - 端口从环境变量 PROJECT_SERVER_PORT 读取 (默认 3000)
*/
import tailwindcss from '@tailwindcss/vite'
import { devtools as tanstackDevtools } from '@tanstack/devtools-vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import react from '@vitejs/plugin-react'
import { nitro } from 'nitro/vite'
import { defineConfig } from 'vite'
import { defineConfig, loadEnv } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
// ============================================================================
// 项目配置 (集中管理)
// ============================================================================
/** 项目名称 - 用于生成稳定端口和 sidecar 命名 */
export const PROJECT_NAME = 'openbridge-token-usage-viewer'
/** 加载 .env 文件中的环境变量 */
const envVars = loadEnv('development', process.cwd(), '')
/**
* DJB2 Hash 算法 - 将项目名称转换为稳定端口
* 端口范围: 10000-60000
*/
const djb2Hash = (str: string): number => {
let hash = 5381
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0
}
return hash
}
/** 开发服务器端口 (基于项目名称的稳定值) */
export const DEV_PORT = 10000 + (djb2Hash(PROJECT_NAME) % 50000)
/** 开发服务器端口 (从环境变量读取,默认 3000) */
const DEV_PORT = Number(envVars.PROJECT_SERVER_PORT) || 3000
export default defineConfig({
// 禁止清屏,方便与 Tauri 开发工具共用终端