统一宿主壳目录边界
移动端壳拆分为 host-bridge 与 shell 目录 桌面端 Tauri 拆分为 host_bridge 与 shell Rust 模块 更新三端桥接层结构门禁与配置检查 同步宿主壳方案文档和项目共享决策
This commit is contained in:
@@ -732,6 +732,16 @@ function collectRustSourceBasenames(files) {
|
||||
return files.map((file) => file.pathname.split('/').pop()).sort();
|
||||
}
|
||||
|
||||
function collectRustSourceRelativePaths(files) {
|
||||
const rootPath = rustSourceDir.pathname.endsWith('/')
|
||||
? rustSourceDir.pathname
|
||||
: `${rustSourceDir.pathname}/`;
|
||||
|
||||
return files
|
||||
.map((file) => file.pathname.replace(rootPath, ''))
|
||||
.sort();
|
||||
}
|
||||
|
||||
function extractNativeAppTauriInvokeCommands(source) {
|
||||
return [...source.matchAll(/\btauriInvoke[\s\S]*?\(\s*([^,\n]+?)\s*,/g)]
|
||||
.map((match) => match[1].trim())
|
||||
@@ -1024,13 +1034,14 @@ const sharedTauriCommand = extractTsStringConst(
|
||||
);
|
||||
const allowedTauriCommands = [sharedTauriCommand];
|
||||
const requiredRustHostModules = [
|
||||
'desktop_host_bridge.rs',
|
||||
'desktop_host_bridge_files.rs',
|
||||
'desktop_host_bridge_protocol.rs',
|
||||
'desktop_host_bridge_share.rs',
|
||||
'desktop_shell_tray.rs',
|
||||
'desktop_shell_webview.rs',
|
||||
'host_bridge/files.rs',
|
||||
'host_bridge/mod.rs',
|
||||
'host_bridge/protocol.rs',
|
||||
'host_bridge/share.rs',
|
||||
'main.rs',
|
||||
'shell/mod.rs',
|
||||
'shell/tray.rs',
|
||||
'shell/webview.rs',
|
||||
];
|
||||
const requiredRustHostSnippets = [
|
||||
'tauri_plugin_single_instance::init',
|
||||
@@ -1138,7 +1149,7 @@ assertSameList(
|
||||
'shared Tauri HostBridge command',
|
||||
);
|
||||
for (const moduleName of requiredRustHostModules) {
|
||||
if (!collectRustSourceBasenames(rustHostSourceFiles).includes(moduleName)) {
|
||||
if (!collectRustSourceRelativePaths(rustHostSourceFiles).includes(moduleName)) {
|
||||
throw new Error(`desktop shell Rust bridge module missing ${moduleName}`);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
use crate::desktop_host_bridge_protocol::{failed, HostBridgeRequest, HostBridgeResponse};
|
||||
use crate::host_bridge::protocol::{failed, HostBridgeRequest, HostBridgeResponse};
|
||||
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _};
|
||||
use serde_json::{json, Value};
|
||||
use std::fs;
|
||||
@@ -431,7 +431,7 @@ pub(crate) fn import_audio_file_payload(path: PathBuf) -> Result<Value, String>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::desktop_host_bridge_protocol::request;
|
||||
use crate::host_bridge::protocol::request;
|
||||
|
||||
#[test]
|
||||
fn export_file_name_normalization_rejects_path_like_characters() {
|
||||
+14
-7
@@ -1,15 +1,22 @@
|
||||
use crate::desktop_host_bridge_files::{
|
||||
pub(crate) mod files;
|
||||
pub(crate) mod protocol;
|
||||
mod share;
|
||||
|
||||
pub(crate) use protocol::HostBridgeReplayState;
|
||||
pub(crate) use share::DesktopShareState;
|
||||
|
||||
use crate::host_bridge::files::{
|
||||
export_audio_payload, export_image_payload, export_text_payload, import_audio_file_payload,
|
||||
import_image_file_payload, import_text_file_payload, write_export_bytes_file,
|
||||
write_export_text_file,
|
||||
};
|
||||
use crate::desktop_host_bridge_protocol::{
|
||||
use crate::host_bridge::protocol::{
|
||||
capabilities, failed, normalize_request_id, ok, required_string_payload, validate_request,
|
||||
HostBridgeReplayReservation, HostBridgeReplayState, HostBridgeRequest, HostBridgeResponse,
|
||||
HostBridgeRuntime, HOST_BRIDGE_VERSION,
|
||||
HostBridgeReplayReservation, HostBridgeRequest, HostBridgeResponse, HostBridgeRuntime,
|
||||
HOST_BRIDGE_VERSION,
|
||||
};
|
||||
use crate::desktop_host_bridge_share::{share_text_from_request, DesktopShareState};
|
||||
use crate::desktop_shell_webview::{
|
||||
use crate::host_bridge::share::share_text_from_request;
|
||||
use crate::shell::webview::{
|
||||
color_scheme_from_theme, desktop_platform, normalize_external_url, normalize_native_page_url,
|
||||
resolve_desktop_network_status,
|
||||
};
|
||||
@@ -527,7 +534,7 @@ pub(crate) async fn host_bridge_request(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::desktop_host_bridge_protocol::request;
|
||||
use crate::host_bridge::protocol::request;
|
||||
|
||||
#[test]
|
||||
fn runtime_response_reports_tauri_shell() {
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
use crate::desktop_host_bridge_protocol::{failed, HostBridgeRequest, HostBridgeResponse};
|
||||
use crate::desktop_shell_webview::WEB_APP_ORIGIN;
|
||||
use crate::host_bridge::protocol::{failed, HostBridgeRequest, HostBridgeResponse};
|
||||
use crate::shell::webview::WEB_APP_ORIGIN;
|
||||
use serde_json::Value;
|
||||
use std::sync::Mutex;
|
||||
|
||||
@@ -84,7 +84,7 @@ pub(crate) fn share_text_from_request(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::desktop_host_bridge_protocol::request;
|
||||
use crate::host_bridge::protocol::request;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
@@ -1,18 +1,12 @@
|
||||
mod desktop_host_bridge;
|
||||
mod desktop_host_bridge_files;
|
||||
mod desktop_host_bridge_protocol;
|
||||
mod desktop_host_bridge_share;
|
||||
mod desktop_shell_tray;
|
||||
mod desktop_shell_webview;
|
||||
mod host_bridge;
|
||||
mod shell;
|
||||
|
||||
use desktop_host_bridge::host_bridge_request;
|
||||
use desktop_host_bridge_protocol::HostBridgeReplayState;
|
||||
use desktop_host_bridge_share::DesktopShareState;
|
||||
use desktop_shell_tray::{
|
||||
use host_bridge::{host_bridge_request, DesktopShareState, HostBridgeReplayState};
|
||||
use shell::tray::{
|
||||
register_desktop_tray, register_desktop_window_close_events,
|
||||
resolve_desktop_single_instance_action, show_main_window, DesktopSingleInstanceAction,
|
||||
};
|
||||
use desktop_shell_webview::{
|
||||
use shell::webview::{
|
||||
desktop_window_config_with_runtime_platform, emit_desktop_lifecycle_event,
|
||||
open_desktop_external_navigation, register_desktop_file_drop_events,
|
||||
register_desktop_lifecycle_events, register_desktop_network_events,
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
pub(crate) mod tray;
|
||||
pub(crate) mod webview;
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
use crate::desktop_host_bridge_files::{import_image_file_payload, import_image_mime_type};
|
||||
use crate::desktop_host_bridge_protocol::{HOST_BRIDGE_PROTOCOL, HOST_BRIDGE_VERSION};
|
||||
use crate::host_bridge::files::{import_image_file_payload, import_image_mime_type};
|
||||
use crate::host_bridge::protocol::{HOST_BRIDGE_PROTOCOL, HOST_BRIDGE_VERSION};
|
||||
use serde_json::{json, Value};
|
||||
use std::net::{TcpStream, ToSocketAddrs};
|
||||
use std::path::PathBuf;
|
||||
@@ -16,25 +16,25 @@ import {
|
||||
configureMobileHostBridgeNavigation,
|
||||
handleMobileHostBridgeMessage,
|
||||
resolveMobileHostCapabilities,
|
||||
} from './src/mobileHostBridge';
|
||||
import { buildMobileShellUrlFromDeepLink } from './src/mobileShellDeepLink';
|
||||
import { lifecyclePayloadFromAppState } from './src/mobileShellLifecycle';
|
||||
} from './src/host-bridge/mobileHostBridge';
|
||||
import { buildMobileShellUrlFromDeepLink } from './src/shell/mobileShellDeepLink';
|
||||
import { lifecyclePayloadFromAppState } from './src/shell/mobileShellLifecycle';
|
||||
import {
|
||||
resolveMobileShellExternalUrl,
|
||||
shouldAcceptMobileShellHostBridgeMessage,
|
||||
shouldOpenInMobileShellWebView,
|
||||
} from './src/mobileShellNavigation';
|
||||
} from './src/shell/mobileShellNavigation';
|
||||
import {
|
||||
getMobileNetworkStatus,
|
||||
subscribeMobileNetworkStatus,
|
||||
} from './src/mobileShellNetwork';
|
||||
import { MOBILE_SHELL_HOST_VERSION } from './src/mobileShellRuntime';
|
||||
import { MOBILE_SHELL_SAFE_AREA_EDGES } from './src/mobileShellSafeArea';
|
||||
} from './src/shell/mobileShellNetwork';
|
||||
import { MOBILE_SHELL_HOST_VERSION } from './src/shell/mobileShellRuntime';
|
||||
import { MOBILE_SHELL_SAFE_AREA_EDGES } from './src/shell/mobileShellSafeArea';
|
||||
import {
|
||||
buildMobileShellUrl,
|
||||
resolveMobileShellBaseWebUrl,
|
||||
} from './src/mobileShellUrl';
|
||||
import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './src/mobileShellWebViewPolicy';
|
||||
} from './src/shell/mobileShellUrl';
|
||||
import { BLOCK_WEBVIEW_DOWNLOAD_SCRIPT } from './src/shell/mobileShellWebViewPolicy';
|
||||
|
||||
function buildHostBridgeMessageScript(message: unknown) {
|
||||
return `window.dispatchEvent(new MessageEvent('message', { data: ${JSON.stringify(
|
||||
|
||||
@@ -6,11 +6,11 @@ const appConfigPath = new URL('../app.json', import.meta.url);
|
||||
const appConfig = JSON.parse(fs.readFileSync(appConfigPath, 'utf8')).expo;
|
||||
const appPath = new URL('../App.tsx', import.meta.url);
|
||||
const appSource = fs.readFileSync(appPath, 'utf8');
|
||||
const bridgePath = new URL('../src/mobileHostBridge.ts', import.meta.url);
|
||||
const bridgePath = new URL('../src/host-bridge/mobileHostBridge.ts', import.meta.url);
|
||||
const bridgeSource = fs.readFileSync(bridgePath, 'utf8');
|
||||
const mobileShellUrlPath = new URL('../src/mobileShellUrl.ts', import.meta.url);
|
||||
const mobileShellUrlPath = new URL('../src/shell/mobileShellUrl.ts', import.meta.url);
|
||||
const mobileShellUrlSource = fs.readFileSync(mobileShellUrlPath, 'utf8');
|
||||
const mobileShellRuntimePath = new URL('../src/mobileShellRuntime.ts', import.meta.url);
|
||||
const mobileShellRuntimePath = new URL('../src/shell/mobileShellRuntime.ts', import.meta.url);
|
||||
const mobileShellRuntimeSource = fs.readFileSync(mobileShellRuntimePath, 'utf8');
|
||||
const sharedContractPath = new URL(
|
||||
'../../../packages/shared/src/contracts/hostBridge.ts',
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import {
|
||||
type HostBridgeMethod,
|
||||
type HostBridgeRequest,
|
||||
type HostBridgeResponse,
|
||||
} from '../../../packages/shared/src/contracts/hostBridge';
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import {
|
||||
configureMobileHostBridgeNavigation,
|
||||
handleMobileHostBridgeMessage,
|
||||
+4
-4
@@ -49,10 +49,10 @@ import {
|
||||
type OpenExternalUrlPayload,
|
||||
type SetBadgeCountPayload,
|
||||
type ShareOpenPayload,
|
||||
} from '../../../packages/shared/src/contracts/hostBridge';
|
||||
import { resolveMobileShellWebViewUrl } from './mobileShellNavigation';
|
||||
import { getMobileNetworkStatus } from './mobileShellNetwork';
|
||||
import { MOBILE_SHELL_HOST_VERSION } from './mobileShellRuntime';
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
import { resolveMobileShellWebViewUrl } from '../shell/mobileShellNavigation';
|
||||
import { getMobileNetworkStatus } from '../shell/mobileShellNetwork';
|
||||
import { MOBILE_SHELL_HOST_VERSION } from '../shell/mobileShellRuntime';
|
||||
|
||||
const WEB_APP_ORIGIN = 'https://app.genarrative.world';
|
||||
const EXPORT_TEXT_MAX_BYTES = 5 * 1024 * 1024;
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { normalizeHostBridgeExternalUrl } from '../../../packages/shared/src/contracts/hostBridge';
|
||||
import { normalizeHostBridgeExternalUrl } from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
|
||||
export function shouldOpenInMobileShellWebView(
|
||||
rawUrl: string,
|
||||
+1
-1
@@ -3,7 +3,7 @@ import * as Network from 'expo-network';
|
||||
import {
|
||||
type NetworkStatusResult,
|
||||
normalizeHostBridgeConnectionType,
|
||||
} from '../../../packages/shared/src/contracts/hostBridge';
|
||||
} from '../../../../packages/shared/src/contracts/hostBridge';
|
||||
|
||||
export function normalizeMobileNetworkStatus(
|
||||
state: Network.NetworkState,
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user