cj-tauri 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +206 -139
- package/bin/cj-tauri.js +287 -287
- package/cjpm.toml +63 -52
- package/cli/cjpm.toml +22 -22
- package/cli/src/doctor.cj +308 -306
- package/cli/src/main.cj +129 -129
- package/cli/src/manifest.cj +643 -558
- package/cli/src/manifest_test.cj +87 -0
- package/cli/src/project.cj +770 -770
- package/cli/src/resolve.cj +348 -348
- package/cli/src/scaffold.cj +369 -369
- package/cli/src/sync.cj +638 -526
- package/cli/src/util.cj +168 -168
- package/cli/templates/app/README.md +51 -48
- package/cli/templates/app/assets/capabilities/default.json +7 -7
- package/cli/templates/app/assets/ui/index.html +120 -118
- package/cli/templates/app/cj-tauri.toml +32 -22
- package/cli/templates/app/cjpm.toml +34 -34
- package/cli/templates/app/src/main.cj +101 -90
- package/cli/templates/app-react/README.md +56 -56
- package/cli/templates/app-react/assets/capabilities/default.json +7 -7
- package/cli/templates/app-react/assets/ui/index.html +25 -25
- package/cli/templates/app-react/assets/ui/package.json +19 -19
- package/cli/templates/app-react/assets/ui/src/App.css +67 -67
- package/cli/templates/app-react/assets/ui/src/App.jsx +124 -124
- package/cli/templates/app-react/assets/ui/src/main.jsx +6 -6
- package/cli/templates/app-react/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-react/cj-tauri.toml +33 -23
- package/cli/templates/app-react/cjpm.toml +34 -34
- package/cli/templates/app-react/src/main.cj +91 -91
- package/cli/templates/app-vue/README.md +56 -56
- package/cli/templates/app-vue/assets/capabilities/default.json +7 -7
- package/cli/templates/app-vue/assets/ui/index.html +25 -25
- package/cli/templates/app-vue/assets/ui/package.json +18 -18
- package/cli/templates/app-vue/assets/ui/src/App.vue +176 -176
- package/cli/templates/app-vue/assets/ui/src/main.js +4 -4
- package/cli/templates/app-vue/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-vue/cj-tauri.toml +33 -23
- package/cli/templates/app-vue/cjpm.toml +34 -34
- package/cli/templates/app-vue/src/main.cj +91 -91
- package/cli/templates/ohos-skeleton/AppScope/app.json5 +13 -13
- package/cli/templates/ohos-skeleton/AppScope/resources/base/element/string.json +8 -8
- package/cli/templates/ohos-skeleton/AppScope/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/README.md +84 -79
- package/cli/templates/ohos-skeleton/build-hap.sh +15 -0
- package/cli/templates/ohos-skeleton/build-profile.json5 +46 -46
- package/cli/templates/ohos-skeleton/entry/build-profile.json5 +26 -26
- package/cli/templates/ohos-skeleton/entry/cjpm.toml +51 -43
- package/cli/templates/ohos-skeleton/entry/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/entry/oh-package.json5 +9 -9
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/ability_stage.cj +17 -17
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/app_host.cj +94 -94
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/dialog_host.cj +217 -0
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/index.cj +527 -167
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/main_ability.cj +139 -139
- package/cli/templates/ohos-skeleton/entry/src/main/module.json5 +57 -49
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/color.json +8 -8
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/string.json +16 -16
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/profile/main_pages.json +2 -2
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/capabilities.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/index.html +92 -92
- package/cli/templates/ohos-skeleton/hvigor/hvigor-config.json5 +5 -5
- package/cli/templates/ohos-skeleton/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/oh-package.json5 +10 -10
- package/native/build_win.bat +62 -62
- package/native/core/bridge_core.c +1681 -1626
- package/native/core/bridge_core.h +675 -618
- package/native/core/bridge_js.h +108 -108
- package/native/platforms/harmonyos/README.md +115 -6
- package/native/platforms/linux/bridge_linux.c +2787 -2485
- package/native/platforms/windows/bridge_win.c +3745 -3248
- package/native/tests/gtk_threading_probe.c +143 -143
- package/native/tests/test_bridge_core.c +1339 -1228
- package/package.json +53 -53
- package/src/api_system.cj +67 -67
- package/src/app.cj +335 -969
- package/src/app_events.cj +166 -0
- package/src/app_host_ops.cj +287 -0
- package/src/app_run.cj +283 -0
- package/src/app_spec.cj +76 -76
- package/src/arkweb_menu.cj +216 -0
- package/src/arkweb_script.cj +142 -142
- package/src/capability.cj +409 -409
- package/src/clipboard_bridge.cj +178 -0
- package/src/dialog_spec.cj +79 -0
- package/src/dragdrop.cj +26 -26
- package/src/embedded_assets.cj +98 -98
- package/src/host.cj +752 -607
- package/src/host_arkweb.cj +924 -778
- package/src/host_webkit.cj +663 -570
- package/src/host_webview2.cj +663 -570
- package/src/hotkey.cj +66 -66
- package/src/ipc_hub.cj +401 -337
- package/src/ipc_message.cj +286 -286
- package/src/launch.cj +62 -62
- package/src/logging.cj +127 -127
- package/src/menu.cj +197 -197
- package/src/platform/platform_app_context.cj +77 -77
- package/src/platform/platform_assets.cj +33 -33
- package/src/platform/platform_discover.cj +176 -176
- package/src/platform/platform_env.cj +29 -29
- package/src/platform/platform_feature.cj +31 -31
- package/src/platform/platform_page_source.cj +87 -87
- package/src/platform/platform_target_info.cj +32 -32
- package/src/platform_host_provider.cj +87 -87
- package/src/plugin.cj +333 -333
- package/src/plugins/clipboard/plugin_clipboard.cj +152 -152
- package/src/plugins/dialog/plugin_dialog.cj +209 -209
- package/src/plugins/fs/plugin_fs.cj +105 -1
- package/src/plugins/http/http_backend.cj +131 -0
- package/src/plugins/http/http_desktop.cj +195 -0
- package/src/plugins/http/http_ohos.cj +204 -0
- package/src/plugins/http/plugin_http.cj +310 -459
- package/src/plugins/log/plugin_log.cj +105 -105
- package/src/plugins/menu/plugin_menu.cj +158 -158
- package/src/plugins/notification/plugin_notification.cj +154 -154
- package/src/plugins/serial/plugin_serial.cj +458 -454
- package/src/plugins/serial/serial_bridge.cj +194 -194
- package/src/plugins/serial/serial_manager_ohos.cj +92 -0
- package/src/plugins/serial/serial_ohos.cj +529 -0
- package/src/plugins/shell/plugin_shell.cj +258 -258
- package/src/plugins/sqlite/plugin_sqlite.cj +705 -710
- package/src/plugins/sqlite/sqlite_ffi.cj +206 -211
- package/src/plugins/ws/plugin_ws.cj +488 -470
- package/src/process_hidden.cj +174 -174
- package/src/scope.cj +391 -391
- package/src/shell_event.cj +69 -69
- package/src/tests/app_spec_test.cj +130 -127
- package/src/tests/capability_test.cj +243 -243
- package/src/tests/dialog_spec_test.cj +73 -0
- package/src/tests/fake_host.cj +201 -201
- package/src/tests/ipc_hub_test.cj +563 -487
- package/src/tests/logging_test.cj +62 -62
- package/src/tests/platform_contract_test.cj +264 -251
- package/src/tests/plugin_clipboard_test.cj +222 -222
- package/src/tests/plugin_dialog_test.cj +237 -237
- package/src/tests/plugin_fs_test.cj +207 -0
- package/src/tests/plugin_http_test.cj +124 -124
- package/src/tests/plugin_notification_test.cj +205 -205
- package/src/tests/plugin_serial_test.cj +48 -0
- package/src/tests/plugin_test.cj +605 -585
- package/src/tests/plugin_ws_test.cj +40 -40
- package/src/tests/process_hidden_test.cj +129 -129
- package/src/tests/scope_test.cj +350 -350
- package/src/tests/system_host_test.cj +99 -81
- package/src/tests/urlutil_test.cj +53 -53
- package/src/tests/version_test.cj +75 -75
- package/src/tests/window_registry_test.cj +123 -123
- package/src/tray.cj +90 -90
- package/src/urlutil.cj +159 -159
- package/src/version.cj +44 -44
- package/src/window.cj +51 -51
- package/src/window_registry.cj +116 -116
- package/prebuilt/win32-x64/cj-tauri.exe +0 -0
- package/src/plugins/serial/serial_ohos_stub.cj +0 -61
- package/src/plugins/sqlite/sqlite_ohos_stub.cj +0 -91
package/src/launch.cj
CHANGED
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
import cjTauri.platform.*
|
|
4
|
-
import stdx.encoding.json.JsonValue
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 三段式 API 的第二段(批次 3,RFC-002 §4.2)
|
|
8
|
-
*
|
|
9
|
-
* 业务入口全文就这几行:
|
|
10
|
-
* ```
|
|
11
|
-
* import cjTauri.*
|
|
12
|
-
* main(): Int64 {
|
|
13
|
-
* launch(build())
|
|
14
|
-
* return 0
|
|
15
|
-
* }
|
|
16
|
-
* ```
|
|
17
|
-
*
|
|
18
|
-
* `Platform.discover()` 是唯一「端在哪儿」的知识入口(§5.1);
|
|
19
|
-
* 桌面阻塞主循环,移动端的非 UI 线程 spawn 由宿主负责(§4.2 鸿蒙示例)。
|
|
20
|
-
*
|
|
21
|
-
* 与 RFC 示意写法的偏差(照实记录):两个重载代替默认参数
|
|
22
|
-
* (当前工具链不用默认参数),`launchWith` 供测试注入假上下文、
|
|
23
|
-
* 鸿蒙 Ability 触发时给移动端上下文。
|
|
24
|
-
*/
|
|
25
|
-
public func launch(spec: AppSpec): Unit {
|
|
26
|
-
let target = Platform.guessTarget()
|
|
27
|
-
launchWith(spec, Platform.discover(spec.appId, target.arch))
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** 注入上下文的变体:测试给假上下文;鸿蒙侧给 Platform.mobile(filesDir) */
|
|
31
|
-
public func launchWith(spec: AppSpec, context: AppContext): Unit {
|
|
32
|
-
eprintln("[cj-tauri] launch:${spec.name}(os=${context.target.os} display=${context.target.display})")
|
|
33
|
-
let app = assemble(spec)
|
|
34
|
-
app.run(spec.pageSource)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* spec → TauriApp(纯装配、不 run):launch 与单测共用
|
|
39
|
-
*
|
|
40
|
-
* 装配顺序即框架契约顺序:窗口配置 → 插件 → 资产解析器 → 能力目录 → 业务命令(wire)。
|
|
41
|
-
*/
|
|
42
|
-
public func assemble(spec: AppSpec): TauriApp {
|
|
43
|
-
let app = TauriApp().window(spec.windowConfig)
|
|
44
|
-
for (p in spec.plugins) {
|
|
45
|
-
app.plugin(p)
|
|
46
|
-
}
|
|
47
|
-
if (spec.assetResolver.isSome()) {
|
|
48
|
-
app.assets(spec.assetResolver.getOrThrow())
|
|
49
|
-
}
|
|
50
|
-
if (spec.capabilitiesDir.size > 0) {
|
|
51
|
-
app.loadCapabilities(spec.capabilitiesDir)
|
|
52
|
-
}
|
|
53
|
-
// 能力清单 JSON 走与显式挂载同一入口:鸿蒙胶水把 rawfile 原文传进来(批次 3-PR3)
|
|
54
|
-
for (j in spec.capabilityJsons) {
|
|
55
|
-
app.addCapabilityJson(JsonValue.fromStr(j))
|
|
56
|
-
}
|
|
57
|
-
if (spec.wireFn.isSome()) {
|
|
58
|
-
let f = spec.wireFn.getOrThrow()
|
|
59
|
-
f(app)
|
|
60
|
-
}
|
|
61
|
-
return app
|
|
62
|
-
}
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
import cjTauri.platform.*
|
|
4
|
+
import stdx.encoding.json.JsonValue
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 三段式 API 的第二段(批次 3,RFC-002 §4.2)
|
|
8
|
+
*
|
|
9
|
+
* 业务入口全文就这几行:
|
|
10
|
+
* ```
|
|
11
|
+
* import cjTauri.*
|
|
12
|
+
* main(): Int64 {
|
|
13
|
+
* launch(build())
|
|
14
|
+
* return 0
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* `Platform.discover()` 是唯一「端在哪儿」的知识入口(§5.1);
|
|
19
|
+
* 桌面阻塞主循环,移动端的非 UI 线程 spawn 由宿主负责(§4.2 鸿蒙示例)。
|
|
20
|
+
*
|
|
21
|
+
* 与 RFC 示意写法的偏差(照实记录):两个重载代替默认参数
|
|
22
|
+
* (当前工具链不用默认参数),`launchWith` 供测试注入假上下文、
|
|
23
|
+
* 鸿蒙 Ability 触发时给移动端上下文。
|
|
24
|
+
*/
|
|
25
|
+
public func launch(spec: AppSpec): Unit {
|
|
26
|
+
let target = Platform.guessTarget()
|
|
27
|
+
launchWith(spec, Platform.discover(spec.appId, target.arch))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 注入上下文的变体:测试给假上下文;鸿蒙侧给 Platform.mobile(filesDir) */
|
|
31
|
+
public func launchWith(spec: AppSpec, context: AppContext): Unit {
|
|
32
|
+
eprintln("[cj-tauri] launch:${spec.name}(os=${context.target.os} display=${context.target.display})")
|
|
33
|
+
let app = assemble(spec)
|
|
34
|
+
app.run(spec.pageSource)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* spec → TauriApp(纯装配、不 run):launch 与单测共用
|
|
39
|
+
*
|
|
40
|
+
* 装配顺序即框架契约顺序:窗口配置 → 插件 → 资产解析器 → 能力目录 → 业务命令(wire)。
|
|
41
|
+
*/
|
|
42
|
+
public func assemble(spec: AppSpec): TauriApp {
|
|
43
|
+
let app = TauriApp().window(spec.windowConfig)
|
|
44
|
+
for (p in spec.plugins) {
|
|
45
|
+
app.plugin(p)
|
|
46
|
+
}
|
|
47
|
+
if (spec.assetResolver.isSome()) {
|
|
48
|
+
app.assets(spec.assetResolver.getOrThrow())
|
|
49
|
+
}
|
|
50
|
+
if (spec.capabilitiesDir.size > 0) {
|
|
51
|
+
app.loadCapabilities(spec.capabilitiesDir)
|
|
52
|
+
}
|
|
53
|
+
// 能力清单 JSON 走与显式挂载同一入口:鸿蒙胶水把 rawfile 原文传进来(批次 3-PR3)
|
|
54
|
+
for (j in spec.capabilityJsons) {
|
|
55
|
+
app.addCapabilityJson(JsonValue.fromStr(j))
|
|
56
|
+
}
|
|
57
|
+
if (spec.wireFn.isSome()) {
|
|
58
|
+
let f = spec.wireFn.getOrThrow()
|
|
59
|
+
f(app)
|
|
60
|
+
}
|
|
61
|
+
return app
|
|
62
|
+
}
|
package/src/logging.cj
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
import std.env.*
|
|
4
|
-
import std.convert.*
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 日志落盘的策略层(RFC-003 第 5 期):文件放哪、预算多少、环境变量怎么兜底。
|
|
8
|
-
*
|
|
9
|
-
* 落盘本身在 `src/log_bridge.cj`(进程级、无平台分支);这里只管策略,纯函数 + `@When` 目录推导。
|
|
10
|
-
*
|
|
11
|
-
* 为什么要环境变量兜底:单文件产物是 Windows 的 GUI 子系统、双击时没有控制台,而**已经分发的
|
|
12
|
-
* exe 改不了代码**——让报障的人带上 `CJ_TAURI_LOG` 再启动一次,就能拿到凭证;
|
|
13
|
-
* 不设这些变量时行为与之前**完全一致**(不落盘、stderr 照旧)。
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
/** 默认预算:256 KB 一份、留 2 份档案(最坏约 1 MB,常驻托盘类应用也吃得消) */
|
|
17
|
-
public let CJ_LOG_DEFAULT_MAX_KB: Int64 = 256
|
|
18
|
-
public let CJ_LOG_DEFAULT_KEEP: Int64 = 2
|
|
19
|
-
|
|
20
|
-
/** 应用名缺省值(应用没给名字时用它当文件名) */
|
|
21
|
-
public let CJ_LOG_DEFAULT_APP: String = "app"
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 单行上限(字节):页面可控的字符串,超了只记一条说明
|
|
25
|
-
*
|
|
26
|
-
* 8 KiB 够放一段异常栈;不设上限的话,一行天文数字能同时把内存与日志文件撑爆,
|
|
27
|
-
* 而这一行本身还未必有诊断价值。
|
|
28
|
-
*/
|
|
29
|
-
public let CJ_LOG_MAX_LINE: Int64 = 8192
|
|
30
|
-
|
|
31
|
-
/** 读环境变量(空串按未设置算)。公开只为子包用例可见(子包看不到父包非 public 符号) */
|
|
32
|
-
public func logEnvOr(name: String, dflt: String): String {
|
|
33
|
-
if (let Some(v) <- getVariable(name)) {
|
|
34
|
-
if (v.size > 0) {
|
|
35
|
-
return v
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return dflt
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 解析预算类环境变量(CJ_TAURI_LOG_MAX_KB / CJ_TAURI_LOG_KEEP)
|
|
43
|
-
*
|
|
44
|
-
* 非法值按未设置算,并留一行 stderr——「设了但没生效」比「没设」难查得多。
|
|
45
|
-
* 公开只为子包用例可见(子包看不到父包非 public 符号)
|
|
46
|
-
*/
|
|
47
|
-
public func logBudgetFromEnv(name: String, dflt: Int64): Int64 {
|
|
48
|
-
if (let Some(v) <- getVariable(name)) {
|
|
49
|
-
if (v.size > 0) {
|
|
50
|
-
try {
|
|
51
|
-
let n = Int64.parse(v)
|
|
52
|
-
if (n > 0) {
|
|
53
|
-
return n
|
|
54
|
-
}
|
|
55
|
-
eprintln("[cj-tauri] ${name}=\"${v}\" 不是正整数,按默认值 ${dflt} 处理")
|
|
56
|
-
} catch (e: Exception) {
|
|
57
|
-
eprintln("[cj-tauri] ${name}=\"${v}\" 解析失败,按默认值 ${dflt} 处理")
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return dflt
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* 平台惯例的日志目录(不含文件名)
|
|
66
|
-
*
|
|
67
|
-
* Linux 认 `XDG_STATE_HOME`(缺省 `~/.local/state`):日志属 state,不属 config——
|
|
68
|
-
* 放 `~/.config` 会把「可丢弃的运行痕迹」混进配置备份里。
|
|
69
|
-
*/
|
|
70
|
-
@When[os == "Linux"]
|
|
71
|
-
public func defaultLogDir(): String {
|
|
72
|
-
let base = logEnvOr("XDG_STATE_HOME", "")
|
|
73
|
-
if (base.size > 0) {
|
|
74
|
-
return "${base}/cj-tauri"
|
|
75
|
-
}
|
|
76
|
-
return "${logEnvOr("HOME", "/tmp")}/.local/state/cj-tauri"
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 平台惯例的日志目录(不含文件名)
|
|
81
|
-
*
|
|
82
|
-
* Windows 认 `%LOCALAPPDATA%`(`C:\Users\<用户>\AppData\Local`):单机可丢的数据就该落这里,
|
|
83
|
-
* 漫游配置里不放日志。变量缺失时退到 USERPROFILE,别拼出个以 `\cj-tauri` 开头的绝对路径。
|
|
84
|
-
*/
|
|
85
|
-
@When[os == "Windows"]
|
|
86
|
-
public func defaultLogDir(): String {
|
|
87
|
-
let base = logEnvOr("LOCALAPPDATA", "")
|
|
88
|
-
if (base.size > 0) {
|
|
89
|
-
return "${base}\\cj-tauri\\logs"
|
|
90
|
-
}
|
|
91
|
-
return "${logEnvOr("USERPROFILE", "C:")}\\AppData\\Local\\cj-tauri\\logs"
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** 目录 + 文件名:分隔符按平台给(C 侧整条路径直接用,不做拼接) */
|
|
95
|
-
@When[os == "Linux"]
|
|
96
|
-
func logPathJoin(dir: String, name: String): String {
|
|
97
|
-
return "${dir}/${name}"
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** 目录 + 文件名:分隔符按平台给(C 侧整条路径直接用,不做拼接) */
|
|
101
|
-
@When[os == "Windows"]
|
|
102
|
-
func logPathJoin(dir: String, name: String): String {
|
|
103
|
-
return "${dir}\\${name}"
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** 应用名 → 平台惯例目录下的日志全路径(`CJ_TAURI_LOG` 的覆写由调用方先判) */
|
|
107
|
-
public func defaultLogPath(appName: String): String {
|
|
108
|
-
let name = if (appName.size > 0) {
|
|
109
|
-
appName
|
|
110
|
-
} else {
|
|
111
|
-
CJ_LOG_DEFAULT_APP
|
|
112
|
-
}
|
|
113
|
-
return logPathJoin(defaultLogDir(), "${name}.log")
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* 「环境变量给了就用它,没给才落平台惯例目录」——`setLogToDefaultFile` 的选择器
|
|
118
|
-
*
|
|
119
|
-
* 抽成纯函数只为**可测**:单测里改环境变量会污染同进程的其它用例,所以把「读到什么」
|
|
120
|
-
* 当参数传进来,判据钉在这个函数上(`envPath` 空串=未设置,与 `logEnvOr` 同口径)。
|
|
121
|
-
*/
|
|
122
|
-
public func logPathOrDefault(envPath: String, appName: String): String {
|
|
123
|
-
if (envPath.size > 0) {
|
|
124
|
-
return envPath
|
|
125
|
-
}
|
|
126
|
-
return defaultLogPath(appName)
|
|
127
|
-
}
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
import std.env.*
|
|
4
|
+
import std.convert.*
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 日志落盘的策略层(RFC-003 第 5 期):文件放哪、预算多少、环境变量怎么兜底。
|
|
8
|
+
*
|
|
9
|
+
* 落盘本身在 `src/log_bridge.cj`(进程级、无平台分支);这里只管策略,纯函数 + `@When` 目录推导。
|
|
10
|
+
*
|
|
11
|
+
* 为什么要环境变量兜底:单文件产物是 Windows 的 GUI 子系统、双击时没有控制台,而**已经分发的
|
|
12
|
+
* exe 改不了代码**——让报障的人带上 `CJ_TAURI_LOG` 再启动一次,就能拿到凭证;
|
|
13
|
+
* 不设这些变量时行为与之前**完全一致**(不落盘、stderr 照旧)。
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** 默认预算:256 KB 一份、留 2 份档案(最坏约 1 MB,常驻托盘类应用也吃得消) */
|
|
17
|
+
public let CJ_LOG_DEFAULT_MAX_KB: Int64 = 256
|
|
18
|
+
public let CJ_LOG_DEFAULT_KEEP: Int64 = 2
|
|
19
|
+
|
|
20
|
+
/** 应用名缺省值(应用没给名字时用它当文件名) */
|
|
21
|
+
public let CJ_LOG_DEFAULT_APP: String = "app"
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 单行上限(字节):页面可控的字符串,超了只记一条说明
|
|
25
|
+
*
|
|
26
|
+
* 8 KiB 够放一段异常栈;不设上限的话,一行天文数字能同时把内存与日志文件撑爆,
|
|
27
|
+
* 而这一行本身还未必有诊断价值。
|
|
28
|
+
*/
|
|
29
|
+
public let CJ_LOG_MAX_LINE: Int64 = 8192
|
|
30
|
+
|
|
31
|
+
/** 读环境变量(空串按未设置算)。公开只为子包用例可见(子包看不到父包非 public 符号) */
|
|
32
|
+
public func logEnvOr(name: String, dflt: String): String {
|
|
33
|
+
if (let Some(v) <- getVariable(name)) {
|
|
34
|
+
if (v.size > 0) {
|
|
35
|
+
return v
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return dflt
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 解析预算类环境变量(CJ_TAURI_LOG_MAX_KB / CJ_TAURI_LOG_KEEP)
|
|
43
|
+
*
|
|
44
|
+
* 非法值按未设置算,并留一行 stderr——「设了但没生效」比「没设」难查得多。
|
|
45
|
+
* 公开只为子包用例可见(子包看不到父包非 public 符号)
|
|
46
|
+
*/
|
|
47
|
+
public func logBudgetFromEnv(name: String, dflt: Int64): Int64 {
|
|
48
|
+
if (let Some(v) <- getVariable(name)) {
|
|
49
|
+
if (v.size > 0) {
|
|
50
|
+
try {
|
|
51
|
+
let n = Int64.parse(v)
|
|
52
|
+
if (n > 0) {
|
|
53
|
+
return n
|
|
54
|
+
}
|
|
55
|
+
eprintln("[cj-tauri] ${name}=\"${v}\" 不是正整数,按默认值 ${dflt} 处理")
|
|
56
|
+
} catch (e: Exception) {
|
|
57
|
+
eprintln("[cj-tauri] ${name}=\"${v}\" 解析失败,按默认值 ${dflt} 处理")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return dflt
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 平台惯例的日志目录(不含文件名)
|
|
66
|
+
*
|
|
67
|
+
* Linux 认 `XDG_STATE_HOME`(缺省 `~/.local/state`):日志属 state,不属 config——
|
|
68
|
+
* 放 `~/.config` 会把「可丢弃的运行痕迹」混进配置备份里。
|
|
69
|
+
*/
|
|
70
|
+
@When[os == "Linux"]
|
|
71
|
+
public func defaultLogDir(): String {
|
|
72
|
+
let base = logEnvOr("XDG_STATE_HOME", "")
|
|
73
|
+
if (base.size > 0) {
|
|
74
|
+
return "${base}/cj-tauri"
|
|
75
|
+
}
|
|
76
|
+
return "${logEnvOr("HOME", "/tmp")}/.local/state/cj-tauri"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 平台惯例的日志目录(不含文件名)
|
|
81
|
+
*
|
|
82
|
+
* Windows 认 `%LOCALAPPDATA%`(`C:\Users\<用户>\AppData\Local`):单机可丢的数据就该落这里,
|
|
83
|
+
* 漫游配置里不放日志。变量缺失时退到 USERPROFILE,别拼出个以 `\cj-tauri` 开头的绝对路径。
|
|
84
|
+
*/
|
|
85
|
+
@When[os == "Windows"]
|
|
86
|
+
public func defaultLogDir(): String {
|
|
87
|
+
let base = logEnvOr("LOCALAPPDATA", "")
|
|
88
|
+
if (base.size > 0) {
|
|
89
|
+
return "${base}\\cj-tauri\\logs"
|
|
90
|
+
}
|
|
91
|
+
return "${logEnvOr("USERPROFILE", "C:")}\\AppData\\Local\\cj-tauri\\logs"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** 目录 + 文件名:分隔符按平台给(C 侧整条路径直接用,不做拼接) */
|
|
95
|
+
@When[os == "Linux"]
|
|
96
|
+
func logPathJoin(dir: String, name: String): String {
|
|
97
|
+
return "${dir}/${name}"
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** 目录 + 文件名:分隔符按平台给(C 侧整条路径直接用,不做拼接) */
|
|
101
|
+
@When[os == "Windows"]
|
|
102
|
+
func logPathJoin(dir: String, name: String): String {
|
|
103
|
+
return "${dir}\\${name}"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 应用名 → 平台惯例目录下的日志全路径(`CJ_TAURI_LOG` 的覆写由调用方先判) */
|
|
107
|
+
public func defaultLogPath(appName: String): String {
|
|
108
|
+
let name = if (appName.size > 0) {
|
|
109
|
+
appName
|
|
110
|
+
} else {
|
|
111
|
+
CJ_LOG_DEFAULT_APP
|
|
112
|
+
}
|
|
113
|
+
return logPathJoin(defaultLogDir(), "${name}.log")
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 「环境变量给了就用它,没给才落平台惯例目录」——`setLogToDefaultFile` 的选择器
|
|
118
|
+
*
|
|
119
|
+
* 抽成纯函数只为**可测**:单测里改环境变量会污染同进程的其它用例,所以把「读到什么」
|
|
120
|
+
* 当参数传进来,判据钉在这个函数上(`envPath` 空串=未设置,与 `logEnvOr` 同口径)。
|
|
121
|
+
*/
|
|
122
|
+
public func logPathOrDefault(envPath: String, appName: String): String {
|
|
123
|
+
if (envPath.size > 0) {
|
|
124
|
+
return envPath
|
|
125
|
+
}
|
|
126
|
+
return defaultLogPath(appName)
|
|
127
|
+
}
|